Class: Lowdown::Connection

Inherits:
Object
  • Object
show all
Includes:
Celluloid::IO, Celluloid::Internals::Logger
Defined in:
lib/lowdown/connection.rb,
lib/lowdown/connection/monitor.rb

Overview

The class responsible for managing the connection to the Apple Push Notification service.

It manages both the SSL connection and processing of the HTTP/2 data sent back and forth over that connection.

Defined Under Namespace

Modules: DelegateProtocol, Monitor Classes: Request, TimedOut

Constant Summary collapse

CONNECT_RETRIES =
5
CONNECT_RETRY_BACKOFF =
5
CONNECT_TIMEOUT =
10
HEARTBEAT_INTERVAL =
10
HEARTBEAT_TIMEOUT =
CONNECT_TIMEOUT

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri, ssl_context, connect = true, socket_maker = nil) ⇒ Connection

Returns a new instance of Connection.

Examples:

Use socket_maker argument with modified ruby-proxifier

socket_maker = lambda do |uri|
  Proxifier::Proxy('http://127.0.0.1:3128').open \
  uri.host, uri.port, nil, nil, Celluloid::IO::TCPSocket
end

connection_pool = Lowdown::Connection.pool \
  size: 2,
  args: [uri, cert.ssl_context, true, socket_maker]

client = Lowdown::Client.client_with_connection connection_pool, certificate: cert

Parameters:

  • uri (URI, String)

    the details to connect to the APN service.

  • ssl_context (OpenSSL::SSL::SSLContext)

    a SSL context, configured with the certificate/key pair, which is used to connect to the APN service.

  • connect (Boolean) (defaults to: true)

    whether or not to immediately connect on initialization.

  • socket_maker (lambda) (defaults to: nil)

    a lambda takes uri and returns duck type of TCPSocket e.g.:



102
103
104
105
106
107
108
109
110
111
112
# File 'lib/lowdown/connection.rb', line 102

def initialize(uri, ssl_context, connect = true, socket_maker = nil)
  @uri, @ssl_context = URI(uri), ssl_context
  @socket_maker = socket_maker
  reset_state!

  if connect
    # This ensures that calls to the public #connect method are ignored while already connecting.
    @connecting = true
    async.connect!
  end
end

Instance Attribute Details

#ssl_contextOpenSSL::SSL::SSLContext (readonly)

Returns a SSL context, configured with the certificate/key pair, which is used to connect to the APN service.

Returns:

  • (OpenSSL::SSL::SSLContext)

    a SSL context, configured with the certificate/key pair, which is used to connect to the APN service.



122
123
124
# File 'lib/lowdown/connection.rb', line 122

def ssl_context
  @ssl_context
end

#uriURI (readonly)

Returns the details to connect to the APN service.

Returns:

  • (URI)

    the details to connect to the APN service.



117
118
119
# File 'lib/lowdown/connection.rb', line 117

def uri
  @uri
end

Instance Method Details

#connectvoid

This method returns an undefined value.

Creates a new SSL connection to the service, a HTTP/2 client, and starts off the main runloop.



128
129
130
# File 'lib/lowdown/connection.rb', line 128

def connect
  connect! unless @connecting
end

#connected?Boolean

Returns whether or not the Connection is open.

Returns:

  • (Boolean)

    whether or not the Connection is open.



148
149
150
# File 'lib/lowdown/connection.rb', line 148

def connected?
  !@connection.nil? && !@connection.closed?
end

#disconnectvoid

This method returns an undefined value.

Closes the connection and resets the internal state



136
137
138
139
140
141
142
143
# File 'lib/lowdown/connection.rb', line 136

def disconnect
  if @connection
    info "Closing..."
    @connection.close
  end
  @heartbeat.cancel if @heartbeat
  reset_state!
end

#pingBoolean

Note:

This halts the caller thread until a reply is received. You should call this on a future and possibly set a timeout.

This performs a HTTP/2 PING to determine if the connection is actually alive. Be sure to not call this on a sleeping connection, or it will be guaranteed to fail.

Returns:

  • (Boolean)

    whether or not a reply was received.



161
162
163
164
165
166
167
168
169
# File 'lib/lowdown/connection.rb', line 161

def ping
  if connected?
    condition = Celluloid::Condition.new
    @http.ping("whatever") { condition.signal(true) }
    condition.wait
  else
    false
  end
end

#post(path:, headers:, body:, delegate:, context: nil) ⇒ void

Note:

It is strongly advised that the delegate object is a Celluloid actor and that you pass in an async proxy of that object, but that is not required. If you do not pass in an actor, then be advised that the callback will run on this connection’s private thread and thus you should not perform long blocking operations.

This method returns an undefined value.

Sends the provided data as a POST request to the service.

Parameters:

  • path (String)

    the request path, which should be /3/device/<device-token>.

  • headers (Hash)

    the additional headers for the request. By default it sends :method, :path, and content-length.

  • body (String)

    the (JSON) encoded payload data to send to the service.

  • delegate (DelegateProtocol)

    an object that implements the delegate protocol.

  • context (Object, nil) (defaults to: nil)

    any object that you want to be passed to the delegate once the response is back.



334
335
336
# File 'lib/lowdown/connection.rb', line 334

def post(path:, headers:, body:, delegate:, context: nil)
  request("POST", path, headers, body, delegate, context)
end