class Rpush::Daemon::Gcm::Delivery

firebase.google.com/docs/cloud-messaging/server

Constants

FCM_URI
INVALID_REGISTRATION_ID_STATES
UNAVAILABLE_STATES

Public Class Methods

new(app, http, notification, batch) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 13
def initialize(app, http, notification, batch)
  @app = app
  @http = http
  @notification = notification
  @batch = batch
end

Public Instance Methods

perform() click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 20
def perform
  handle_response(do_post)
rescue SocketError => error
  mark_retryable(@notification, Time.now + 10.seconds, error)
  raise
rescue StandardError => error
  mark_failed(error)
  raise
ensure
  @batch.notification_processed
end

Protected Instance Methods

bad_gateway(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 126
def bad_gateway(response)
  retry_delivery(@notification, response)
  log_warn("GCM responded with a Bad Gateway Error. " + retry_message)
end
bad_request() click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 113
def bad_request
  fail Rpush::DeliveryError.new(400, @notification.id, 'GCM failed to parse the JSON request. Possibly an Rpush bug, please open an issue.')
end
create_new_notification(response, unavailable_idxs) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 106
def create_new_notification(response, unavailable_idxs)
  attrs = { 'app_id' => @notification.app_id, 'collapse_key' => @notification.collapse_key, 'delay_while_idle' => @notification.delay_while_idle }
  registration_ids = @notification.registration_ids.values_at(*unavailable_idxs)
  Rpush::Daemon.store.create_gcm_notification(attrs, @notification.data,
                                              registration_ids, deliver_after_header(response), @app)
end
deliver_after_header(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 141
def deliver_after_header(response)
  Rpush::Daemon::RetryHeaderParser.parse(response.header['retry-after'])
end
do_post() click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 158
def do_post
  post = Net::HTTP::Post.new(FCM_URI.path, 'Content-Type'  => 'application/json',
                                           'Authorization' => "key=#{@app.auth_key}")
  post.body = @notification.as_json.to_json
  @http.request(FCM_URI, post)
end
handle_errors(failures) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 97
def handle_errors(failures)
  failures.each do |result|
    reflect(:gcm_failed_to_recipient, @notification, result[:error], result[:registration_id])
  end
  failures[:invalid].each do |result|
    reflect(:gcm_invalid_registration_id, @app, result[:error], result[:registration_id])
  end
end
handle_failures(failures, response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 82
def handle_failures(failures, response)
  if failures[:unavailable].count == @notification.registration_ids.count
    retry_delivery(@notification, response)
    log_warn("All recipients unavailable. #{retry_message}")
  else
    if failures[:unavailable].any?
      unavailable_idxs = failures[:unavailable].map { |result| result[:index] }
      new_notification = create_new_notification(response, unavailable_idxs)
      failures.description += " #{unavailable_idxs.join(', ')} will be retried as notification #{new_notification.id}."
    end
    handle_errors(failures)
    fail Rpush::DeliveryError.new(nil, @notification.id, failures.description)
  end
end
handle_response(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 34
def handle_response(response)
  case response.code.to_i
  when 200
    ok(response)
  when 400
    bad_request
  when 401
    unauthorized
  when 500
    internal_server_error(response)
  when 502
    bad_gateway(response)
  when 503
    service_unavailable(response)
  when 500..599
    other_5xx_error(response)
  else
    fail Rpush::DeliveryError.new(response.code.to_i, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
  end
end
handle_successes(successes) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 74
def handle_successes(successes)
  successes.each do |result|
    reflect(:gcm_delivered_to_recipient, @notification, result[:registration_id])
    next unless result.key?(:canonical_id)
    reflect(:gcm_canonical_id, result[:registration_id], result[:canonical_id])
  end
end
internal_server_error(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 121
def internal_server_error(response)
  retry_delivery(@notification, response)
  log_warn("GCM responded with an Internal Error. " + retry_message)
end
ok(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 55
def ok(response)
  results = process_response(response)
  handle_successes(results.successes)

  if results.failures.any?
    handle_failures(results.failures, response)
  else
    mark_delivered
    log_info("#{@notification.id} sent to #{@notification.registration_ids.join(', ')}")
  end
end
other_5xx_error(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 136
def other_5xx_error(response)
  retry_delivery(@notification, response)
  log_warn("GCM responded with a 5xx Error. " + retry_message)
end
process_response(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 67
def process_response(response)
  body = multi_json_load(response.body)
  results = Results.new(body['results'], @notification.registration_ids)
  results.process(invalid: INVALID_REGISTRATION_ID_STATES, unavailable: UNAVAILABLE_STATES)
  results
end
retry_delivery(notification, response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 145
def retry_delivery(notification, response)
  time = deliver_after_header(response)
  if time
    mark_retryable(notification, time)
  else
    mark_retryable_exponential(notification)
  end
end
retry_message() click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 154
def retry_message
  "Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')} (retry #{@notification.retries})."
end
service_unavailable(response) click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 131
def service_unavailable(response)
  retry_delivery(@notification, response)
  log_warn("GCM responded with an Service Unavailable Error. " + retry_message)
end
unauthorized() click to toggle source
# File lib/rpush/daemon/gcm/delivery.rb, line 117
def unauthorized
  fail Rpush::DeliveryError.new(401, @notification.id, 'Unauthorized, check your App auth_key.')
end