lib/submodules/ably-ruby/lib/ably/rest/channel.rb in ably-rest-1.0.6 vs lib/submodules/ably-ruby/lib/ably/rest/channel.rb in ably-rest-1.1.0

- old
+ new

@@ -1,21 +1,31 @@ module Ably module Rest # The Ably Realtime service organises the traffic within any application into named channels. # Channels are the "unit" of message distribution; clients attach to channels to subscribe to messages, and every message broadcast by the service is associated with a unique channel. # - # @!attribute [r] client - # @return {Ably::Realtime::Client} Ably client associated with this channel # @!attribute [r] name # @return {String} channel name # @!attribute [r] options # @return {Hash} channel options configured for this channel, see {#initialize} for channel_options class Channel include Ably::Modules::Conversions - attr_reader :client, :name, :options + # Ably client associated with this channel + # @return [Ably::Realtime::Client] + # @api private + attr_reader :client + attr_reader :name, :options + + # Push channel used for push notification (client-side) + # @return [Ably::Rest::Channel::PushChannel] + # @api private + attr_reader :push + + IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH = 9 # See spec RSL1k1 + # Initialize a new Channel object # # @param client [Ably::Rest::Client] # @param name [String] The name of the channel # @param channel_options [Hash] Channel options, currently reserved for Encryption options @@ -25,17 +35,18 @@ name = (ensure_utf_8 :name, name) update_options channel_options @client = client @name = name + @push = PushChannel.new(self) end # Publish one or more messages to the channel. # # @param name [String, Array<Ably::Models::Message|Hash>, nil] The event name of the message to publish, or an Array of [Ably::Model::Message] objects or [Hash] objects with +:name+ and +:data+ pairs # @param data [String, ByteArray, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument - # @param attributes [Hash, nil] Optional additional message attributes such as :client_id or :connection_id, applied when name attribute is nil or a string + # @param attributes [Hash, nil] Optional additional message attributes such as :extras, :id, :client_id or :connection_id, applied when name attribute is nil or a string # @return [Boolean] true if the message was published, otherwise false # # @example # # Publish a single message # channel.publish 'click', { x: 1, y: 2 } @@ -56,16 +67,20 @@ # def publish(name, data = nil, attributes = {}) messages = if name.kind_of?(Enumerable) name else + if name.kind_of?(Ably::Models::Message) + raise ArgumentError, "name argument does not support single Message objects, only arrays of Message objects" + end + name = ensure_utf_8(:name, name, allow_nil: true) ensure_supported_payload data [{ name: name, data: data }.merge(attributes)] end - payload = messages.map do |message| + payload = messages.each_with_index.map do |message, index| Ably::Models::Message(message.dup).tap do |msg| msg.encode client.encoders, options next if msg.client_id.nil? if msg.client_id == '*' @@ -73,10 +88,21 @@ end unless client.auth.can_assume_client_id?(msg.client_id) raise Ably::Exceptions::IncompatibleClientId.new("Cannot publish with client_id '#{msg.client_id}' as it is incompatible with the current configured client_id '#{client.client_id}'") end end.as_json + end.tap do |payload| + if client.idempotent_rest_publishing + # We cannot mutate for idempotent publishing if one or more messages already has an ID + if payload.all? { |msg| !msg['id'] } + # Mutate the JSON to support idempotent publishing where a Message.id does not exist + idempotent_publish_id = SecureRandom.base64(IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH) + payload.each_with_index do |msg, idx| + msg['id'] = "#{idempotent_publish_id}:#{idx}" + end + end + end end response = client.post("#{base_path}/publish", payload.length == 1 ? payload.first : payload) [201, 204].include?(response.status) @@ -139,5 +165,7 @@ client.logger.error { "Decoding Error on channel '#{name}', message event name '#{message.name}'. #{e.class.name}: #{e.message}" } end end end end + +require 'ably/rest/channel/push_channel'