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

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