Class: Lowdown::Client
- Inherits:
-
Object
- Object
- Lowdown::Client
- Defined in:
- lib/lowdown/client.rb,
lib/lowdown/client/request_group.rb
Overview
The main class to use for interactions with the Apple Push Notification HTTP/2 service.
Important connection configuration options are pool_size
and keep_alive
. The former specifies the number of
simultaneous connections the client should make and the latter is key for long running processes.
Defined Under Namespace
Classes: RequestGroup
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")
- DEFAULT_GROUP_TIMEOUT =
The default timeout for #group.
3600
Instance Attribute Summary collapse
-
#connection ⇒ Connection, Celluloid::Supervision::Container::Pool<Connection>
readonly
A single Connection or a pool of Connection actors configured to connect to the remote service.
-
#default_topic ⇒ String?
readonly
The ‘topic’ to use if the Certificate is a Universal Certificate and a Notification doesn’t explicitely provide one.
Constructor Summary collapse
-
.client(uri:, certificate:, pool_size: 1, keep_alive: false, connection_class: Connection) ⇒ Client
Creates a connection pool that connects to the specified
uri
. -
.client_with_connection(connection, certificate:) ⇒ Client
Creates a Client configured with the
app_bundle_id
as itsdefault_topic
, in case the Certificate represents a Universal Certificate. -
.production(production, certificate:, pool_size: 1, keep_alive: false, connection_class: Connection) ⇒ Client
This is the most convenient constructor for regular use.
-
#initialize(connection:, default_topic: nil) ⇒ Client
constructor
You should normally use any of the other constructors to create a Client object.
Instance Method Summary collapse
-
#connect(group_timeout: nil) {|group| ... } ⇒ void
Opens the connection to the service, yields a request group, and automatically closes the connection by the end of the block.
-
#disconnect ⇒ void
Closes the connection to the service.
-
#group(timeout: nil) {|group| ... } ⇒ void
Use this to group a batch of requests and halt the caller thread until all of the requests in the group have been performed.
-
#monitor {|condition| ... } ⇒ void
Registers a condition object with the connection pool, for the duration of the given block.
-
#send_notification(notification, delegate:, context: nil) ⇒ void
Verifies the
notification
is valid and then sends it to the remote service.
Constructor Details
#initialize(connection:, default_topic: nil) ⇒ Client
You should normally use any of the other constructors to create a Client object.
128 129 130 |
# File 'lib/lowdown/client.rb', line 128 def initialize(connection:, default_topic: nil) @connection, @default_topic = connection, default_topic end |
Instance Attribute Details
#connection ⇒ Connection, Celluloid::Supervision::Container::Pool<Connection> (readonly)
Returns a single Connection or a pool of Connection actors configured to connect to the remote service.
137 138 139 |
# File 'lib/lowdown/client.rb', line 137 def connection @connection end |
#default_topic ⇒ String? (readonly)
Returns the ‘topic’ to use if the Certificate is a Universal Certificate and a Notification doesn’t explicitely provide one.
143 144 145 |
# File 'lib/lowdown/client.rb', line 143 def default_topic @default_topic end |
Class Method Details
.client(uri:, certificate:, pool_size: 1, keep_alive: false, connection_class: Connection) ⇒ Client
Creates a connection pool that connects to the specified uri
.
94 95 96 97 98 99 |
# File 'lib/lowdown/client.rb', line 94 def self.client(uri:, certificate:, pool_size: 1, keep_alive: false, connection_class: Connection) certificate = Certificate.certificate(certificate) connection_class ||= Connection connection_pool = connection_class.pool(size: pool_size, args: [uri, certificate.ssl_context, keep_alive]) client_with_connection(connection_pool, certificate: 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.
112 113 114 |
# File 'lib/lowdown/client.rb', line 112 def self.client_with_connection(connection, certificate:) new(connection: connection, default_topic: certificate.universal? ? certificate.topics.first : nil) end |
.production(production, certificate:, pool_size: 1, keep_alive: false, connection_class: Connection) ⇒ Client
This is the most convenient constructor for regular use.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/lowdown/client.rb', line 56 def self.production(production, certificate:, pool_size: 1, keep_alive: false, connection_class: Connection) certificate = Certificate.certificate(certificate) 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(uri: production ? PRODUCTION_URI : DEVELOPMENT_URI, certificate: certificate, pool_size: pool_size, keep_alive: keep_alive, connection_class: connection_class) end |
Instance Method Details
#connect(group_timeout: nil) {|group| ... } ⇒ void
Don’t use this if you opted to keep a pool of connections alive.
This method returns an undefined value.
Opens the connection to the service, yields a request group, and automatically closes the connection by the end of the block.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/lowdown/client.rb', line 162 def connect(group_timeout: nil, &block) if @connection.respond_to?(:actors) @connection.actors.each { |connection| connection.async.connect } else @connection.async.connect end if block begin group(timeout: group_timeout, &block) ensure disconnect end end end |
#disconnect ⇒ void
This method returns an undefined value.
Closes the connection to the service.
183 184 185 186 187 188 189 190 191 |
# File 'lib/lowdown/client.rb', line 183 def disconnect if @connection.respond_to?(:actors) @connection.actors.each do |connection| connection.async.disconnect if connection.alive? end else @connection.async.disconnect if @connection.alive? end end |
#group(timeout: nil) {|group| ... } ⇒ void
Do not share the yielded group across threads.
This method returns an undefined value.
Use this to group a batch of requests and halt the caller thread until all of the requests in the group have been performed.
It proxies Lowdown::Client::RequestGroup#send_notification to #send_notification, but, unlike the latter, the request callbacks are provided in the form of a block.
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/lowdown/client.rb', line 216 def group(timeout: nil) group = nil monitor do |condition| group = RequestGroup.new(self, condition) yield group if !group.empty? && exception = condition.wait(timeout || DEFAULT_GROUP_TIMEOUT) raise exception end end ensure group.terminate end |
#monitor {|condition| ... } ⇒ void
This method returns an undefined value.
Registers a condition object with the connection pool, for the duration of the given block. It either returns an exception that caused a connection to die, or whatever value you signal to it.
This is automatically used by #group.
239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/lowdown/client.rb', line 239 def monitor condition = Connection::Monitor::Condition.new if defined?(Mock::Connection) && @connection.class == Mock::Connection yield condition else begin @connection.__register_lowdown_crash_condition__(condition) yield condition ensure @connection.__deregister_lowdown_crash_condition__(condition) end end end |
#send_notification(notification, delegate:, context: nil) ⇒ void
In general, you will probably want to use #group to be able to use Lowdown::Client::RequestGroup#send_notification, which takes a traditional blocks-based callback approach.
This method returns an undefined value.
Verifies the notification
is valid and then sends it to the remote service. Response feedback is provided via
a delegate mechanism.
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/lowdown/client.rb', line 275 def send_notification(notification, delegate:, context: nil) 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 headers["apns-priority"] = notification.priority if notification.priority headers["apns-topic"] = topic if topic body = notification.formatted_payload.to_json @connection.async.post(path: "/3/device/#{notification.token}", headers: headers, body: body, delegate: delegate, context: context) end |