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.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ably/agent.rb +8 -0
  3. data/lib/ably/auth.rb +791 -0
  4. data/lib/ably/exceptions.rb +169 -0
  5. data/lib/ably/logger.rb +119 -0
  6. data/lib/ably/models/auth_details.rb +45 -0
  7. data/lib/ably/models/channel_details.rb +69 -0
  8. data/lib/ably/models/channel_metrics.rb +107 -0
  9. data/lib/ably/models/channel_occupancy.rb +50 -0
  10. data/lib/ably/models/channel_options.rb +120 -0
  11. data/lib/ably/models/channel_state_change.rb +84 -0
  12. data/lib/ably/models/channel_status.rb +63 -0
  13. data/lib/ably/models/cipher_params.rb +137 -0
  14. data/lib/ably/models/connection_details.rb +149 -0
  15. data/lib/ably/models/connection_state_change.rb +83 -0
  16. data/lib/ably/models/delta_extras.rb +28 -0
  17. data/lib/ably/models/device_details.rb +126 -0
  18. data/lib/ably/models/device_push_details.rb +94 -0
  19. data/lib/ably/models/error_info.rb +104 -0
  20. data/lib/ably/models/http_paginated_response.rb +112 -0
  21. data/lib/ably/models/idiomatic_ruby_wrapper.rb +235 -0
  22. data/lib/ably/models/message.rb +223 -0
  23. data/lib/ably/models/message_encoders/base.rb +135 -0
  24. data/lib/ably/models/message_encoders/base64.rb +40 -0
  25. data/lib/ably/models/message_encoders/cipher.rb +84 -0
  26. data/lib/ably/models/message_encoders/json.rb +34 -0
  27. data/lib/ably/models/message_encoders/utf8.rb +26 -0
  28. data/lib/ably/models/nil_logger.rb +20 -0
  29. data/lib/ably/models/paginated_result.rb +201 -0
  30. data/lib/ably/models/presence_message.rb +244 -0
  31. data/lib/ably/models/protocol_message.rb +288 -0
  32. data/lib/ably/models/push_channel_subscription.rb +114 -0
  33. data/lib/ably/models/stats.rb +242 -0
  34. data/lib/ably/models/stats_types.rb +107 -0
  35. data/lib/ably/models/token_details.rb +148 -0
  36. data/lib/ably/models/token_request.rb +180 -0
  37. data/lib/ably/modules/ably.rb +26 -0
  38. data/lib/ably/modules/async_wrapper.rb +69 -0
  39. data/lib/ably/modules/channels_collection.rb +105 -0
  40. data/lib/ably/modules/conversions.rb +153 -0
  41. data/lib/ably/modules/encodeable.rb +111 -0
  42. data/lib/ably/modules/enum.rb +230 -0
  43. data/lib/ably/modules/event_emitter.rb +200 -0
  44. data/lib/ably/modules/event_machine_helpers.rb +26 -0
  45. data/lib/ably/modules/exception_codes.rb +128 -0
  46. data/lib/ably/modules/http_helpers.rb +41 -0
  47. data/lib/ably/modules/message_emitter.rb +78 -0
  48. data/lib/ably/modules/message_pack.rb +14 -0
  49. data/lib/ably/modules/model_common.rb +84 -0
  50. data/lib/ably/modules/safe_deferrable.rb +83 -0
  51. data/lib/ably/modules/safe_yield.rb +41 -0
  52. data/lib/ably/modules/state_emitter.rb +181 -0
  53. data/lib/ably/modules/state_machine.rb +59 -0
  54. data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  55. data/lib/ably/modules/uses_state_machine.rb +111 -0
  56. data/lib/ably/realtime/auth.rb +283 -0
  57. data/lib/ably/realtime/channel/channel_manager.rb +272 -0
  58. data/lib/ably/realtime/channel/channel_properties.rb +40 -0
  59. data/lib/ably/realtime/channel/channel_state_machine.rb +104 -0
  60. data/lib/ably/realtime/channel/publisher.rb +82 -0
  61. data/lib/ably/realtime/channel/push_channel.rb +69 -0
  62. data/lib/ably/realtime/channel.rb +440 -0
  63. data/lib/ably/realtime/channels.rb +71 -0
  64. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +225 -0
  65. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +87 -0
  66. data/lib/ably/realtime/client.rb +363 -0
  67. data/lib/ably/realtime/connection/connection_manager.rb +594 -0
  68. data/lib/ably/realtime/connection/connection_state_machine.rb +144 -0
  69. data/lib/ably/realtime/connection/websocket_transport.rb +287 -0
  70. data/lib/ably/realtime/connection.rb +738 -0
  71. data/lib/ably/realtime/models/nil_channel.rb +30 -0
  72. data/lib/ably/realtime/presence/members_map.rb +395 -0
  73. data/lib/ably/realtime/presence/presence_manager.rb +78 -0
  74. data/lib/ably/realtime/presence/presence_state_machine.rb +57 -0
  75. data/lib/ably/realtime/presence.rb +502 -0
  76. data/lib/ably/realtime/push/admin.rb +75 -0
  77. data/lib/ably/realtime/push/channel_subscriptions.rb +108 -0
  78. data/lib/ably/realtime/push/device_registrations.rb +105 -0
  79. data/lib/ably/realtime/push.rb +25 -0
  80. data/lib/ably/realtime/recovery_key_context.rb +36 -0
  81. data/lib/ably/realtime.rb +60 -0
  82. data/lib/ably/rest/channel/push_channel.rb +59 -0
  83. data/lib/ably/rest/channel.rb +194 -0
  84. data/lib/ably/rest/channels.rb +47 -0
  85. data/lib/ably/rest/client.rb +727 -0
  86. data/lib/ably/rest/middleware/encoder.rb +49 -0
  87. data/lib/ably/rest/middleware/exceptions.rb +53 -0
  88. data/lib/ably/rest/middleware/external_exceptions.rb +24 -0
  89. data/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +22 -0
  90. data/lib/ably/rest/middleware/logger.rb +58 -0
  91. data/lib/ably/rest/middleware/parse_json.rb +27 -0
  92. data/lib/ably/rest/middleware/parse_message_pack.rb +43 -0
  93. data/lib/ably/rest/presence.rb +113 -0
  94. data/lib/ably/rest/push/admin.rb +58 -0
  95. data/lib/ably/rest/push/channel_subscriptions.rb +121 -0
  96. data/lib/ably/rest/push/device_registrations.rb +114 -0
  97. data/lib/ably/rest/push.rb +25 -0
  98. data/lib/ably/rest.rb +40 -0
  99. data/lib/ably/util/ably_extensions.rb +29 -0
  100. data/lib/ably/util/crypto.rb +134 -0
  101. data/lib/ably/util/pub_sub.rb +45 -0
  102. data/lib/ably/util/safe_deferrable.rb +44 -0
  103. data/lib/ably/version.rb +7 -0
  104. data/lib/ably.rb +16 -0
  105. metadata +497 -0
@@ -0,0 +1,169 @@
1
+ require 'ably/modules/exception_codes'
2
+
3
+ module Ably
4
+ module Exceptions
5
+ TOKEN_EXPIRED_CODE = 40140..40149
6
+
7
+ # Base Ably exception class that contains status and code values used by Ably
8
+ # Refer to https://github.com/ably/ably-common/blob/main/protocol/errors.json
9
+ #
10
+ # @!attribute [r] message
11
+ # @return [String] Error message from Ably
12
+ # @!attribute [r] status
13
+ # @return [String] HTTP status code of error
14
+ # @!attribute [r] code
15
+ # @return [String] Ably specific error code
16
+ class BaseAblyException < StandardError
17
+ attr_reader :status, :code, :request_id
18
+
19
+ def initialize(message, status = nil, code = nil, base_exception = nil, options = {})
20
+ super message
21
+
22
+ @base_exception = base_exception
23
+ @status = status
24
+ @status ||= base_exception.status if base_exception && base_exception.respond_to?(:status)
25
+ @status ||= options[:fallback_status]
26
+ @code = code
27
+ @code ||= base_exception.code if base_exception && base_exception.respond_to?(:code)
28
+ @code ||= options[:fallback_code]
29
+ @request_id ||= options[:request_id]
30
+ end
31
+
32
+ def to_s
33
+ message = [super]
34
+ if status || code
35
+ additional_info = []
36
+ additional_info << "code: #{code}" if code
37
+ additional_info << "http status: #{status}" if status
38
+ additional_info << "base exception: #{@base_exception.class}" if @base_exception
39
+ additional_info << "request_id: #{request_id}" if request_id
40
+ message << "(#{additional_info.join(', ')})"
41
+ message << "-> see https://help.ably.io/error/#{code} for help" if code
42
+ end
43
+ message.join(' ')
44
+ end
45
+
46
+ def as_json(*args)
47
+ {
48
+ message: "#{self.class}: #{message}",
49
+ status: @status,
50
+ code: @code
51
+ }.delete_if { |key, val| val.nil? }
52
+ end
53
+ end
54
+
55
+ # Maximum frame size exceeded TO3l9
56
+ class MaxFrameSizeExceeded < BaseAblyException; end
57
+
58
+ # Maximum message size exceeded TO3l8
59
+ class MaxMessageSizeExceeded < BaseAblyException; end
60
+
61
+ # An invalid request was received by Ably
62
+ class InvalidRequest < BaseAblyException; end
63
+
64
+ class InvalidCredentials < BaseAblyException; end
65
+
66
+ # Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided
67
+ class UnauthorizedRequest < BaseAblyException; end
68
+
69
+ # The request was a valid request, but Ably is refusing to respond to it
70
+ class ForbiddenRequest < BaseAblyException; end
71
+
72
+ # The requested resource could not be found but may be available again in the future
73
+ class ResourceMissing < BaseAblyException; end
74
+
75
+ # Ably Protocol message received that is invalid
76
+ class ProtocolError < BaseAblyException; end
77
+
78
+ # Encryption or Decryption failure
79
+ class CipherError < BaseAblyException; end
80
+
81
+ # Encoding or decoding failure
82
+ class EncoderError < BaseAblyException; end
83
+
84
+ # Connection error from Realtime or REST service
85
+ class ConnectionError < BaseAblyException
86
+ def initialize(message, status = nil, code = nil, base_exception = nil, options = {})
87
+ super message, status, code, base_exception, options
88
+ end
89
+
90
+ def to_s
91
+ message = [super]
92
+ if @base_exception
93
+ message << "#{@base_exception}"
94
+ if @base_exception.respond_to?(:message) && @base_exception.message.match(/certificate verify failed/i)
95
+ message << "See https://goo.gl/eKvfcR to resolve this issue."
96
+ end
97
+ end
98
+ message.join(' < ')
99
+ end
100
+ end
101
+
102
+ # Connection Timeout accessing Realtime or REST service
103
+ class ConnectionTimeout < ConnectionError; end
104
+
105
+ # Transport closed unexpectedly
106
+ class TransportClosed < ConnectionError; end
107
+
108
+ # Connection closed unexpectedly
109
+ class ConnectionClosed < ConnectionError; end
110
+
111
+ # Connection suspended
112
+ class ConnectionSuspended < ConnectionError; end
113
+
114
+ # Connection failed
115
+ class ConnectionFailed < ConnectionError; end
116
+
117
+ class AuthenticationFailed < ConnectionError; end
118
+
119
+ # Invalid State Change error on a {https://github.com/gocardless/statesman Statesman State Machine}
120
+ class InvalidStateChange < BaseAblyException; end
121
+
122
+ class InvalidState < BaseAblyException; end
123
+
124
+ # A generic Ably exception taht supports a status & code.
125
+ # See https://github.com/ably/ably-common/blob/main/protocol/errors.json for a list of Ably errors
126
+ class Standard < BaseAblyException; end
127
+
128
+ # The HTTP request has returned a 500 error
129
+ class ServerError < BaseAblyException; end
130
+
131
+ # PaginatedResult cannot retrieve the page
132
+ class PageMissing < BaseAblyException; end
133
+
134
+ # The expected response from the server was invalid
135
+ class InvalidResponseBody < BaseAblyException; end
136
+
137
+ # The request cannot be performed because it is insecure
138
+ class InsecureRequest < BaseAblyException; end
139
+
140
+ # The token request could not be created
141
+ class TokenRequestFailed < BaseAblyException; end
142
+
143
+ # The token has expired, 40140..40149
144
+ class TokenExpired < BaseAblyException; end
145
+
146
+ # The message could not be delivered to the server
147
+ class MessageDeliveryFailed < BaseAblyException; end
148
+
149
+ # The client has been configured to not queue messages i.e. only publish down an active connection
150
+ class MessageQueueingDisabled < BaseAblyException; end
151
+
152
+ # The data payload type is not supported
153
+ class UnsupportedDataType < BaseAblyException; end
154
+
155
+ # When a channel is detached / failed, certain operations are not permitted such as publishing messages
156
+ class ChannelInactive < BaseAblyException; end
157
+
158
+ class IncompatibleClientId < BaseAblyException
159
+ def initialize(messages, status = 400, code = Ably::Exceptions::Codes::INVALID_CLIENT_ID, *args)
160
+ super(message, status, code, *args)
161
+ end
162
+ end
163
+
164
+ # Token request has missing or invalid attributes
165
+ class InvalidTokenRequest < BaseAblyException; end
166
+
167
+ class PushNotificationsNotSupported < BaseAblyException; end
168
+ end
169
+ end
@@ -0,0 +1,119 @@
1
+ module Ably
2
+ # Logger unifies logging for #debug, #info, #warn, #error, and #fatal messages.
3
+ # A new Ably client uses this Logger and sets the appropriate log level.
4
+ # A custom Logger can be configured when instantiating the client, refer to the {Ably::Rest::Client} and {Ably::Realtime::Client} documentation
5
+ #
6
+ class Logger
7
+ extend Forwardable
8
+
9
+ # @param client [Ably::Rest::Client,Ably::Realtime::Client] Rest or Realtime Ably client
10
+ # @param log_level [Integer] {http://www.ruby-doc.org/stdlib-3.1.1/libdoc/logger/rdoc/Logger.html Ruby Logger} log level
11
+ # @param custom_logger [nil,Object] A custom logger can optionally be used instead of the,
12
+ # however it must provide a {http://www.ruby-doc.org/stdlib-3.1.1/libdoc/logger/rdoc/Logger.html Ruby Logger} compatible interface.
13
+ #
14
+ def initialize(client, log_level, custom_logger = nil)
15
+ @client = client
16
+ @custom_logger = custom_logger
17
+ @logger = custom_logger || default_logger
18
+ @log_level = log_level
19
+
20
+ ensure_logger_interface_is_valid
21
+
22
+ @logger.level = log_level
23
+
24
+ @log_mutex = Mutex.new
25
+ end
26
+
27
+ # The logger used by this class, defaults to {http://www.ruby-doc.org/stdlib-3.1.1/libdoc/logger/rdoc/Logger.html Ruby Logger}
28
+ # @return {Object,Logger}
29
+ attr_reader :logger
30
+
31
+ # If a custom logger is being used with this Logger, this property is not nil
32
+ # @return {nil,Object}
33
+ attr_reader :custom_logger
34
+
35
+ # The log level ranging from DEBUG to FATAL, refer to http://www.ruby-doc.org/stdlib-3.1.1/libdoc/logger/rdoc/Logger.html
36
+ # @return {Integer}
37
+ attr_reader :log_level
38
+
39
+ # Catch exceptiosn in blocks passed to the logger, log the error and continue
40
+ %w(fatal error warn info debug).each do |method_name|
41
+ define_method(method_name) do |*args, &block|
42
+ begin
43
+ log_mutex.synchronize do
44
+ logger.public_send(method_name, *args, &block)
45
+ end
46
+ rescue StandardError => e
47
+ logger.error "Logger: Failed to log #{method_name} block - #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+ attr_reader :log_mutex
54
+
55
+ def client
56
+ @client
57
+ end
58
+
59
+ def color(color_value, string)
60
+ "\033[#{color_value}m#{string}\033[0m"
61
+ end
62
+
63
+ def red(string)
64
+ color(31, string)
65
+ end
66
+
67
+ def magenta(string)
68
+ color(35, string)
69
+ end
70
+
71
+ def cyan(string)
72
+ color(36, string)
73
+ end
74
+
75
+ def connection_id
76
+ if realtime?
77
+ if client.connection.id
78
+ "[#{cyan(client.connection.id)}] "
79
+ else
80
+ "[ #{cyan('--')} ] "
81
+ end
82
+ end
83
+ end
84
+
85
+ def realtime?
86
+ defined?(Ably::Realtime::Client) && client.kind_of?(Ably::Realtime::Client)
87
+ end
88
+
89
+ def default_logger
90
+ ::Logger.new(STDOUT).tap do |logger|
91
+ logger.formatter = lambda do |severity, datetime, progname, msg|
92
+ severity = ::Logger::SEV_LABEL.index(severity) if severity.kind_of?(String)
93
+
94
+ formatted_date = if severity == ::Logger::DEBUG
95
+ datetime.strftime("%H:%M:%S.%L")
96
+ else
97
+ datetime.strftime("%Y-%m-%d %H:%M:%S.%L")
98
+ end
99
+
100
+ severity_label = if severity <= ::Logger::INFO
101
+ magenta(::Logger::SEV_LABEL[severity])
102
+ else
103
+ red(::Logger::SEV_LABEL[severity])
104
+ end
105
+
106
+ "#{formatted_date} #{severity_label} #{connection_id}#{msg}\n"
107
+ end
108
+ end
109
+ end
110
+
111
+ def ensure_logger_interface_is_valid
112
+ %w(fatal error warn info debug level level=).each do |method|
113
+ unless logger.respond_to?(method)
114
+ raise ArgumentError, "The custom Logger's interface does not provide the method '#{method}'"
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,45 @@
1
+ module Ably::Models
2
+ # Convert auth details attributes to a {AuthDetails} object
3
+ #
4
+ # @param attributes (see #initialize)
5
+ #
6
+ # @return [AuthDetails]
7
+ #
8
+ def self.AuthDetails(attributes)
9
+ case attributes
10
+ when AuthDetails
11
+ return attributes
12
+ else
13
+ AuthDetails.new(attributes || {})
14
+ end
15
+ end
16
+
17
+ # AuthDetails are included in an +AUTH+ {Ably::Models::ProtocolMessage#auth} attribute
18
+ # to provide the realtime service with new token authentication details following a re-auth workflow
19
+ #
20
+ class AuthDetails
21
+ include Ably::Modules::ModelCommon
22
+
23
+ # @param attributes [Hash]
24
+ # @option attributes [String] :access_token token string
25
+ #
26
+ def initialize(attributes = {})
27
+ @hash_object = IdiomaticRubyWrapper(attributes.clone)
28
+ self.attributes.freeze
29
+ end
30
+
31
+ # The authentication token string.
32
+ #
33
+ # @spec AD2
34
+ #
35
+ # @return [String]
36
+ #
37
+ def access_token
38
+ attributes[:access_token]
39
+ end
40
+
41
+ def attributes
42
+ @hash_object
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,69 @@
1
+ module Ably::Models
2
+ # Convert token details argument to a {ChannelDetails} object
3
+ #
4
+ # @param attributes (see #initialize)
5
+ #
6
+ # @return [ChannelDetails]
7
+ #
8
+ def self.ChannelDetails(attributes)
9
+ case attributes
10
+ when ChannelDetails
11
+ return attributes
12
+ else
13
+ ChannelDetails.new(attributes)
14
+ end
15
+ end
16
+
17
+ # Contains the details of a {Ably::Models::Rest::Channel} or {Ably::Models::Realtime::Channel} object
18
+ # such as its ID and {Ably::Models::ChannelStatus}.
19
+ #
20
+ class ChannelDetails
21
+ extend Ably::Modules::Enum
22
+ extend Forwardable
23
+ include Ably::Modules::ModelCommon
24
+
25
+ # The attributes of ChannelDetails
26
+ #
27
+ # @spec CHD2
28
+ #
29
+ attr_reader :attributes
30
+
31
+ alias_method :to_h, :attributes
32
+
33
+ # Initialize a new ChannelDetails
34
+ #
35
+ def initialize(attrs)
36
+ @attributes = IdiomaticRubyWrapper(attrs.clone)
37
+ end
38
+
39
+ # The identifier of the channel
40
+ #
41
+ # @spec CHD2a
42
+ #
43
+ # @return [String]
44
+ #
45
+ def channel_id
46
+ attributes[:channel_id]
47
+ end
48
+
49
+ # The identifier of the channel
50
+ #
51
+ # @spec CHD2a
52
+ #
53
+ # @return [String]
54
+ #
55
+ def name
56
+ attributes[:name]
57
+ end
58
+
59
+ # A {Ably::Models::ChannelStatus} object.
60
+ #
61
+ # @spec CHD2b
62
+ #
63
+ # @return [Ably::Models::ChannelStatus, nil]
64
+ #
65
+ def status
66
+ Ably::Models::ChannelStatus(attributes[:status])
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,107 @@
1
+ module Ably::Models
2
+ # Convert token details argument to a {ChannelMetrics} object
3
+ #
4
+ # @param attributes (see #initialize)
5
+ #
6
+ # @return [ChannelMetrics]
7
+ #
8
+ def self.ChannelMetrics(attributes)
9
+ case attributes
10
+ when ChannelMetrics
11
+ return attributes
12
+ else
13
+ ChannelMetrics.new(attributes)
14
+ end
15
+ end
16
+
17
+ # Contains the metrics associated with a {Ably::Models::Rest::Channel} or {Ably::Models::Realtime::Channel},
18
+ # such as the number of publishers, subscribers and connections it has.
19
+ #
20
+ # @spec CHM1
21
+ #
22
+ class ChannelMetrics
23
+ extend Ably::Modules::Enum
24
+ extend Forwardable
25
+ include Ably::Modules::ModelCommon
26
+
27
+ # The attributes of ChannelMetrics (CHM2)
28
+ #
29
+ attr_reader :attributes
30
+
31
+ alias_method :to_h, :attributes
32
+
33
+ # Initialize a new ChannelMetrics
34
+ #
35
+ def initialize(attrs)
36
+ @attributes = IdiomaticRubyWrapper(attrs.clone)
37
+ end
38
+
39
+ # The number of realtime connections attached to the channel.
40
+ #
41
+ # @spec CHM2a
42
+ #
43
+ # @return [Integer]
44
+ #
45
+ def connections
46
+ attributes[:connections]
47
+ end
48
+
49
+ # The number of realtime connections attached to the channel with permission to enter the presence set, regardless
50
+ # of whether or not they have entered it. This requires the presence capability and for a client to not have specified
51
+ # a {Ably::Models::ChannelOptions::MODES} flag that excludes {Ably::Models::ChannelOptions::MODES}#PRESENCE.
52
+ #
53
+ # @spec CHM2b
54
+ #
55
+ # @return [Integer]
56
+ #
57
+ def presence_connections
58
+ attributes[:presence_connections]
59
+ end
60
+
61
+ # The number of members in the presence set of the channel.
62
+ #
63
+ # @spec CHM2c
64
+ #
65
+ # @return [Integer]
66
+ #
67
+ def presence_members
68
+ attributes[:presence_members]
69
+ end
70
+
71
+ # The number of realtime attachments receiving presence messages on the channel. This requires the subscribe capability
72
+ # and for a client to not have specified a {Ably::Models::ChannelOptions::MODES} flag that excludes
73
+ # {Ably::Models::ChannelOptions::MODES}#PRESENCE_SUBSCRIBE.
74
+ #
75
+ # @spec CHM2d
76
+ #
77
+ # @return [Integer]
78
+ #
79
+ def presence_subscribers
80
+ attributes[:presence_subscribers]
81
+ end
82
+
83
+ # The number of realtime attachments permitted to publish messages to the channel. This requires the publish
84
+ # capability and for a client to not have specified a {Ably::Models::ChannelOptions::MODES} flag that excludes
85
+ # {Ably::Models::ChannelOptions::MODES}#PUBLISH.
86
+ #
87
+ # @spec CHM2e
88
+ #
89
+ # @return [Integer]
90
+ #
91
+ def publishers
92
+ attributes[:publishers]
93
+ end
94
+
95
+ # The number of realtime attachments receiving messages on the channel. This requires the subscribe capability and
96
+ # for a client to not have specified a {Ably::Models::ChannelOptions::MODES} flag that excludes
97
+ # {Ably::Models::ChannelOptions::MODES}#SUBSCRIBE.
98
+ #
99
+ # @spec CHM2f
100
+ #
101
+ # @return [Integer]
102
+ #
103
+ def subscribers
104
+ attributes[:subscribers]
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,50 @@
1
+ module Ably::Models
2
+ # Convert token details argument to a {ChannelOccupancy} object
3
+ #
4
+ # @param attributes (see #initialize)
5
+ #
6
+ # @return [ChannelOccupancy]
7
+ #
8
+ def self.ChannelOccupancy(attributes)
9
+ case attributes
10
+ when ChannelOccupancy
11
+ return attributes
12
+ else
13
+ ChannelOccupancy.new(attributes)
14
+ end
15
+ end
16
+
17
+ # Contains the metrics of a {Ably::Models::Rest::Channel} or {Ably::Models::Realtime::Channel} object.
18
+ #
19
+ # @spec CHO1
20
+ #
21
+ class ChannelOccupancy
22
+ extend Ably::Modules::Enum
23
+ extend Forwardable
24
+ include Ably::Modules::ModelCommon
25
+
26
+ # The attributes of ChannelOccupancy.
27
+ #
28
+ # @spec CH02
29
+ #
30
+ attr_reader :attributes
31
+
32
+ alias_method :to_h, :attributes
33
+
34
+ # Initialize a new ChannelOccupancy
35
+ #
36
+ def initialize(attrs)
37
+ @attributes = IdiomaticRubyWrapper(attrs.clone)
38
+ end
39
+
40
+ # A {Ably::Models::ChannelMetrics} object.
41
+ #
42
+ # @spec CHO2a
43
+ #
44
+ # @return [Ably::Models::ChannelMetrics, nil]
45
+ #
46
+ def metrics
47
+ Ably::Models::ChannelMetrics(attributes[:metrics])
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,120 @@
1
+ module Ably::Models
2
+ # Convert token details argument to a {ChannelOptions} object
3
+ #
4
+ # @param attributes (see #initialize)
5
+ #
6
+ # @return [ChannelOptions]
7
+ #
8
+ def self.ChannelOptions(attributes)
9
+ case attributes
10
+ when ChannelOptions
11
+ return attributes
12
+ else
13
+ ChannelOptions.new(attributes)
14
+ end
15
+ end
16
+
17
+ # Represents options of a channel
18
+ class ChannelOptions
19
+ extend Ably::Modules::Enum
20
+ extend Forwardable
21
+ include Ably::Modules::ModelCommon
22
+
23
+ # Describes the possible flags used to configure client capabilities, using {Ably::Models::ChannelOptions::MODES}.
24
+ #
25
+ # PRESENCE The client can enter the presence set.
26
+ # PUBLISH The client can publish messages.
27
+ # SUBSCRIBE The client can subscribe to messages.
28
+ # PRESENCE_SUBSCRIBE The client can receive presence messages.
29
+ #
30
+ # @spec TB2d
31
+ #
32
+ MODES = ruby_enum('MODES',
33
+ presence: 0,
34
+ publish: 1,
35
+ subscribe: 2,
36
+ presence_subscribe: 3
37
+ )
38
+
39
+ attr_reader :attributes
40
+
41
+ alias_method :to_h, :attributes
42
+
43
+ def_delegators :attributes, :fetch, :size, :empty?
44
+ # Initialize a new ChannelOptions
45
+ #
46
+ # @spec TB3
47
+ #
48
+ # @option params [Hash] (TB2c) params (for realtime client libraries only) a of key/value pairs
49
+ # @option modes [Hash] modes (for realtime client libraries only) an array of ChannelMode
50
+ # @option cipher [Hash,Ably::Models::CipherParams] :cipher A hash of options or a {Ably::Models::CipherParams} to configure the encryption. *:key* is required, all other options are optional.
51
+ #
52
+ def initialize(attrs)
53
+ @attributes = IdiomaticRubyWrapper(attrs.clone)
54
+
55
+ attributes[:modes] = modes.to_a.map { |mode| Ably::Models::ChannelOptions::MODES[mode] } if modes
56
+ attributes[:cipher] = Ably::Models::CipherParams(cipher) if cipher
57
+ attributes.clone
58
+ end
59
+
60
+ # Requests encryption for this channel when not null, and specifies encryption-related parameters (such as algorithm,
61
+ # chaining mode, key length and key). See an example.
62
+ #
63
+ # @spec RSL5a, TB2b
64
+ #
65
+ # @return [CipherParams]
66
+ #
67
+ def cipher
68
+ attributes[:cipher]
69
+ end
70
+
71
+ # Channel Parameters that configure the behavior of the channel.
72
+ #
73
+ # @spec TB2c
74
+ #
75
+ # @return [Hash]
76
+ #
77
+ def params
78
+ attributes[:params].to_h
79
+ end
80
+
81
+ # An array of {Ably:Models:ChannelOptions::MODES} objects.
82
+ #
83
+ # @spec TB2d
84
+ #
85
+ # @return [Array<ChannelOptions::MODES>]
86
+ #
87
+ def modes
88
+ attributes[:modes]
89
+ end
90
+
91
+ # Converts modes to a bitfield that coresponds to ProtocolMessage#flags
92
+ #
93
+ # @return [Integer]
94
+ #
95
+ def modes_to_flags
96
+ modes.map { |mode| Ably::Models::ProtocolMessage::ATTACH_FLAGS_MAPPING[mode.to_sym] }.reduce(:|)
97
+ end
98
+
99
+ # @return [Hash]
100
+ # @api private
101
+ def set_params(hash)
102
+ attributes[:params] = hash
103
+ end
104
+
105
+ # Sets modes from ProtocolMessage#flags
106
+ #
107
+ # @return [Array<ChannelOptions::MODES>]
108
+ # @api private
109
+ def set_modes_from_flags(flags)
110
+ return unless flags
111
+
112
+ message_modes = MODES.select do |mode|
113
+ flag = Ably::Models::ProtocolMessage::ATTACH_FLAGS_MAPPING[mode.to_sym]
114
+ flags & flag == flag
115
+ end
116
+
117
+ attributes[:modes] = message_modes.map { |mode| Ably::Models::ChannelOptions::MODES[mode] }
118
+ end
119
+ end
120
+ end