Skip to content

Consider avoiding apnotic/net-http2 dependency #25

@trevorturk

Description

@trevorturk

Hello!

Exciting to see this gem, I was looking for something built into Rails a few months ago and I'm so happy to see this!

I just wanted to drop a suggestion to consider what apnotic is buying you, because FWIW I found it was (in combination with the net-http2 dependency) increasing my app's memory use (in a memory constrained environment on Heroku).

Here's what I ended up with using Async::HTTP in case it's useful to you or others (please excuse the application-specific code!)

require "async/http/internet/instance"

class ApnsToken < ActiveRecord::Base
  TOPIC = "ios-app-name-goes-here"

  validates :env, :token, :topic, presence: true
  validates :token, uniqueness: { scope: [:env, :topic] }
  validates :topic, inclusion: { in: [TOPIC] }

  def test
    push(:alert, { alert: "Hello!", sound: "default" })
  end

  def ping
    push(:background, { "content-available": 1 })
  end

  private

  def push(type, payload)
    host = case env
      when "development" then "https://api.sandbox.push.apple.com"
      when "production"  then "https://api.push.apple.com"
    end

    url = "#{host}/3/device/#{token}"

    headers = {
      "authorization" => "bearer #{jwt}",
      "apns-topic" => topic,
      "apns-push-type" => type,
      "content-type" => "application/json"
    }

    body = JSON.generate({ aps: payload })

    Sync do |task|
      response = nil
      result = nil

      task.with_timeout(2.seconds) do
        response = Async::HTTP::Internet.instance.post(url, headers, body)

        result = case response.status
          when 200
            true
          when 400
            destroy if JSON.parse(response.read).dig("reason") == "BadDeviceToken"
            false
          when 410
            destroy
            false
        else
          false
        end
      end

      result
    ensure
      response&.finish
    end
  end

  def jwt
    @_jwt ||= begin
      payload = {
        iss: Rails.application.credentials.services.apns.team_id,
        iat: Time.now.to_i
      }

      JWT.encode(
        payload,
        OpenSSL::PKey::EC.new(Rails.application.credentials.services.apns.private_key),
        "ES256",
        kid: Rails.application.credentials.services.apns.key_id
      )
    end
  end
end

In any case please feel free to close as not planned etc, but I figured it was worth sending a note.

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions