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,107 @@
|
|
|
1
|
+
module Ably::Models
|
|
2
|
+
class Stats
|
|
3
|
+
# StatsStruct is a basic Struct like class that allows methods to be defined
|
|
4
|
+
# on the class that will be retuned co-erced objects from the underlying hash used to
|
|
5
|
+
# initialize the object.
|
|
6
|
+
#
|
|
7
|
+
# This class provides a concise way to create classes that have fixed attributes and types
|
|
8
|
+
#
|
|
9
|
+
# @example
|
|
10
|
+
# class MessageCount < StatsStruct
|
|
11
|
+
# coerce_attributes :count, :data, into: Integer
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# @api private
|
|
15
|
+
#
|
|
16
|
+
class StatsStruct
|
|
17
|
+
class << self
|
|
18
|
+
def coerce_attributes(*attributes)
|
|
19
|
+
options = attributes.pop
|
|
20
|
+
raise ArgumentError, 'Expected attribute into: within options hash' unless options.kind_of?(Hash) && options[:into]
|
|
21
|
+
|
|
22
|
+
@type_klass = options[:into]
|
|
23
|
+
setup_attribute_methods attributes
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def type_klass
|
|
27
|
+
@type_klass
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
def setup_attribute_methods(attributes)
|
|
32
|
+
attributes.each do |attr|
|
|
33
|
+
define_method(attr) do
|
|
34
|
+
# Lazy load the co-erced value only when accessed
|
|
35
|
+
unless instance_variable_defined?("@#{attr}")
|
|
36
|
+
instance_variable_set "@#{attr}", self.class.type_klass.new(hash[attr.to_sym])
|
|
37
|
+
end
|
|
38
|
+
instance_variable_get("@#{attr}")
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
attr_reader :hash
|
|
45
|
+
|
|
46
|
+
def initialize(hash)
|
|
47
|
+
@hash = hash || {}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# IntegerDefaultZero will always return an Integer object and will default to value 0 unless truthy
|
|
52
|
+
#
|
|
53
|
+
# @api private
|
|
54
|
+
#
|
|
55
|
+
class IntegerDefaultZero
|
|
56
|
+
def self.new(value)
|
|
57
|
+
(value && value.to_i) || 0
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# MessageCount contains aggregate counts for messages and data transferred
|
|
62
|
+
#
|
|
63
|
+
# @spec TS5a, TS5b
|
|
64
|
+
#
|
|
65
|
+
class MessageCount < StatsStruct
|
|
66
|
+
coerce_attributes :count, :data, into: IntegerDefaultZero
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# RequestCount contains aggregate counts for requests made
|
|
70
|
+
#
|
|
71
|
+
# @spec TS8a, TS8b, TS8c
|
|
72
|
+
#
|
|
73
|
+
class RequestCount < StatsStruct
|
|
74
|
+
coerce_attributes :succeeded, :failed, :refused, into: IntegerDefaultZero
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# ResourceCount contains aggregate data for usage of a resource in a specific scope
|
|
78
|
+
#
|
|
79
|
+
class ResourceCount < StatsStruct
|
|
80
|
+
coerce_attributes :opened, :peak, :mean, :min, :refused, into: IntegerDefaultZero
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# ConnectionTypes contains a breakdown of summary stats data for different (TLS vs non-TLS) connection types
|
|
84
|
+
#
|
|
85
|
+
# @spec TS4a, TS4b, TS4c
|
|
86
|
+
#
|
|
87
|
+
class ConnectionTypes < StatsStruct
|
|
88
|
+
coerce_attributes :tls, :plain, :all, into: ResourceCount
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# MessageTypes contains a breakdown of summary stats data for different (message vs presence) message types
|
|
92
|
+
#
|
|
93
|
+
# @spec TS6a, TS6b, TS6c
|
|
94
|
+
#
|
|
95
|
+
class MessageTypes < StatsStruct
|
|
96
|
+
coerce_attributes :messages, :presence, :all, into: MessageCount
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# MessageTraffic contains a breakdown of summary stats data for traffic over various transport types
|
|
100
|
+
#
|
|
101
|
+
# @spec TS7a, TS7b, TS7c, TS7d
|
|
102
|
+
#
|
|
103
|
+
class MessageTraffic < StatsStruct
|
|
104
|
+
coerce_attributes :realtime, :rest, :webhook, :all, into: MessageTypes
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
module Ably::Models
|
|
2
|
+
# Convert token details argument to a {TokenDetails} object
|
|
3
|
+
#
|
|
4
|
+
# @param attributes (see #initialize)
|
|
5
|
+
#
|
|
6
|
+
# @return [TokenDetails]
|
|
7
|
+
#
|
|
8
|
+
def self.TokenDetails(attributes)
|
|
9
|
+
case attributes
|
|
10
|
+
when TokenDetails
|
|
11
|
+
return attributes
|
|
12
|
+
else
|
|
13
|
+
TokenDetails.new(attributes)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Contains an Ably Token and its associated metadata.
|
|
18
|
+
#
|
|
19
|
+
class TokenDetails
|
|
20
|
+
include Ably::Modules::ModelCommon
|
|
21
|
+
|
|
22
|
+
# Buffer in seconds before a token is considered unusable
|
|
23
|
+
# For example, if buffer is 10s, the token can no longer be used for new requests 9s before it expires
|
|
24
|
+
TOKEN_EXPIRY_BUFFER = 15
|
|
25
|
+
|
|
26
|
+
# @param attributes
|
|
27
|
+
# @option attributes [String] :token token used to authenticate requests
|
|
28
|
+
# @option attributes [String] :key_name API key name used to create this token
|
|
29
|
+
# @option attributes [Time,Integer] :issued Time the token was issued as Time or Integer in milliseconds
|
|
30
|
+
# @option attributes [Time,Integer] :expires Time the token expires as Time or Integer in milliseconds
|
|
31
|
+
# @option attributes [String] :capability JSON stringified capabilities assigned to this token
|
|
32
|
+
# @option attributes [String] :client_id client ID assigned to this token
|
|
33
|
+
#
|
|
34
|
+
def initialize(attributes = {})
|
|
35
|
+
@hash_object = IdiomaticRubyWrapper(attributes.clone)
|
|
36
|
+
|
|
37
|
+
%w(issued expires).map(&:to_sym).each do |time_attribute|
|
|
38
|
+
if self.attributes[time_attribute].kind_of?(Time)
|
|
39
|
+
self.attributes[time_attribute] = (self.attributes[time_attribute].to_f * 1000).round
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
self.attributes.freeze
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# The Ably Token itself. A typical Ably Token string appears with the form xVLyHw.A-pwh7wicf3afTfgiw4k2Ku33kcnSA7z6y8FjuYpe3QaNRTEo4.
|
|
47
|
+
#
|
|
48
|
+
# @spec TD2
|
|
49
|
+
#
|
|
50
|
+
# @return [String] Token used to authenticate requests
|
|
51
|
+
#
|
|
52
|
+
def token
|
|
53
|
+
attributes[:token]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @return [String] API key name used to create this token. An API key is made up of an API key name and secret delimited by a +:+
|
|
57
|
+
#
|
|
58
|
+
def key_name
|
|
59
|
+
attributes[:key_name]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# The timestamp at which this token was issued as milliseconds since the Unix epoch.
|
|
63
|
+
# @spec TD4
|
|
64
|
+
# @return [Time] Time the token was issued
|
|
65
|
+
def issued
|
|
66
|
+
as_time_from_epoch(attributes[:issued], granularity: :ms, allow_nil: :true)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The timestamp at which this token expires as milliseconds since the Unix epoch.
|
|
70
|
+
# @spec TD3
|
|
71
|
+
# @return [Time] Time the token expires
|
|
72
|
+
def expires
|
|
73
|
+
as_time_from_epoch(attributes[:expires], granularity: :ms, allow_nil: :true)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# The capabilities associated with this Ably Token. The capabilities value is a JSON-encoded representation of the
|
|
77
|
+
# resource paths and associated operations. Read more about capabilities in the capabilities docs.
|
|
78
|
+
# @spec TD5
|
|
79
|
+
# @return [Hash] Capabilities assigned to this token
|
|
80
|
+
def capability
|
|
81
|
+
if attributes.has_key?(:capability)
|
|
82
|
+
capability_val = attributes.fetch(:capability)
|
|
83
|
+
case capability_val
|
|
84
|
+
when Hash
|
|
85
|
+
capability_val
|
|
86
|
+
when Ably::Models::IdiomaticRubyWrapper
|
|
87
|
+
capability_val.as_json
|
|
88
|
+
else
|
|
89
|
+
JSON.parse(attributes.fetch(:capability))
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The client ID, if any, bound to this Ably Token. If a client ID is included, then the Ably Token authenticates its
|
|
95
|
+
# bearer as that client ID, and the Ably Token may only be used to perform operations on behalf of that client ID.
|
|
96
|
+
# The client is then considered to be an identified client.
|
|
97
|
+
# @spec TD6
|
|
98
|
+
# @return [String] Optional client ID assigned to this token
|
|
99
|
+
def client_id
|
|
100
|
+
attributes[:client_id]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns true if token is expired or about to expire
|
|
104
|
+
# For tokens that have not got an explicit expires attribute expired? will always return true
|
|
105
|
+
#
|
|
106
|
+
# @param attributes [Hash]
|
|
107
|
+
# @option attributes [Time] :from Sets a current time from which token expires
|
|
108
|
+
#
|
|
109
|
+
# @return [Boolean]
|
|
110
|
+
def expired?(attributes = {})
|
|
111
|
+
return false if !expires
|
|
112
|
+
|
|
113
|
+
from = attributes[:from] || Time.now
|
|
114
|
+
expires < from + TOKEN_EXPIRY_BUFFER
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# True if the TokenDetails was created from an opaque string i.e. no metadata exists for this token
|
|
118
|
+
# @return [Boolean]
|
|
119
|
+
# @api private
|
|
120
|
+
def from_token_string?
|
|
121
|
+
attributes.keys == [:token]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# @return [Hash] Access the token details Hash object ruby'fied to use symbolized keys
|
|
125
|
+
#
|
|
126
|
+
def attributes
|
|
127
|
+
@hash_object
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def to_s
|
|
131
|
+
"<TokenDetails token=#{token} client_id=#{client_id} key_name=#{key_name} issued=#{issued} expires=#{expires} capability=#{capability} expired?=#{expired?}>"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# A static factory method to create a {Ably::Models::TokenDetails} object from a deserialized {Ably::Models::TokenDetails}-like
|
|
135
|
+
# object or a JSON stringified TokenDetails object. This method is provided to minimize bugs as a result of differing
|
|
136
|
+
# types by platform for fields such as timestamp or ttl. For example, in Ruby ttl in the {Ably::Models::TokenDetails}
|
|
137
|
+
# object is exposed in seconds as that is idiomatic for the language, yet when serialized to JSON using to_json it
|
|
138
|
+
# is automatically converted to the Ably standard which is milliseconds. By using the fromJson() method when constructing
|
|
139
|
+
# a {Ably::Models::TokenDetails} object, Ably ensures that all fields are consistently serialized and deserialized across platforms.
|
|
140
|
+
#
|
|
141
|
+
# @overload from_json(json_like_object)
|
|
142
|
+
# @spec TD7
|
|
143
|
+
# @param json_like_object [Hash, String] A deserialized TokenDetails-like object or a JSON stringified TokenDetails object.
|
|
144
|
+
#
|
|
145
|
+
# @return [Ably::Models::TokenDetails] An Ably authentication token.
|
|
146
|
+
#
|
|
147
|
+
end
|
|
148
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
module Ably::Models
|
|
2
|
+
# Convert token request argument to a {TokenRequest} object
|
|
3
|
+
#
|
|
4
|
+
# @param attributes (see #initialize)
|
|
5
|
+
#
|
|
6
|
+
# @return [TokenRequest]
|
|
7
|
+
#
|
|
8
|
+
def self.TokenRequest(attributes)
|
|
9
|
+
case attributes
|
|
10
|
+
when TokenRequest
|
|
11
|
+
return attributes
|
|
12
|
+
else
|
|
13
|
+
TokenRequest.new(attributes)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Contains the properties of a request for a token to Ably.
|
|
19
|
+
# Tokens are generated using {Ably::Auth#requestToken}.
|
|
20
|
+
#
|
|
21
|
+
# Ruby {http://ruby-doc.org/core/Time.html Time} objects are supported in place of Ably ms since epoch time fields. However, if a numeric is provided
|
|
22
|
+
# it must always be expressed in milliseconds as the Ably API always uses milliseconds for time fields.
|
|
23
|
+
#
|
|
24
|
+
class TokenRequest
|
|
25
|
+
include Ably::Modules::ModelCommon
|
|
26
|
+
|
|
27
|
+
# @param attributes
|
|
28
|
+
# @option attributes [Integer] :ttl requested time to live for the token in milliseconds
|
|
29
|
+
# @option attributes [Time,Integer] :timestamp the timestamp of this request in milliseconds or as a {http://ruby-doc.org/core/Time.html Time}
|
|
30
|
+
# @option attributes [String] :key_name API key name of the key against which this request is made
|
|
31
|
+
# @option attributes [String] :capability JSON stringified capability of the token
|
|
32
|
+
# @option attributes [String] :client_id client ID to associate with this token
|
|
33
|
+
# @option attributes [String] :nonce an opaque nonce string of at least 16 characters
|
|
34
|
+
# @option attributes [String] :mac the Message Authentication Code for this request
|
|
35
|
+
#
|
|
36
|
+
def initialize(attributes = {})
|
|
37
|
+
@hash_object = IdiomaticRubyWrapper(attributes.clone)
|
|
38
|
+
if self.attributes[:timestamp].kind_of?(Time)
|
|
39
|
+
self.attributes[:timestamp] = (self.attributes[:timestamp].to_f * 1000).round
|
|
40
|
+
end
|
|
41
|
+
self.attributes.freeze
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The name of the key against which this request is made. The key name is public, whereas the key secret is private.
|
|
45
|
+
#
|
|
46
|
+
# @!attribute [r] key_name
|
|
47
|
+
#
|
|
48
|
+
# @spec TE2
|
|
49
|
+
#
|
|
50
|
+
# @return [String] API key name of the key against which this request is made. An API key is made up of an API key name and secret delimited by a +:+
|
|
51
|
+
#
|
|
52
|
+
def key_name
|
|
53
|
+
attributes.fetch(:key_name) { raise Ably::Exceptions::InvalidTokenRequest, 'Key name is missing' }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Requested time to live for the Ably Token in milliseconds. If the Ably TokenRequest is successful, the TTL of the
|
|
57
|
+
# returned Ably Token is less than or equal to this value, depending on application settings and the attributes of
|
|
58
|
+
# the issuing key. The default is 60 minutes.
|
|
59
|
+
#
|
|
60
|
+
# @!attribute [r] ttl
|
|
61
|
+
#
|
|
62
|
+
# @spec TE4
|
|
63
|
+
#
|
|
64
|
+
# @return [Integer] requested time to live for the token in seconds. If the token request is successful,
|
|
65
|
+
# the TTL of the returned token will be less than or equal to this value depending on application
|
|
66
|
+
# settings and the attributes of the issuing key.
|
|
67
|
+
# TTL when sent to Ably is in milliseconds.
|
|
68
|
+
def ttl
|
|
69
|
+
attributes.fetch(:ttl) / 1000
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Capability of the requested Ably Token. If the Ably TokenRequest is successful, the capability of the returned
|
|
73
|
+
# Ably Token will be the intersection of this capability with the capability of the issuing key. The capabilities
|
|
74
|
+
# value is a JSON-encoded representation of the resource paths and associated operations. Read more about
|
|
75
|
+
# capabilities in the capabilities docs.
|
|
76
|
+
#
|
|
77
|
+
# @!attribute [r] capability
|
|
78
|
+
#
|
|
79
|
+
# @spec TE3
|
|
80
|
+
#
|
|
81
|
+
# @return [Hash] capability of the token. If the token request is successful,
|
|
82
|
+
# the capability of the returned token will be the intersection of
|
|
83
|
+
# this capability with the capability of the issuing key.
|
|
84
|
+
def capability
|
|
85
|
+
capability_val = attributes.fetch(:capability) { raise Ably::Exceptions::InvalidTokenRequest, 'Capability is missing' }
|
|
86
|
+
|
|
87
|
+
case capability_val
|
|
88
|
+
when Hash
|
|
89
|
+
capability_val
|
|
90
|
+
when Ably::Models::IdiomaticRubyWrapper
|
|
91
|
+
capability_val.as_json
|
|
92
|
+
else
|
|
93
|
+
JSON.parse(attributes.fetch(:capability))
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# The client ID to associate with the requested Ably Token. When provided, the Ably Token may only be used to
|
|
98
|
+
# perform operations on behalf of that client ID.
|
|
99
|
+
#
|
|
100
|
+
# @!attribute [r] client_id
|
|
101
|
+
#
|
|
102
|
+
# @spec TE2
|
|
103
|
+
#
|
|
104
|
+
# @return [String] the client ID to associate with this token. The generated token
|
|
105
|
+
# may be used to authenticate as this clientId.
|
|
106
|
+
def client_id
|
|
107
|
+
attributes[:client_id]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# The timestamp of this request as milliseconds since the Unix epoch.
|
|
111
|
+
#
|
|
112
|
+
# @!attribute [r] timestamp
|
|
113
|
+
#
|
|
114
|
+
# @spec TE5
|
|
115
|
+
#
|
|
116
|
+
# @return [Time] the timestamp of this request.
|
|
117
|
+
# Timestamps, in conjunction with the nonce, are used to prevent
|
|
118
|
+
# token requests from being replayed.
|
|
119
|
+
# Timestamp when sent to Ably is in milliseconds.
|
|
120
|
+
def timestamp
|
|
121
|
+
timestamp_val = attributes.fetch(:timestamp) { raise Ably::Exceptions::InvalidTokenRequest, 'Timestamp is missing' }
|
|
122
|
+
as_time_from_epoch(timestamp_val, granularity: :ms)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# A cryptographically secure random string of at least 16 characters, used to ensure the TokenRequest cannot be reused.
|
|
126
|
+
#
|
|
127
|
+
# @!attribute [r] nonce
|
|
128
|
+
#
|
|
129
|
+
# @spec TE2
|
|
130
|
+
#
|
|
131
|
+
# @return [String] an opaque nonce string of at least 16 characters to ensure
|
|
132
|
+
# uniqueness of this request. Any subsequent request using the
|
|
133
|
+
# same nonce will be rejected.
|
|
134
|
+
def nonce
|
|
135
|
+
attributes.fetch(:nonce) { raise Ably::Exceptions::InvalidTokenRequest, 'Nonce is missing' }
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# The Message Authentication Code for this request.
|
|
139
|
+
#
|
|
140
|
+
# @!attribute [r] mac
|
|
141
|
+
#
|
|
142
|
+
# @spec TE2
|
|
143
|
+
#
|
|
144
|
+
# @return [String] the Message Authentication Code for this request. See the
|
|
145
|
+
#
|
|
146
|
+
def mac
|
|
147
|
+
attributes.fetch(:mac) { raise Ably::Exceptions::InvalidTokenRequest, 'MAC is missing' }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Requests that the token is always persisted
|
|
151
|
+
#
|
|
152
|
+
# @api private
|
|
153
|
+
#
|
|
154
|
+
def persisted
|
|
155
|
+
attributes[:persisted]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# @!attribute [r] attributes
|
|
159
|
+
#
|
|
160
|
+
# @return [Hash] the token request Hash object ruby'fied to use symbolized keys
|
|
161
|
+
#
|
|
162
|
+
def attributes
|
|
163
|
+
@hash_object
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# A static factory method to create a TokenRequest object from a deserialized TokenRequest-like object or a JSON
|
|
167
|
+
# stringified TokenRequest object. This method is provided to minimize bugs as a result of differing types by platform
|
|
168
|
+
# for fields such as timestamp or ttl. For example, in Ruby ttl in the TokenRequest object is exposed in seconds as
|
|
169
|
+
# that is idiomatic for the language, yet when serialized to JSON using to_json it is automatically converted to
|
|
170
|
+
# the Ably standard which is milliseconds. By using the fromJson() method when constructing a TokenRequest object,
|
|
171
|
+
# Ably ensures that all fields are consistently serialized and deserialized across platforms.
|
|
172
|
+
#
|
|
173
|
+
# @overload from_json(json_like_object)
|
|
174
|
+
# @spec TE6
|
|
175
|
+
# @param json_like_object [Hash, String] A deserialized TokenRequest-like object or a JSON stringified TokenRequest object to create a TokenRequest.
|
|
176
|
+
#
|
|
177
|
+
# @return [Ably::Models::TokenRequest] An Ably token request object.
|
|
178
|
+
#
|
|
179
|
+
end
|
|
180
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Ably is the base namespace for the Ably {Ably::Realtime Realtime} & {Ably::Rest Rest} client libraries.
|
|
2
|
+
#
|
|
3
|
+
# Please refer to the {file:README.md Readme} on getting started.
|
|
4
|
+
#
|
|
5
|
+
# @see file:README.md README
|
|
6
|
+
module Ably
|
|
7
|
+
# Fallback hosts to use when a connection to rest/realtime.ably.io is not possible due to
|
|
8
|
+
# network failures either at the client, between the client and Ably, within an Ably data center, or at the IO domain registrar
|
|
9
|
+
# see https://ably.com/docs/client-lib-development-guide/features/#RSC15a
|
|
10
|
+
#
|
|
11
|
+
FALLBACK_DOMAIN = 'ably-realtime.com'.freeze
|
|
12
|
+
FALLBACK_IDS = %w(a b c d e).freeze
|
|
13
|
+
|
|
14
|
+
# Default production fallbacks a.ably-realtime.com ... e.ably-realtime.com
|
|
15
|
+
FALLBACK_HOSTS = FALLBACK_IDS.map { |host| "#{host}.#{FALLBACK_DOMAIN}".freeze }.freeze
|
|
16
|
+
|
|
17
|
+
# Custom environment default fallbacks {ENV}-a-fallback.ably-realtime.com ... {ENV}-a-fallback.ably-realtime.com
|
|
18
|
+
CUSTOM_ENVIRONMENT_FALLBACKS_SUFFIXES = FALLBACK_IDS.map do |host|
|
|
19
|
+
"-#{host}-fallback.#{FALLBACK_DOMAIN}".freeze
|
|
20
|
+
end.freeze
|
|
21
|
+
|
|
22
|
+
INTERNET_CHECK = {
|
|
23
|
+
url: '//internet-up.ably-realtime.com/is-the-internet-up.txt',
|
|
24
|
+
ok_text: 'yes'
|
|
25
|
+
}.freeze
|
|
26
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
|
|
3
|
+
module Ably::Modules
|
|
4
|
+
# Provides methods to convert synchronous operations into async operations through the use of
|
|
5
|
+
# {http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine#defer-class_method EventMachine#defer}.
|
|
6
|
+
# The async_wrap method can only be called from within an EventMachine reactor, and must be thread safe.
|
|
7
|
+
#
|
|
8
|
+
# @note using this AsyncWrapper should only be used for methods that are used less frequently and typically
|
|
9
|
+
# not run with levels of concurrency due to the limited number of threads available to EventMachine by default.
|
|
10
|
+
# This module requires that the method #logger is defined.
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# class BlockingOperation
|
|
14
|
+
# include Aby::Modules::AsyncWrapper
|
|
15
|
+
#
|
|
16
|
+
# def operation(&success_callback)
|
|
17
|
+
# async_wrap(success_callback) do
|
|
18
|
+
# sleep 1
|
|
19
|
+
# 'slept'
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# blocking_object = BlockingOperation.new
|
|
25
|
+
# deferrable = blocking_object.operation do |result|
|
|
26
|
+
# puts "Done with result: #{result}"
|
|
27
|
+
# end
|
|
28
|
+
# puts "Starting"
|
|
29
|
+
#
|
|
30
|
+
# # => 'Starting'
|
|
31
|
+
# # => 'Done with result: slept'
|
|
32
|
+
#
|
|
33
|
+
module AsyncWrapper
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Will yield the provided block in a new thread and return an {Ably::Util::SafeDeferrable}
|
|
37
|
+
#
|
|
38
|
+
# @yield [Object] operation block that is run in a thread
|
|
39
|
+
#
|
|
40
|
+
# @return [Ably::Util::SafeDeferrable]
|
|
41
|
+
#
|
|
42
|
+
def async_wrap(success_callback = nil, custom_error_handling = nil)
|
|
43
|
+
raise ArgumentError, 'Block required' unless block_given?
|
|
44
|
+
|
|
45
|
+
Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
|
|
46
|
+
deferrable.callback(&success_callback) if success_callback
|
|
47
|
+
|
|
48
|
+
operation_with_exception_handling = lambda do
|
|
49
|
+
begin
|
|
50
|
+
yield
|
|
51
|
+
rescue StandardError => err
|
|
52
|
+
if custom_error_handling
|
|
53
|
+
custom_error_handling.call err, deferrable
|
|
54
|
+
else
|
|
55
|
+
logger.error { "An exception in an AsyncWrapper block was caught. #{err.class}: #{err.message}\n#{err.backtrace.join("\n")}" }
|
|
56
|
+
deferrable.fail err
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
complete_callback = lambda do |result|
|
|
62
|
+
deferrable.succeed result
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
EventMachine.defer operation_with_exception_handling, complete_callback
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Ably::Modules
|
|
2
|
+
# ChannelsCollection module provides common functionality to the Rest and Realtime Channels objects
|
|
3
|
+
# such as #get, #[], #fetch, and #release
|
|
4
|
+
module ChannelsCollection
|
|
5
|
+
include Enumerable
|
|
6
|
+
|
|
7
|
+
def initialize(client, channel_klass)
|
|
8
|
+
@client = client
|
|
9
|
+
@channel_klass = channel_klass
|
|
10
|
+
@channels = {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Return a Channel for the given name
|
|
14
|
+
#
|
|
15
|
+
# @param name [String] The name of the channel
|
|
16
|
+
# @param channel_options [Hash, Ably::Models::ChannelOptions] A hash of options or a {Ably::Models::ChannelOptions}
|
|
17
|
+
#
|
|
18
|
+
# @return [Channel]
|
|
19
|
+
#
|
|
20
|
+
def get(name, channel_options = {})
|
|
21
|
+
if channels.has_key?(name)
|
|
22
|
+
channels[name].tap do |channel|
|
|
23
|
+
if channel_options && !channel_options.empty?
|
|
24
|
+
if channel.respond_to?(:need_reattach?) && channel.need_reattach?
|
|
25
|
+
raise_implicit_options_update
|
|
26
|
+
else
|
|
27
|
+
warn_implicit_options_update
|
|
28
|
+
channel.options = channel_options
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
else
|
|
33
|
+
channels[name] ||= channel_klass.new(client, name, channel_options)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
alias_method :[], :get
|
|
37
|
+
|
|
38
|
+
# Return a Channel for the given name if it exists, else the block will be called.
|
|
39
|
+
# 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
|
|
40
|
+
#
|
|
41
|
+
# @param name [String] The name of the channel
|
|
42
|
+
#
|
|
43
|
+
# @yield [options] (optional) if a missing_block is passed to this method and no channel exists matching the name, this block is called
|
|
44
|
+
# @yieldparam [String] name of the missing channel
|
|
45
|
+
#
|
|
46
|
+
# @return [Channel]
|
|
47
|
+
#
|
|
48
|
+
def fetch(name, &missing_block)
|
|
49
|
+
channels.fetch(name, &missing_block)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Destroy the Channel and releases the associated resources.
|
|
53
|
+
#
|
|
54
|
+
# Releasing a Channel is not typically necessary as a channel consumes no resources other than the memory footprint of the
|
|
55
|
+
# Channel object. Explicitly release channels to free up resources if required
|
|
56
|
+
#
|
|
57
|
+
# @param name [String] The name of the channel
|
|
58
|
+
#
|
|
59
|
+
# @return [void]
|
|
60
|
+
#
|
|
61
|
+
def release(name)
|
|
62
|
+
channels.delete(name)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @!attribute [r] length
|
|
66
|
+
# @return [Integer] number of channels created
|
|
67
|
+
def length
|
|
68
|
+
channels.length
|
|
69
|
+
end
|
|
70
|
+
alias_method :count, :length
|
|
71
|
+
alias_method :size, :length
|
|
72
|
+
|
|
73
|
+
# Method to allow {ChannelsCollection} to be {http://ruby-doc.org/core-2.1.3/Enumerable.html Enumerable}
|
|
74
|
+
def each(&block)
|
|
75
|
+
return to_enum(:each) unless block_given?
|
|
76
|
+
channels.values.each(&block)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def raise_implicit_options_update
|
|
82
|
+
raise ArgumentError, "You are trying to indirectly update channel options which will trigger reattachment of the channel. Please use Channel#set_options directly if you wish to continue"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def warn_implicit_options_update
|
|
86
|
+
logger.warn { "Channels#get: Using this method to update channel options is deprecated and may be removed in a future version of ably-ruby. Please use Channel#setOptions instead" }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def logger
|
|
90
|
+
client.logger
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def client
|
|
94
|
+
@client
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def channel_klass
|
|
98
|
+
@channel_klass
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def channels
|
|
102
|
+
@channels
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|