ably-pubsub-core 0.0.1.pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/ably/agent.rb +8 -0
- data/lib/ably/auth.rb +791 -0
- data/lib/ably/exceptions.rb +169 -0
- data/lib/ably/logger.rb +119 -0
- data/lib/ably/models/auth_details.rb +45 -0
- data/lib/ably/models/channel_details.rb +69 -0
- data/lib/ably/models/channel_metrics.rb +107 -0
- data/lib/ably/models/channel_occupancy.rb +50 -0
- data/lib/ably/models/channel_options.rb +120 -0
- data/lib/ably/models/channel_state_change.rb +84 -0
- data/lib/ably/models/channel_status.rb +63 -0
- data/lib/ably/models/cipher_params.rb +137 -0
- data/lib/ably/models/connection_details.rb +149 -0
- data/lib/ably/models/connection_state_change.rb +83 -0
- data/lib/ably/models/delta_extras.rb +28 -0
- data/lib/ably/models/device_details.rb +126 -0
- data/lib/ably/models/device_push_details.rb +94 -0
- data/lib/ably/models/error_info.rb +104 -0
- data/lib/ably/models/http_paginated_response.rb +112 -0
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +235 -0
- data/lib/ably/models/message.rb +223 -0
- data/lib/ably/models/message_encoders/base.rb +135 -0
- data/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/ably/models/message_encoders/cipher.rb +84 -0
- data/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_result.rb +201 -0
- data/lib/ably/models/presence_message.rb +244 -0
- data/lib/ably/models/protocol_message.rb +288 -0
- data/lib/ably/models/push_channel_subscription.rb +114 -0
- data/lib/ably/models/stats.rb +242 -0
- data/lib/ably/models/stats_types.rb +107 -0
- data/lib/ably/models/token_details.rb +148 -0
- data/lib/ably/models/token_request.rb +180 -0
- data/lib/ably/modules/ably.rb +26 -0
- data/lib/ably/modules/async_wrapper.rb +69 -0
- data/lib/ably/modules/channels_collection.rb +105 -0
- data/lib/ably/modules/conversions.rb +153 -0
- data/lib/ably/modules/encodeable.rb +111 -0
- data/lib/ably/modules/enum.rb +230 -0
- data/lib/ably/modules/event_emitter.rb +200 -0
- data/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/ably/modules/exception_codes.rb +128 -0
- data/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/ably/modules/message_emitter.rb +78 -0
- data/lib/ably/modules/message_pack.rb +14 -0
- data/lib/ably/modules/model_common.rb +84 -0
- data/lib/ably/modules/safe_deferrable.rb +83 -0
- data/lib/ably/modules/safe_yield.rb +41 -0
- data/lib/ably/modules/state_emitter.rb +181 -0
- data/lib/ably/modules/state_machine.rb +59 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +111 -0
- data/lib/ably/realtime/auth.rb +283 -0
- data/lib/ably/realtime/channel/channel_manager.rb +272 -0
- data/lib/ably/realtime/channel/channel_properties.rb +40 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +104 -0
- data/lib/ably/realtime/channel/publisher.rb +82 -0
- data/lib/ably/realtime/channel/push_channel.rb +69 -0
- data/lib/ably/realtime/channel.rb +440 -0
- data/lib/ably/realtime/channels.rb +71 -0
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +225 -0
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +87 -0
- data/lib/ably/realtime/client.rb +363 -0
- data/lib/ably/realtime/connection/connection_manager.rb +594 -0
- data/lib/ably/realtime/connection/connection_state_machine.rb +144 -0
- data/lib/ably/realtime/connection/websocket_transport.rb +287 -0
- data/lib/ably/realtime/connection.rb +738 -0
- data/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/ably/realtime/presence/members_map.rb +395 -0
- data/lib/ably/realtime/presence/presence_manager.rb +78 -0
- data/lib/ably/realtime/presence/presence_state_machine.rb +57 -0
- data/lib/ably/realtime/presence.rb +502 -0
- data/lib/ably/realtime/push/admin.rb +75 -0
- data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
- data/lib/ably/realtime/push/device_registrations.rb +105 -0
- data/lib/ably/realtime/push.rb +25 -0
- data/lib/ably/realtime/recovery_key_context.rb +36 -0
- data/lib/ably/realtime.rb +60 -0
- data/lib/ably/rest/channel/push_channel.rb +59 -0
- data/lib/ably/rest/channel.rb +194 -0
- data/lib/ably/rest/channels.rb +47 -0
- data/lib/ably/rest/client.rb +727 -0
- data/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/ably/rest/middleware/exceptions.rb +53 -0
- data/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +22 -0
- data/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/ably/rest/middleware/parse_message_pack.rb +43 -0
- data/lib/ably/rest/presence.rb +113 -0
- data/lib/ably/rest/push/admin.rb +58 -0
- data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
- data/lib/ably/rest/push/device_registrations.rb +114 -0
- data/lib/ably/rest/push.rb +25 -0
- data/lib/ably/rest.rb +40 -0
- data/lib/ably/util/ably_extensions.rb +29 -0
- data/lib/ably/util/crypto.rb +134 -0
- data/lib/ably/util/pub_sub.rb +45 -0
- data/lib/ably/util/safe_deferrable.rb +44 -0
- data/lib/ably/version.rb +7 -0
- data/lib/ably.rb +16 -0
- metadata +497 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Ably::Realtime
|
|
2
|
+
class Push
|
|
3
|
+
# Manage device registrations for push notifications
|
|
4
|
+
class DeviceRegistrations
|
|
5
|
+
include Ably::Modules::Conversions
|
|
6
|
+
include Ably::Modules::AsyncWrapper
|
|
7
|
+
|
|
8
|
+
# @api private
|
|
9
|
+
attr_reader :client
|
|
10
|
+
|
|
11
|
+
# @api private
|
|
12
|
+
attr_reader :admin
|
|
13
|
+
|
|
14
|
+
def initialize(admin)
|
|
15
|
+
@admin = admin
|
|
16
|
+
@client = admin.client
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# (see Ably::Rest::Push::DeviceRegistrations#get)
|
|
20
|
+
#
|
|
21
|
+
# @yield Block is invoked when request succeeds
|
|
22
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
23
|
+
#
|
|
24
|
+
def get(device_id, &callback)
|
|
25
|
+
device_id = device_id.id if device_id.kind_of?(Ably::Models::DeviceDetails)
|
|
26
|
+
raise ArgumentError, "device_id must be a string or DeviceDetails object" unless device_id.kind_of?(String)
|
|
27
|
+
|
|
28
|
+
async_wrap(callback) do
|
|
29
|
+
rest_device_registrations.get(device_id)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# (see Ably::Rest::Push::DeviceRegistrations#list)
|
|
34
|
+
#
|
|
35
|
+
# @yield Block is invoked when request succeeds
|
|
36
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
37
|
+
#
|
|
38
|
+
def list(params = {}, &callback)
|
|
39
|
+
params = {} if params.nil?
|
|
40
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
|
41
|
+
raise ArgumentError, "device_id filter cannot be specified alongside a client_id filter. Use one or the other" if params[:client_id] && params[:device_id]
|
|
42
|
+
|
|
43
|
+
async_wrap(callback) do
|
|
44
|
+
rest_device_registrations.list(params.merge(async_blocking_operations: true))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# (see Ably::Rest::Push::DeviceRegistrations#save)
|
|
49
|
+
#
|
|
50
|
+
# @yield Block is invoked when request succeeds
|
|
51
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
52
|
+
#
|
|
53
|
+
def save(device, &callback)
|
|
54
|
+
device_details = DeviceDetails(device)
|
|
55
|
+
raise ArgumentError, "Device ID is required yet is empty" if device_details.id.nil? || device_details == ''
|
|
56
|
+
|
|
57
|
+
async_wrap(callback) do
|
|
58
|
+
rest_device_registrations.save(device_details)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# (see Ably::Rest::Push::DeviceRegistrations#remove)
|
|
63
|
+
#
|
|
64
|
+
# @yield Block is invoked when request succeeds
|
|
65
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
66
|
+
#
|
|
67
|
+
def remove(device_id, &callback)
|
|
68
|
+
device_id = device_id.id if device_id.kind_of?(Ably::Models::DeviceDetails)
|
|
69
|
+
raise ArgumentError, "device_id must be a string or DeviceDetails object" unless device_id.kind_of?(String)
|
|
70
|
+
|
|
71
|
+
async_wrap(callback) do
|
|
72
|
+
rest_device_registrations.remove(device_id)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# (see Ably::Rest::Push::DeviceRegistrations#remove_where)
|
|
77
|
+
#
|
|
78
|
+
# @yield Block is invoked when request succeeds
|
|
79
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
80
|
+
#
|
|
81
|
+
def remove_where(params = {}, &callback)
|
|
82
|
+
filter = if params.kind_of?(Ably::Models::DeviceDetails)
|
|
83
|
+
{ 'deviceId' => params.id }
|
|
84
|
+
else
|
|
85
|
+
raise ArgumentError, "params must be a Hash" unless params.kind_of?(Hash)
|
|
86
|
+
raise ArgumentError, "device_id filter cannot be specified alongside a client_id filter. Use one or the other" if params[:client_id] && params[:device_id]
|
|
87
|
+
IdiomaticRubyWrapper(params).as_json
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
async_wrap(callback) do
|
|
91
|
+
rest_device_registrations.remove_where(filter)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
def rest_device_registrations
|
|
97
|
+
client.rest_client.push.admin.device_registrations
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def logger
|
|
101
|
+
client.logger
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'ably/realtime/push/admin'
|
|
2
|
+
|
|
3
|
+
module Ably
|
|
4
|
+
module Realtime
|
|
5
|
+
# Class providing push notification functionality
|
|
6
|
+
class Push
|
|
7
|
+
# @private
|
|
8
|
+
attr_reader :client
|
|
9
|
+
|
|
10
|
+
def initialize(client)
|
|
11
|
+
@client = client
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# A {Ably::Realtime::Push::Admin} object.
|
|
15
|
+
#
|
|
16
|
+
# @spec RSH1
|
|
17
|
+
#
|
|
18
|
+
# @return [Ably::Realtime::Push::Admin]
|
|
19
|
+
#
|
|
20
|
+
def admin
|
|
21
|
+
@admin ||= Admin.new(self)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Ably
|
|
5
|
+
module Realtime
|
|
6
|
+
class RecoveryKeyContext
|
|
7
|
+
attr_reader :connection_key
|
|
8
|
+
attr_reader :msg_serial
|
|
9
|
+
attr_reader :channel_serials
|
|
10
|
+
|
|
11
|
+
def initialize(connection_key, msg_serial, channel_serials)
|
|
12
|
+
@connection_key = connection_key
|
|
13
|
+
@msg_serial = msg_serial
|
|
14
|
+
@channel_serials = channel_serials
|
|
15
|
+
if @channel_serials.nil?
|
|
16
|
+
@channel_serials = {}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_json
|
|
21
|
+
{ 'connection_key' => @connection_key, 'msg_serial' => @msg_serial, 'channel_serials' => @channel_serials }.to_json
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.from_json(obj, logger = nil)
|
|
25
|
+
begin
|
|
26
|
+
data = JSON.load obj
|
|
27
|
+
self.new data['connection_key'], data['msg_serial'], data['channel_serials']
|
|
28
|
+
rescue => e
|
|
29
|
+
logger.warn "unable to decode recovery key, found error #{e}" unless logger.nil?
|
|
30
|
+
return nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
require 'websocket/driver'
|
|
3
|
+
require 'em-http-request'
|
|
4
|
+
|
|
5
|
+
require 'ably/modules/event_emitter'
|
|
6
|
+
|
|
7
|
+
require 'ably/realtime/auth'
|
|
8
|
+
require 'ably/realtime/channel'
|
|
9
|
+
require 'ably/realtime/channels'
|
|
10
|
+
require 'ably/realtime/client'
|
|
11
|
+
require 'ably/realtime/connection'
|
|
12
|
+
require 'ably/realtime/push'
|
|
13
|
+
require 'ably/realtime/presence'
|
|
14
|
+
|
|
15
|
+
require 'ably/models/message_encoders/base'
|
|
16
|
+
|
|
17
|
+
Dir.glob(File.expand_path("models/*.rb", File.dirname(__FILE__))).each do |file|
|
|
18
|
+
require file
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Dir.glob(File.expand_path("realtime/models/*.rb", File.dirname(__FILE__))).each do |file|
|
|
22
|
+
require file
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require 'ably/models/message_encoders/base'
|
|
26
|
+
|
|
27
|
+
require 'ably/realtime/client/incoming_message_dispatcher'
|
|
28
|
+
require 'ably/realtime/client/outgoing_message_dispatcher'
|
|
29
|
+
|
|
30
|
+
module Ably
|
|
31
|
+
# Realtime provides the top-level class to be instanced for the Ably Realtime library
|
|
32
|
+
#
|
|
33
|
+
# @example
|
|
34
|
+
# client = Ably::Realtime.new("xxxxx")
|
|
35
|
+
# channel = client.channel("test")
|
|
36
|
+
# channel.subscribe do |message|
|
|
37
|
+
# message[:name] #=> "greeting"
|
|
38
|
+
# end
|
|
39
|
+
# channel.publish "greeting", "data"
|
|
40
|
+
#
|
|
41
|
+
module Realtime
|
|
42
|
+
# Convenience method providing an alias to {Ably::Realtime::Client} constructor.
|
|
43
|
+
#
|
|
44
|
+
# @param (see Ably::Realtime::Client#initialize)
|
|
45
|
+
# @option options (see Ably::Realtime::Client#initialize)
|
|
46
|
+
#
|
|
47
|
+
# @return [Ably::Realtime::Client]
|
|
48
|
+
#
|
|
49
|
+
# @example
|
|
50
|
+
# # create a new client authenticating with basic auth
|
|
51
|
+
# client = Ably::Realtime.new('key.id:secret')
|
|
52
|
+
#
|
|
53
|
+
# # create a new client authenticating with basic auth and a client_id
|
|
54
|
+
# client = Ably::Realtime.new(key: 'key.id:secret', client_id: 'john')
|
|
55
|
+
#
|
|
56
|
+
def self.new(options)
|
|
57
|
+
Ably::Realtime::Client.new(options)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Ably::Rest
|
|
2
|
+
class Channel
|
|
3
|
+
# A push channel used for push notifications
|
|
4
|
+
# Each PushChannel maps to exactly one Rest Channel
|
|
5
|
+
#
|
|
6
|
+
class PushChannel
|
|
7
|
+
attr_reader :channel
|
|
8
|
+
|
|
9
|
+
def initialize(channel)
|
|
10
|
+
raise ArgumentError, "Unsupported channel type '#{channel.class}'" unless channel.kind_of?(Ably::Rest::Channel)
|
|
11
|
+
@channel = channel
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
"<PushChannel: name=#{channel.name}>"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Subscribe local device for push notifications on this channel
|
|
19
|
+
#
|
|
20
|
+
# @note This is unsupported in the Ruby library
|
|
21
|
+
def subscribe_device(*args)
|
|
22
|
+
raise_unsupported
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Subscribe all devices registered to this client's authenticated client_id for push notifications on this channel
|
|
26
|
+
#
|
|
27
|
+
# @note This is unsupported in the Ruby library
|
|
28
|
+
def subscribe_client_id(*args)
|
|
29
|
+
raise_unsupported
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Unsubscribe local device for push notifications on this channel
|
|
33
|
+
#
|
|
34
|
+
# @note This is unsupported in the Ruby library
|
|
35
|
+
def unsubscribe_device(*args)
|
|
36
|
+
raise_unsupported
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Unsubscribe all devices registered to this client's authenticated client_id for push notifications on this channel
|
|
40
|
+
#
|
|
41
|
+
# @note This is unsupported in the Ruby library
|
|
42
|
+
def unsubscribe_client_id(*args)
|
|
43
|
+
raise_unsupported
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Get list of subscriptions on this channel for this device or authenticate client_id
|
|
47
|
+
#
|
|
48
|
+
# @note This is unsupported in the Ruby library
|
|
49
|
+
def get_subscriptions(*args)
|
|
50
|
+
raise_unsupported
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
def raise_unsupported
|
|
55
|
+
raise Ably::Exceptions::PushNotificationsNotSupported, 'This device does not support receiving or subscribing to push notifications. All PushChannel methods are unavailable'
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module Rest
|
|
3
|
+
# Enables messages to be published and historic messages to be retrieved for a channel.
|
|
4
|
+
#
|
|
5
|
+
class Channel
|
|
6
|
+
include Ably::Modules::Conversions
|
|
7
|
+
|
|
8
|
+
# Ably client associated with this channel
|
|
9
|
+
# @return [Ably::Realtime::Client]
|
|
10
|
+
# @api private
|
|
11
|
+
attr_reader :client
|
|
12
|
+
|
|
13
|
+
# The channel name.
|
|
14
|
+
# @return [String]
|
|
15
|
+
attr_reader :name
|
|
16
|
+
|
|
17
|
+
attr_reader :options
|
|
18
|
+
|
|
19
|
+
# A {Ably::Rest::Channel::PushChannel} object
|
|
20
|
+
# @spec RSH4
|
|
21
|
+
# @return [Ably::Rest::Channel::PushChannel]
|
|
22
|
+
# @api private
|
|
23
|
+
attr_reader :push
|
|
24
|
+
|
|
25
|
+
IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH = 9 # See spec RSL1k1
|
|
26
|
+
|
|
27
|
+
# Initialize a new Channel object
|
|
28
|
+
#
|
|
29
|
+
# @param client [Ably::Rest::Client]
|
|
30
|
+
# @param name [String] The name of the channel
|
|
31
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
32
|
+
#
|
|
33
|
+
def initialize(client, name, channel_options = {})
|
|
34
|
+
name = (ensure_utf_8 :name, name)
|
|
35
|
+
|
|
36
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
37
|
+
@client = client
|
|
38
|
+
@name = name
|
|
39
|
+
@push = PushChannel.new(self)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Publishes a message to the channel. A callback may optionally be passed in to this call to be notified of success or failure of the operation.
|
|
43
|
+
#
|
|
44
|
+
# @spec RSL1
|
|
45
|
+
#
|
|
46
|
+
# @param name [String, Array<Ably::Models::Message|Hash>, Ably::Models::Message, 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, or a single Ably::Model::Message object
|
|
47
|
+
# @param data [String, Array, Hash, nil] The message payload unless an Array of [Ably::Model::Message] objects passed in the first argument, in which case an optional hash of query parameters
|
|
48
|
+
# @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 (Deprecated, will be removed in 2.0 in favour of constructing a Message object)
|
|
49
|
+
# @return [Boolean] true if the message was published, otherwise false
|
|
50
|
+
#
|
|
51
|
+
# @example
|
|
52
|
+
# # Publish a single message with (name, data) form
|
|
53
|
+
# channel.publish 'click', { x: 1, y: 2 }
|
|
54
|
+
#
|
|
55
|
+
# # Publish a single message with single Hash form
|
|
56
|
+
# message = { name: 'click', data: { x: 1, y: 2 } }
|
|
57
|
+
# channel.publish message
|
|
58
|
+
#
|
|
59
|
+
# # Publish an array of message Hashes form
|
|
60
|
+
# messages = [
|
|
61
|
+
# { name: 'click', data: { x: 1, y: 2 } },
|
|
62
|
+
# { name: 'click', data: { x: 2, y: 3 } }
|
|
63
|
+
# ]
|
|
64
|
+
# channel.publish messages
|
|
65
|
+
#
|
|
66
|
+
# # Publish an array of Ably::Models::Message objects form
|
|
67
|
+
# messages = [
|
|
68
|
+
# Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
|
69
|
+
# Ably::Models::Message(name: 'click', data: { x: 2, y: 3 })
|
|
70
|
+
# ]
|
|
71
|
+
# channel.publish messages
|
|
72
|
+
#
|
|
73
|
+
# # Publish a single Ably::Models::Message object form
|
|
74
|
+
# message = Ably::Models::Message(name: 'click', data: { x: 1, y: 2 })
|
|
75
|
+
# channel.publish message
|
|
76
|
+
#
|
|
77
|
+
def publish(name, data = nil, attributes = {})
|
|
78
|
+
qs_params = nil
|
|
79
|
+
qs_params = data if name.kind_of?(Enumerable) || name.kind_of?(Ably::Models::Message)
|
|
80
|
+
|
|
81
|
+
messages = build_messages(name, data, attributes) # (RSL1a, RSL1b)
|
|
82
|
+
|
|
83
|
+
if messages.sum(&:size) > (max_message_size = client.max_message_size || Ably::Rest::Client::MAX_MESSAGE_SIZE)
|
|
84
|
+
raise Ably::Exceptions::MaxMessageSizeExceeded.new("Maximum message size exceeded #{max_message_size} bytes.")
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
payload = messages.map do |message|
|
|
88
|
+
Ably::Models::Message(message.dup).tap do |msg|
|
|
89
|
+
msg.encode client.encoders, options
|
|
90
|
+
|
|
91
|
+
next if msg.client_id.nil?
|
|
92
|
+
if msg.client_id == '*'
|
|
93
|
+
raise Ably::Exceptions::IncompatibleClientId.new('Wildcard client_id is reserved and cannot be used when publishing messages')
|
|
94
|
+
end
|
|
95
|
+
unless client.auth.can_assume_client_id?(msg.client_id)
|
|
96
|
+
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}'")
|
|
97
|
+
end
|
|
98
|
+
end.as_json
|
|
99
|
+
end.tap do |payload|
|
|
100
|
+
if client.idempotent_rest_publishing
|
|
101
|
+
# We cannot mutate for idempotent publishing if one or more messages already has an ID
|
|
102
|
+
if payload.all? { |msg| !msg['id'] }
|
|
103
|
+
# Mutate the JSON to support idempotent publishing where a Message.id does not exist
|
|
104
|
+
idempotent_publish_id = SecureRandom.base64(IDEMPOTENT_LIBRARY_GENERATED_ID_LENGTH)
|
|
105
|
+
payload.each_with_index do |msg, idx|
|
|
106
|
+
msg['id'] = "#{idempotent_publish_id}:#{idx}"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
options = qs_params ? { qs_params: qs_params } : {}
|
|
113
|
+
response = client.post("#{base_path}/publish", payload.length == 1 ? payload.first : payload, options)
|
|
114
|
+
|
|
115
|
+
[201, 204].include?(response.status)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Retrieves a {Ably::Models::PaginatedResult} object, containing an array of historical {Ably::Models::Message}
|
|
119
|
+
# objects for the channel. If the channel is configured to persist messages, then messages can be retrieved from
|
|
120
|
+
# history for up to 72 hours in the past. If not, messages can only be retrieved from history for up to two minutes in the past.
|
|
121
|
+
#
|
|
122
|
+
# @spec RSL2a
|
|
123
|
+
#
|
|
124
|
+
# @param [Hash] options the options for the message history request
|
|
125
|
+
# @option options [Integer,Time] :start The time from which messages are retrieved, specified as milliseconds since the Unix epoch. RSL2b1
|
|
126
|
+
# @option options [Integer,Time] :end The time until messages are retrieved, specified as milliseconds since the Unix epoch. RSL2b1
|
|
127
|
+
# @option options [Symbol] :direction The order for which messages are returned in. Valid values are backwards which orders messages from most recent to oldest, or forwards which orders messages from oldest to most recent. The default is backwards. RSL2b2
|
|
128
|
+
# @option options [Integer] :limit An upper limit on the number of messages returned. The default is 100, and the maximum is 1000. RSL2b3
|
|
129
|
+
#
|
|
130
|
+
# @return [Ably::Models::PaginatedResult<Ably::Models::Message>] A {Ably::Models::PaginatedResult} object containing an array of {Ably::Models::Message} objects.
|
|
131
|
+
#
|
|
132
|
+
def history(options = {})
|
|
133
|
+
url = "#{base_path}/messages"
|
|
134
|
+
options = {
|
|
135
|
+
:direction => :backwards,
|
|
136
|
+
:limit => 100
|
|
137
|
+
}.merge(options)
|
|
138
|
+
|
|
139
|
+
[:start, :end].each { |option| options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
|
|
140
|
+
raise ArgumentError, ":end must be equal to or after :start" if options[:start] && options[:end] && (options[:start] > options[:end])
|
|
141
|
+
|
|
142
|
+
paginated_options = {
|
|
143
|
+
coerce_into: 'Ably::Models::Message',
|
|
144
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
response = client.get(url, options)
|
|
148
|
+
|
|
149
|
+
Ably::Models::PaginatedResult.new(response, url, client, paginated_options) do |message|
|
|
150
|
+
message.tap do |msg|
|
|
151
|
+
decode_message msg
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# A {Ably::Rest::Presence} object.
|
|
157
|
+
# @spec RSL3
|
|
158
|
+
# @return [Ably::Rest::Presence]
|
|
159
|
+
def presence
|
|
160
|
+
@presence ||= Presence.new(client, self)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# Sets the {Ably::Models::ChannelOptions} for the channel.
|
|
164
|
+
# @spec RSL7
|
|
165
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
166
|
+
# @return [Ably::Models::ChannelOptions]
|
|
167
|
+
def set_options(channel_options)
|
|
168
|
+
@options = Ably::Models::ChannelOptions(channel_options)
|
|
169
|
+
end
|
|
170
|
+
alias options= set_options
|
|
171
|
+
|
|
172
|
+
# Retrieves a {Ably::Models::ChannelDetails} object for the channel, which includes status and occupancy metrics.
|
|
173
|
+
# @spec RSL8
|
|
174
|
+
# @return [Ably::Models::ChannelDetails] A {Ably::Models::ChannelDetails} object.
|
|
175
|
+
def status
|
|
176
|
+
Ably::Models::ChannelDetails.new(client.get(base_path).body)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
private
|
|
180
|
+
|
|
181
|
+
def base_path
|
|
182
|
+
"/channels/#{URI.encode_www_form_component(name)}"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def decode_message(message)
|
|
186
|
+
message.decode client.encoders, options
|
|
187
|
+
rescue Ably::Exceptions::CipherError, Ably::Exceptions::EncoderError => e
|
|
188
|
+
client.logger.error { "Decoding Error on channel '#{name}', message event name '#{message.name}'. #{e.class.name}: #{e.message}" }
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
require 'ably/rest/channel/push_channel'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module Rest
|
|
3
|
+
class Channels
|
|
4
|
+
include Ably::Modules::ChannelsCollection
|
|
5
|
+
|
|
6
|
+
# @return [Ably::Rest::Channels]
|
|
7
|
+
def initialize(client)
|
|
8
|
+
super client, Ably::Rest::Channel
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Return a {Ably::Rest::Channel} for the given name
|
|
12
|
+
#
|
|
13
|
+
# @param name [String] The name of the channel
|
|
14
|
+
# @param channel_options [Hash] Channel options, currently reserved for Encryption options
|
|
15
|
+
#
|
|
16
|
+
# @return [Ably::Rest::Channel]
|
|
17
|
+
#
|
|
18
|
+
def get(*args)
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Return a {Ably::Rest::Channel} for the given name if it exists, else the block will be called.
|
|
23
|
+
# This method is intentionally similar to {http://ruby-doc.org/core-2.1.3/Hash.html#method-i-fetch Hash#fetch} providing a simple way to check if a channel exists or not without creating one
|
|
24
|
+
#
|
|
25
|
+
# @param name [String] The name of the channel
|
|
26
|
+
# @yield [options] (optional) if a missing_block is passed to this method and no channel exists matching the name, this block is called
|
|
27
|
+
# @yieldparam [String] name of the missing channel
|
|
28
|
+
#
|
|
29
|
+
# @return [Ably::Rest::Channel]
|
|
30
|
+
#
|
|
31
|
+
def fetch(*args)
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Destroy the {Ably::Rest::Channel} and releases the associated resources.
|
|
36
|
+
#
|
|
37
|
+
# Releasing a {Ably::Rest::Channel} is not typically necessary as a channel consumes no resources other than the memory footprint of the
|
|
38
|
+
# {Ably::Rest::Channel} object. Explicitly release channels to free up resources if required
|
|
39
|
+
#
|
|
40
|
+
# @return [void]
|
|
41
|
+
#
|
|
42
|
+
def release(*args)
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|