class Firebase::Admin::Messaging::Client

A client for communicating with the Firebase Cloud Messaging service.

Constants

FCM_ERROR_TYPES
FCM_HEADERS
FCM_HOST
IID_HEADERS
IID_HOST

Public Class Methods

new(app) click to toggle source
# File lib/firebase/admin/messaging/client.rb, line 6
def initialize(app)
  @project_id = app.project_id
  @http_client = Firebase::Admin::Internal::HTTPClient.new(credentials: app.credentials)
  @message_encoder = MessageEncoder.new
end

Public Instance Methods

send_all(messages, dry_run: false) click to toggle source

Sends the given list of messages via Firebase Cloud Messaging (FCM) as a single batch.

If the `dry_run` flag is set, the messages will not be actually delivered to the recipients. Instead FCM performs all the usual validations, and emulates the send operation.

@param [Array<Message>] messages An array of messages to send. @param [Boolean] dry_run A flag indicating whether to run the operation in dry run mode.

@return [BatchResponse] A batch response.

# File lib/firebase/admin/messaging/client.rb, line 41
def send_all(messages, dry_run: false)
  raise NotImplementedError
end
send_multicast(multicast_message, dry_run: false) click to toggle source

Sends the given multicast message to all tokens via Firebase Cloud Messaging (FCM).

If the `dry_run` flag is set, the message will not be actually delivered to the recipients. Instead FCM performs all the usual validations, and emulates the send operation.

@param [MulticastMessage] multicast_message A multicast message to send. @param [Boolean] dry_run A flag indicating whether to run the operation in dry run mode.

@return [BatchResponse] A batch response.

# File lib/firebase/admin/messaging/client.rb, line 54
def send_multicast(multicast_message, dry_run: false)
  messages = multicast_message.tokens.map do |token|
    Message.new(
      token: token,
      data: multicast_message.data,
      notification: multicast_message.notification,
      android: multicast_message.android,
      apns: multicast_message.apns,
      fcm_options: multicast_message.fcm_options
    )
  end
  send_all(messages, dry_run: dry_run)
end
send_one(message, dry_run: false) click to toggle source

Sends a message via Firebase Cloud Messaging (FCM).

If the `dry_run` flag is set, the message will not be actually delivered to the recipients. Instead FCM performs all the usual validations, and emulates the send operation.

@param [Message] message A message to send. @param [Boolean] dry_run A flag indicating whether to run the operation in dry run mode.

@return [String] A message id that uniquely identifies the message.

# File lib/firebase/admin/messaging/client.rb, line 21
def send_one(message, dry_run: false)
  body = {
    validate_only: dry_run,
    message: @message_encoder.encode(message)
  }
  res = @http_client.post(send_url, body, FCM_HEADERS)
  res.body["name"]
rescue Faraday::Error => e
  raise parse_fcm_error(e)
end
subscribe_to_topic(tokens, topic) click to toggle source

Subscribes a list of registration tokens to an FCM topic.

@param [Array<String>, String] tokens An array of device registration tokens (max 1000). @param [String] topic Name of the topic to subscribe to. May contain the `/topics` prefix.

@return [TopicManagementResponse] A topic management response.

# File lib/firebase/admin/messaging/client.rb, line 74
def subscribe_to_topic(tokens, topic)
  make_topic_mgmt_request(tokens, topic, "batchAdd")
end
unsubscribe_from_topic(tokens, topic) click to toggle source

Unsubscribes a list of registration tokens from an FCM topic.

@param [Array<String>, String] tokens An array of device registration tokens (max 1000). @param [String] topic Name of the topic to unsubscribe from. May contain the `/topics` prefix.

@return [TopicManagementResponse] A topic management response.

# File lib/firebase/admin/messaging/client.rb, line 84
def unsubscribe_from_topic(tokens, topic)
  make_topic_mgmt_request(tokens, topic, "batchRemove")
end

Private Instance Methods

make_topic_mgmt_request(tokens, topic, operation) click to toggle source
# File lib/firebase/admin/messaging/client.rb, line 100
def make_topic_mgmt_request(tokens, topic, operation)
  tokens = [tokens] if tokens.is_a?(String)

  unless tokens.is_a?(Array) && !tokens.empty?
    raise ArgumentError, "tokens must be a string or non-empty array of strings."
  end

  unless tokens.all?(String)
    raise ArgumentError, "tokens must be a non-empty array of strings."
  end

  unless topic.is_a?(String) && !topic.empty?
    raise ArgumentError, "topic must be a non-empty string."
  end

  unless %w[batchAdd batchRemove].include?(operation)
    raise ArgumentError, "operation is invalid"
  end

  uri = topic_mgmt_url(operation)
  res = @http_client.post(uri, {
    to: @message_encoder.sanitize_topic_name(topic, strip_prefix: false),
    registration_tokens: tokens
  }, IID_HEADERS)
  TopicManagementResponse.new(res)
end
parse_fcm_error(err) click to toggle source

@param [Faraday::Error] err

# File lib/firebase/admin/messaging/client.rb, line 128
def parse_fcm_error(err)
  msg, info = parse_platform_error(err.response_status, err.response_body)
  return err if info.empty?

  details = info["details"] || []
  detail = details.find { |detail| detail["@type"] == "type.googleapis.com/google.firebase.fcm.v1.FcmError" }
  return err unless detail.is_a?(Hash)

  cls = FCM_ERROR_TYPES[detail["errorCode"] || ""] || Error
  cls.new(msg, info)
rescue JSON::ParserError
  Error.new("HTTP response is not json.", err.response)
end
parse_platform_error(status_code, body) click to toggle source

Parses an HTTP error response from a Google Cloud Platform API and extracts the error code and message fields.

@param [Integer] status_code @param [String] body @return Array<String,Hash>

# File lib/firebase/admin/messaging/client.rb, line 148
def parse_platform_error(status_code, body)
  parsed = JSON.parse(body)
  data = parsed.is_a?(Hash) ? parsed : {}
  details = data.fetch("error", {})
  msg = details.fetch("message", "Unexpected HTTP response with status #{status_code}; body: #{body}")
  [msg, details]
end
send_url() click to toggle source

@return [String] The firebase cloud messaging send endpoint url.

# File lib/firebase/admin/messaging/client.rb, line 91
def send_url
  "#{FCM_HOST}/v1/projects/#{@project_id}/messages:send"
end
topic_mgmt_url(operation) click to toggle source

@return [String] The topic management endpoint url.

# File lib/firebase/admin/messaging/client.rb, line 96
def topic_mgmt_url(operation)
  "#{IID_HOST}/iid/v1:#{operation}"
end