Class: Lowdown::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/lowdown/client.rb

Overview

The main class to use for interactions with the Apple Push Notification HTTP/2 service.

Constant Summary collapse

DEVELOPMENT_URI =

The details to connect to the development (sandbox) environment version of the APN service.

URI.parse("https://api.development.push.apple.com:443")
PRODUCTION_URI =

The details to connect to the production environment version of the APN service.

URI.parse("https://api.push.apple.com:443")

Instance Attribute Summary collapse

Constructor Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(connection, default_topic = nil) ⇒ Client

You should normally use any of the other constructors to create a Client object.

Parameters:

  • connection (Connection)

    a Connection configured to connect to the remote service.

  • default_topic (String) (defaults to: nil)

    the ‘topic’ to use if the Certificate is a Universal Certificate and a Notification doesn’t explicitely provide one.



95
96
97
# File 'lib/lowdown/client.rb', line 95

def initialize(connection, default_topic = nil)
  @connection, @default_topic = connection, default_topic
end

Instance Attribute Details

#connectionConnection (readonly)

Returns a Connection configured to connect to the remote service.

Returns:

  • (Connection)

    a Connection configured to connect to the remote service.



104
105
106
# File 'lib/lowdown/client.rb', line 104

def connection
  @connection
end

#default_topicString? (readonly)

Returns the ‘topic’ to use if the Certificate is a Universal Certificate and a Notification doesn’t explicitely provide one.

Returns:

  • (String, nil)

    the ‘topic’ to use if the Certificate is a Universal Certificate and a Notification doesn’t explicitely provide one.



110
111
112
# File 'lib/lowdown/client.rb', line 110

def default_topic
  @default_topic
end

Class Method Details

.client(uri, certificate_or_data) ⇒ Client

Creates a connection that connects to the specified uri.

It then calls client_with_connection.

Parameters:

  • uri (URI)

    the endpoint details of the service to connect to.

  • certificate_or_data (Certificate, String)

    a configured Certificate or PEM data to construct a Certificate from.

Returns:

  • (Client)

    a new instance of Client.



63
64
65
66
# File 'lib/lowdown/client.rb', line 63

def self.client(uri, certificate_or_data)
  certificate = Certificate.certificate(certificate_or_data)
  client_with_connection(Connection.new(uri, certificate.ssl_context), certificate)
end

.client_with_connection(connection, certificate) ⇒ Client

Creates a Client configured with the app_bundle_id as its default_topic, in case the Certificate represents a Universal Certificate.

Parameters:

  • connection (Connection)

    a Connection configured to connect to the remote service.

  • certificate (Certificate)

    a configured Certificate.

Returns:

  • (Client)

    a new instance of Client.



79
80
81
# File 'lib/lowdown/client.rb', line 79

def self.client_with_connection(connection, certificate)
  new(connection, certificate.universal? ? certificate.topics.first : nil)
end

.production(production, certificate_or_data) ⇒ Client

This is the most convenient constructor for regular use.

It then calls client.

Parameters:

  • production (Boolean)

    whether to use the production or the development environment.

  • certificate_or_data (Certificate, String)

    a configured Certificate or PEM data to construct a Certificate from.

Returns:

  • (Client)

    a new instance of Client.

Raises:

  • (ArgumentError)

    raised if the provided Certificate does not support the requested environment.



37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/lowdown/client.rb', line 37

def self.production(production, certificate_or_data)
  certificate = Certificate.certificate(certificate_or_data)
  if production
    unless certificate.production?
      raise ArgumentError, "The specified certificate is not usable with the production environment."
    end
  else
    unless certificate.development?
      raise ArgumentError, "The specified certificate is not usable with the development environment."
    end
  end
  client(production ? PRODUCTION_URI : DEVELOPMENT_URI, certificate)
end

Instance Method Details

#closevoid

This method returns an undefined value.

Closes the connection.



150
151
152
# File 'lib/lowdown/client.rb', line 150

def close
  @connection.close
end

#connect {|client| ... } ⇒ void

This method returns an undefined value.

Opens the connection to the service. If a block is given the connection is automatically closed.

Yields:

See Also:



123
124
125
126
127
128
129
130
131
132
# File 'lib/lowdown/client.rb', line 123

def connect
  @connection.open
  if block_given?
    begin
      yield self
    ensure
      close
    end
  end
end

#flushvoid

This method returns an undefined value.

Flushes the connection.



140
141
142
# File 'lib/lowdown/client.rb', line 140

def flush
  @connection.flush
end

#send_notification(notification) {|response, notification| ... } ⇒ void

Note:

The callback is performed on a different thread, dedicated to perfoming these callbacks.

This method returns an undefined value.

Verifies the notification is valid and sends it to the remote service.

Parameters:

  • notification (Notification)

    the notification object whose data to send to the service.

Yields:

  • (response, notification)

    called when the request is finished and a response is available.

Yield Parameters:

  • response (Response)

    the Response that holds the status data that came back from the service.

  • notification (Notification)

    the originally passed in notification object.

Raises:

See Also:



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/lowdown/client.rb', line 177

def send_notification(notification, &callback)
  raise ArgumentError, "Invalid notification: #{notification.inspect}" unless notification.valid?

  topic = notification.topic || @default_topic
  headers = {}
  headers["apns-expiration"] = (notification.expiration || 0).to_i
  headers["apns-id"]         = notification.formatted_id if notification.id
  headers["apns-priority"]   = notification.priority     if notification.priority
  headers["apns-topic"]      = topic                     if topic

  body = notification.formatted_payload.to_json

  # No need to keep a strong reference to the notification object, unless the user really wants it.
  actual_callback = callback.arity < 2 ? callback : lambda { |response| callback.call(response, notification) }

  @connection.post("/3/device/#{notification.token}", headers, body, &actual_callback)
end