class Pushr::Daemon::GcmSupport::ConnectionGcm

Constants

IDLE_PERIOD
PUSH_URL

Attributes

configuration[R]
name[R]
response[R]

Public Class Methods

new(configuration, i) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 11
def initialize(configuration, i)
  @configuration = configuration
  @name = "#{@configuration.app}: ConnectionGcm #{i}"
end

Public Instance Methods

connect() click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 16
def connect
  @last_use = Time.now
  uri = URI.parse(PUSH_URL)
  @connection = open_http(uri.host, uri.port)
  @connection.start
  Pushr::Daemon.logger.info("[#{@name}] Connected to #{PUSH_URL}")
end
write(data) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 24
def write(data)
  retry_count = 0
  begin
    response = notification_request(data.to_message)
    handle_response(response, data, retry_count)
  rescue GcmError => e
    raise e
  rescue => e
    retry_count += 1
    if retry_count < 10
      retry
    else
      raise e
    end
  end
end

Private Instance Methods

handle_error_5xx_response(response, retry_count) click to toggle source

sleep if there is a Retry-After header

# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 70
def handle_error_5xx_response(response, retry_count)
  if response.header['Retry-After']
    value = response.header['Retry-After']

    if value.to_i > 0 # Retry-After: 120
      sleep value.to_i
    elsif Date.rfc2822(value) # Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
      sleep Time.now.utc - Date.rfc2822(value).to_time.utc
    end
  else
    sleep 2**retry_count
  end
end
handle_error_response(response, data, retry_count) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 52
def handle_error_response(response, data, retry_count)
  case response.code.to_i
  when 400
    # Pushr::Daemon.logger.error("[#{@name}] JSON formatting exception received.")
    return Pushr::Daemon::DeliveryError.new(response.code, data, 'JSON formatting exception', 'GCM', false)
  when 401
    # Pushr::Daemon.logger.error("[#{@name}] Authentication exception received.")
    return Pushr::Daemon::DeliveryError.new(response.code, data, 'Authentication exception', 'GCM', false)
  when 500..599
    # internal error GCM server || service unavailable: exponential back-off
    handle_error_5xx_response(response, retry_count)
  else
    # Pushr::Daemon.logger.error("[#{@name}] Unknown error: #{response.code} #{response.message}")
    return Pushr::Daemon::DeliveryError.new(response.code, data, "Unknown error: #{response.message}", 'GCM', false)
  end
end
handle_response(response, data, retry_count) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 43
def handle_response(response, data, retry_count)
  if response.code.eql? '200'
    handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, data)
    handler.handle
  else
    handle_error_response(response, data, retry_count)
  end
end
idle_period_exceeded?() click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 123
def idle_period_exceeded?
  # Timeout on the http connection is 5 minutes, reconnect after 5 minutes
  @last_use + IDLE_PERIOD < Time.now
end
notification_request(data) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 90
def notification_request(data)
  headers = { 'Authorization' => "key=#{@configuration.api}",
              'Content-type' => 'application/json',
              'Content-length' => "#{data.length}" }
  uri = URI.parse(PUSH_URL)
  post(uri, data, headers)
end
open_http(host, port) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 84
def open_http(host, port)
  http = Net::HTTP.new(host, port)
  http.use_ssl = true
  http
end
post(uri, data, headers) click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 98
def post(uri, data, headers)
  reconnect_idle if idle_period_exceeded?

  retry_count = 0

  begin
    response = @connection.post(uri.path, data, headers)
    @last_use = Time.now
  rescue EOFError, Errno::ECONNRESET, Timeout::Error => e
    retry_count += 1

    Pushr::Daemon.logger.error("[#{@name}] Lost connection to #{PUSH_URL} (#{e.class.name}), reconnecting ##{retry_count}...")

    if retry_count <= 3
      reconnect
      sleep 1
      retry
    else
      raise ConnectionError, "#{@name} tried #{retry_count - 1} times to reconnect but failed (#{e.class.name})."
    end
  end

  response
end
reconnect() click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 133
def reconnect
  @connection.finish
  @last_use = Time.now
  @connection.start
end
reconnect_idle() click to toggle source
# File lib/pushr/daemon/gcm_support/connection_gcm.rb, line 128
def reconnect_idle
  Pushr::Daemon.logger.info("[#{@name}] Idle period exceeded, reconnecting...")
  reconnect
end