require 'faraday' require 'faraday_middleware' require 'time' # A very tiny Urban Airship Push Notification API client. # # Provides thin wrappers around API calls to the most common API tasks. For more # information on how the requests and responses are formatted, visit the [Urban # Airship Push Notification API docs](http://urbanairship.com/docs/push.html). class Zeppelin BASE_URI = 'https://go.urbanairship.com' PUSH_URI = '/api/push/' BATCH_PUSH_URI = '/api/push/batch/' BROADCAST_URI = '/api/push/broadcast/' JSON_HEADERS = { 'Content-Type' => 'application/json' } attr_reader :application_key, :application_master_secret, :options # @param [String] application_key your Urban Airship Application Key # # @param [String] application_master_secret your Urban Airship Application # Master Secret def initialize(application_key, application_master_secret, options = {}) @application_key = application_key @application_master_secret = application_master_secret @options = options end # The connection to UrbanAirship def connection return @connection if defined?(@connection) @connection = initialize_connection end # Registers an iPhone device token. # # @param [String] device_token # @param [Hash] payload the payload to send during registration # # @return [Boolean] whether or not the registration was successful # # @raise [Zeppelin::ClientError] malformed request def register_device_token(device_token, payload = {}) uri = device_token_uri(device_token) put_request(uri, payload) end # Registers an Android APID. # # @param [String] apid # # @param [Hash] payload the payload to send during registration # # @return [Boolean] whether or not the registration was successful # # @raise [Zeppelin::ClientError] invalid payload format def register_apid(apid, payload = {}) uri = apid_uri(apid) put_request(uri, payload) end # Registers a Blackberry PIN # # @param [String] pin # # @param [Hash] payload the payload to send during registration # # @return [Boolean] whether or not the registration was successful # # @raise [Zeppelin::ClientError] invalid payload format # # @see http://urbanairship.com/docs/blackberry.html#registration def register_pin(pin, payload = {}) uri = pin_uri(pin) put_request(uri, payload) end # Retrieves information on a device token. # # @param [String] device_token # @return [Hash, nil] # # @raise [Zeppelin::ResourceNotFound] invalid device token provided def device_token(device_token) uri = device_token_uri(device_token) get_request(uri) end # Retrieves information on an APID. # # @param [String] apid # # @return [Hash, nil] # # @raise [Zeppelin::ResourceNotFound] invalid APID provided def apid(apid) uri = apid_uri(apid) get_request(uri) end # @param [String] pin # # @return [Hash, nil] # # @raise [Zeppelin::ResourceNotFound] invalid PIN provided def pin(pin) uri = pin_uri(pin) get_request(uri) end # Deletes a device token. # # @param [String] device_token # # @return [Boolean] whether or not the deletion was successful # # @raise [Zeppelin::ResourceNotFound] invalid device token provided def delete_device_token(device_token) uri = device_token_uri(device_token) delete_request(uri) end # Deletes an APID. # # @param [String] apid # # @return [Boolean] whether or not the deletion was successful # # @raise [Zeppelin::ResourceNotFound] invalid APID provided def delete_apid(apid) uri = apid_uri(apid) delete_request(uri) end # Deletes a PIN # # @param [String] pin # # @return [Boolean] whether or not deletion was successful # # @raise [Zeppelin::ResourceNotFound] invalid PIN provided def delete_pin(pin) uri = pin_uri(pin) delete_request(uri) end # Retrieve a page of device tokens # # @param [Integer] page (nil) Page of device tokens to retrieve # # @return [Hash] result set. See documentation for details # # @Note that the next page number is included in the result set instead of the # raw URI to request for the next page # # @raise [Zeppelin::ClientError] invalid request def device_tokens(page=nil) uri = device_token_uri(nil, :page => page) get_paged_request(uri) end # Retrieve a page of APIDs # # @param [Integer] page (nil) Page of APIDs to retrieve # # @return [Hash] result set. See documentation for details # # @Note that the next page number is included in the result set instead of the # raw URI to request for the next page # # @raise [Zeppelin::ClientError] invalid request def apids(page=nil) uri = apid_uri(nil, :page => page) get_paged_request(uri) end # Pushes a message. # # @param [Hash] payload the payload of the message # # @return [Boolean] whether or not pushing the message was successful # # @raise [Zeppelin::ClientError] invalid payload format def push(payload) post_request(PUSH_URI, payload) end # Batch pushes multiple messages. # # @param [] payload the payloads of each message # # @return [Boolean] whether or not pushing the messages was successful # # @raise [Zeppelin::ClientError] invalid payload format def batch_push(*payload) post_request(BATCH_PUSH_URI, payload) end # Broadcasts a message. # # @param [Hash] payload the payload of the message # # @return [Boolean] whether or not broadcasting the message was successful # # @raise [Zeppelin::ClientError] invalid payload format def broadcast(payload) post_request(BROADCAST_URI, payload) end # Retrieves feedback on device tokens. # # This is useful for removing inactive device tokens for the database. # # @param [Time] since the time to retrieve inactive tokens from # # @return [Hash, nil] # # @raise [Zeppelin::ClientError] invalid time param def feedback(since) uri = feedback_uri(since) get_request(uri) end # Retrieve all tags on the service # # @return [Hash, nil] def tags uri = tag_uri(nil) get_request(uri) end # Modifies device tokens associated with a tag. # # @param [String] tag The name of the tag to modify tag associations on # # @param [Hash] payload # # @see http://urbanairship.com/docs/tags.html#modifying-device-tokens-on-a-tag def modify_device_tokens_on_tag(tag_name, payload = {}) uri = tag_uri(tag_name) post_request(uri, payload) end # Creates a tag that is not associated with any device # # @param [#to_s] name The name of the tag to add # # @return [Boolean] whether or not the request was successful def add_tag(name) uri = tag_uri(name) put_request(uri) end # Removes a tag from the service # # @param [#to_s] name The name of the tag to remove # # @return [Boolean] true when the request was successful. Note that this # method will return false if the tag has already been removed. # # @raise [Zeppelin::ResourceNotFound] tag already removed def remove_tag(name) uri = tag_uri(name) delete_request(uri) end # @param [String] device_token # # @return [Hash, nil] # # @raise [Zeppelin::ResourceNotFound] device does not exist def device_tags(device_token) uri = device_tag_uri(device_token, nil) get_request(uri) end # @param [String] device_token # # @param [#to_s] tag_name # # @return [Boolean] whether or not a tag was successfully associated with # a device # # @raise [Zeppelin::ResourceNotFound] device does not exist def add_tag_to_device(device_token, tag_name) uri = device_tag_uri(device_token, tag_name) put_request(uri) end # @param [String] device_token # # @param [#to_s] tag_name # # @return [Boolean] whether or not a tag was successfully dissociated from # a device # # @raise [Zeppelin::ResourceNotFound] device does not exist def remove_tag_from_device(device_token, tag_name) uri = device_tag_uri(device_token, tag_name) delete_request(uri) end private def initialize_connection conn = Faraday::Connection.new(BASE_URI, @options) do |builder| builder.request :json builder.response :json, :content_type => /\bjson$/ builder.response :zeppelin_raise_error builder.adapter :net_http end conn.basic_auth(@application_key, @application_master_secret) conn end def put_request(uri, payload={}) if !(payload.nil? || payload.empty?) response = connection.put(uri, payload, JSON_HEADERS) else response = connection.put(uri) end response.success? end def delete_request(uri) connection.delete(uri).success? end def get_request(uri) response = connection.get(uri) response.body if response.success? end def get_paged_request(uri) results = get_request(uri) md = results['next_page'] && results['next_page'].match(/(start|page)=(\d+)/) results['next_page'] = md[2].to_i unless md.nil? results end def post_request(uri, payload) connection.post(uri, payload, JSON_HEADERS).success? end def query_string(query) '?' + query.map { |k, v| "#{k}=#{v}" }.join('&') end def device_token_uri(device_token, query={}) uri = "/api/device_tokens/#{device_token}" uri << query_string(query) unless query.empty? uri end def apid_uri(apid, query={}) uri = "/api/apids/#{apid}" uri << query_string(query) unless query.empty? uri end def feedback_uri(since) "/api/device_tokens/feedback/?since=#{since.utc.iso8601}" end def tag_uri(name) "/api/tags/#{name}" end def device_tag_uri(device_token, tag_name) device_token_uri(device_token) + "/tags/#{tag_name}" end def pin_uri(pin) "/api/device_pins/#{pin}/" end end require 'zeppelin/middleware' require 'zeppelin/version'