From 429867b2f5ffb7e1ad8d2ccff86cee17f2257a2d Mon Sep 17 00:00:00 2001 From: Matthew O'Riordan Date: Tue, 3 Jan 2017 16:04:09 +0100 Subject: [PATCH] spec: Remove old redundant version file --- .../versions/features-0-8.textile | 1359 ----------------- 1 file changed, 1359 deletions(-) delete mode 100644 content/client-lib-development-guide/versions/features-0-8.textile diff --git a/content/client-lib-development-guide/versions/features-0-8.textile b/content/client-lib-development-guide/versions/features-0-8.textile deleted file mode 100644 index 5c3c90efc1..0000000000 --- a/content/client-lib-development-guide/versions/features-0-8.textile +++ /dev/null @@ -1,1359 +0,0 @@ ---- -title: Features spec v0.8 -index: 1 -anchor_specs: true -jump_to: - General: - - Test guidelines - REST client library: - - RestClient - - Auth#rest-auth - - Channels#rest-channels - - Channel#rest-channel - - Presence#rest-presence - Realtime client library: - - RealtimeClient - - Connection#realtime-connection - - Channels#realtime-channels - - Channel#realtime-channel - - Presence#realtime-presence - - EventEmitter#eventemitter - - State conditions and operations#state-conditions-and-operations - Types: - - Data types#types - - Options#options - Interface Definition: - - Complete API IDL#idl ---- - -p(tip). This version is deprecated. "View the latest version of this spec":/client-lib-development-guide/features - -A detailed "test specification":https://github.com/ably/ably-ruby/blob/master/SPEC.md that applies to all client libraries is generated from the Ably Ruby client library's acceptance and test suites. Whilst every official Ably client library has test coverage, the amount of test coverage varies, and as such our recommendation is to refer to the official "test specification":https://github.com/ably/ably-ruby/blob/master/SPEC.md when developing a client library. - -However, we have found the "test specification":https://github.com/ably/ably-ruby/blob/master/SPEC.md can be difficult as a reference because of both its breadth and the fact that it applies to the Ruby client library which may be unfamiliar as a language for a lot of developers. - -As a result, this document outlines the complete feature set of both the REST and Realtime client libraries. It is expected that every client library developer refers to this document to ensure that their client library provides the same API and features as the existing Ably client libraries. In addition to this, it is essential that there is test coverage over all of the features described below. - -We recommend you use the "IDL (Interface Definition Language)":#idl and the "Ably Java library":https://github.com/ably/ably-java as a reference when reviewing how the API has been implemented. - -h2(#test-guidelines). Test guidelines - -* @(G1)@ Every test should be executed using all supported protocols (i.e. JSON and "MessagePack":http://msgpack.org/ if supported). This includes both sending & receiving data -* @(G2)@ All tests by default are run against a special Ably sandbox environment. This environment allows apps to be provisioned without any authentication that can then be used for client library testing. Bear in mind that all apps created in the sandbox environment are automatically deleted after 60 minutes and have low limits to prevent abuse. Apps are configured by sending a @POST@ request to @https://sandbox-rest.ably.io/apps@ with a JSON body that specifies the keys and their associated capabilities, channel namespace rules and any presence fixture data that is required; see "ably-common test-app-setup.json":https://github.com/ably/ably-common/blob/master/test-resources/test-app-setup.json. See the "Java test setup":https://github.com/ably/ably-java/blob/master/test/io/ably/test/rest/RestSetup.java. Presence fixture data is necessary for the REST library presence tests as there is no way to register presence on a channel in the REST library -* @(G3)@ Testing statistics can be tricky due to timing issues and slow test suites as a result of sending requests to generate statistics. As such, we provide a special stats endpoint in our sandbox environment that allows stats to be injected into our metrics system so that stats tests can make predictable assertions. To create stats you must send an authenticated @POST@ request to the stats JSON to @https://sandbox-rest.ably.io/stats@ with the stats data you wish to create. See the "Javascript stats fixture":https://github.com/ably/ably-js/blob/4e65d4e13eb8750a375b9511e4dd059092c0e481/spec/rest/stats.test.js#L8-L51 and "setup helper":https://github.com/ably/ably-js/blob/4e65d4e13eb8750a375b9511e4dd059092c0e481/spec/common/modules/testapp_manager.js#L158-L182 as an example -* @(G4)@ All REST requests and WebSocket connections to Ably must include the current API version @0.8@. Should any new API version with breaking changes be released, the client library will continue to use the API version explicitly requested - -h2(#rest). REST client library - -Client library developers - clone our "REST client library Google Doc spec":https://docs.google.com/spreadsheets/d/1vBzr9N-0ovtVZ0mxTeg7zLMEhcgj5lB9ivmkOcO-9J0/edit?usp=sharing when developing a REST client library to help you keep track of feature compliance and test coverage. - -h3(#restclient). RestClient - -* @(RSC1)@ The constructor accepts either an API key, a token string, or a set of "@ClientOptions@":#options. If invalid arguments are provided such as a no API key, no token and no means to create a token, then this will result in an error -* @(RSC2)@ The logger by default outputs to @STDOUT@ (or other logging medium as appropriate to the platform) and the log level is set to warning -* @(RSC3)@ The log level can be changed -* @(RSC4)@ A custom logger can be provided in the constructor -* @(RSC5)@ @RestClient#auth@ attribute provides access to the @Auth@ object that was instanced with the @ClientOptions@ provided in the @RestClient@ constructor -* @(RSC6)@ @RestClient#stats@ function: -** @(RSC6a)@ Returns a @PaginatedResult@ page containing @Stats@ objects in the @PaginatedResult#items@ attribute returned from the stats request -** @(RSC6b)@ Supports the following params: -*** @(RSC6b1)@ @start@ and @end@ are timestamp fields represented as milliseconds since epoch, or where suitable to the language, Date or Time objects. @start@ must be equal to or less than @end@ and is unaffected by the request direction -*** @(RSC6b2)@ @direction@ backwards or forwards; if omitted the direction defaults to the REST API default (backwards) -*** @(RSC6b3)@ @limit@ supports up to 1,000 items; if omitted the limit defaults to the REST API default (100) -*** @(RSC6b4)@ @unit@ is the period for which the stats will be aggregated by, values supported are @minute@, @hour@, @day@ or @month@; if omitted the unit defaults to the REST API default (@minute@) -* @(RSC16)@ @RestClient#time@ function sends a get request to @rest.ably.io/time@ and returns the server time in milliseconds since epoch or as a Date/Time object where suitable -* @(RSC7)@ Sends REST requests over HTTP and HTTPS to the REST end-point @rest.ably.io@ -** @(RSC7a)@ The header @X-Ably-Version: 0.8@ must be included in all REST requests to the Ably end-point -* @(RSC18)@ If @ClientOptions#tls@ is true, then all communication is over HTTPS. If false, all communication is over HTTP however "Basic Auth":https://en.wikipedia.org/wiki/Basic_access_authentication over HTTP will result in an error as private keys cannot be submitted over an insecure connection. See @Auth@ below -* @(RSC8)@ Supports two protocols: -** @(RSC8a)@ "MessagePack":http://msgpack.org/ binary protocol (this is the default for environments having a suitable level or support for binary data) -** @(RSC8b)@ JSON text protocol (used when @useBinaryProtocol@ option is false) -* @(RSC9)@ Uses @Auth@ to establish what authentication scheme to use, how to authenticate, and automatic issuing of tokens when necessary -* @(RSC10)@ If a REST request responds with a token error (401 HTTP status code and an Ably error value @40140 <= @code < 40150@), then the Auth class is responsible for reissuing a token and the request should be reattempted, see "RSC14c":#RSC14c and "RSC14d":#RSC14d -* @(RSC11)@ Requests are sent to the default endpoint @rest.ably.io@. However, if the @restHost@ option is set, the client will send requests to the specified host. If @environment@ option is configured and is not "production", the environment name is prefixed to the default host endpoint and the @restHost@ is set accordingly. For example, if the @environment@ is set to sandbox, then the @restHost@ endpoint will become @sandbox-rest.ably.io@ -* @(RSC12)@ REST endpoint host is configurable in the Client constructor with the option @restHost@ -* @(RSC13)@ The client library must use the connection and request timeouts specified in the @ClientOptions@, falling back to the defaults described in @ClientOptions@ below -* @(RSC14)@ Authentication -** @(RSC14a)@ Supports basic authentication when an API key is provided with the @key@ option. The API key follows the format @"KEY_NAME:KEY_SECRET"@ so when authenticating using "Basic Auth":https://en.wikipedia.org/wiki/Basic_access_authentication, the key name can be used as the username and the key secret as the password -** @(RSC14b)@ Uses token authentication whenever the criteria of "RSA4":#RSA4 are met -** @(RSC14c)@ When a @token@ or @tokenDetails@ is used to instance the library, and no means to renew the token is provided (either an API key, @authCallback@ or @authUrl@), if the server responds with a token error (401 HTTP status code and an Ably error value @40140 <= @code < 40150@), then the client library should indicate an error and not retry the request -** @(RSC14d)@ When the client does have a means to renew the token automatically, and the token has expired or the server has responded with a token error (@statusCode@ value of 401 and error @code@ value in the range @40140 <= @code < 40150@), then the client should automatically make a single attempt to reissue the token and resend the request using the new token. If the token creation failed or the subsequent request with the new token failed due to a token error, then the request should result in an error -* @(RSC15)@ Host Fallback -** @(RSC15b)@ The fallback behavior described below only applies when the default @rest.ably.io@ endpoint is being used and has not been overriden, see "RSC11":#RSC11. If host fallback is not supported, failing HTTP requests that would have "qualified for a retry against a fallback host (see RSC15d)":#RSC15d, will instead result in an error immediately -** @(RSC15e)@ By default, every new HTTP request is first attempted to the primary host @rest.ably.io@, which, through DNS, is automatically routed to the client's closest data center. The client library must always prefer the default endpoint (closest data center), even if a previous request to that endpoint has failed -** @(RSC15a)@ In the case of an error necessitating use of an alternative host (see "RSC15d":#RSC15d), try fallback hosts in random order, continuing to try further hosts if "qualifying errors":#RSC15d occur, failing when all have been tried or the configured @httpMaxRetryCount@ has been reached (see "@TO3l5@":#TO3l5). This ensures that a client library is able to work around routing or other problems for the user's closest data center. For example, if a @POST@ request to @rest.ably.io@ fails because the default endpoint is unreachable or unserviceable, then the @POST@ request should be retried again against the fallback hosts in attempt to find an alternate healthy data center to service the request. The five fallback hosts are @[a-e].ably-realtime.com@. -** @(RSC15d)@ Errors that necessitate use of an alternative host include: host unresolvable or unreachable, request timeout, or a response but with an applicable HTTP status code in the range @500 <= code <= 504@. Resending requests that have failed for other failure conditions will not fix the problem and will simply increase the load on other data-centers unnecessarily -* @(RSC17)@ When instancing the library, if a @clientId@ attribute is set in @ClientOptions@, then the @Auth#clientId@ attribute will contain the provided @clientId@ - -h3(#rest-auth). Auth - -* @(RSA1)@ "Basic Auth":https://en.wikipedia.org/wiki/Basic_access_authentication connects over HTTPS by default. Any attempt to use Basic Auth over HTTP will result in an error -* @(RSA11)@ When using Basic Auth, the API key is Base64 encoded and included in an @Authorization@ header, as specified in "RFC7235":https://tools.ietf.org/html/rfc7235 -* @(RSA2)@ "Basic Auth":https://en.wikipedia.org/wiki/Basic_access_authentication is the default authentication scheme if an API key exists -* @(RSA3)@ Token Auth: -** @(RSA3a)@ Can be used over HTTP or HTTPs -** @(RSA3b)@ For REST requests, the token string is Base64 encoded and used in the @Authorization: Bearer@ header -** @(RSA3c)@ For Realtime connections, the querystring param @accessToken@ is appended to the URL endpoint -* @(RSA4)@ Token Auth is used if @useTokenAuth@ is set to true, or if @useTokenAuth@ is unspecified and any one of the following conditions are met: a @clientId@ is specified; @authUrl@ or @authCallback@ is provided; an explicit @token@ or @TokenDetails@ is provided -* @(RSA14)@ If Token Auth is selected, yet a token is not provided and there is no means to generate a token, then this will result in an error. For example, if only the option @useTokenAuth@ is specified, and a @key@ is not provided, then the client library is unable to authenticate or issue a token -* @(RSA15)@ If Token Auth is selected and @clientId@ has been set in the @ClientOptions@ when the library was instanced: -** @(RSA15a)@ Any @clientId@ provided in @ClientOptions@ must match any non wildcard (@'*'@) @clientId@ value in @TokenDetails@ or @connectionDetails@ of the @CONNECTED@ @ProtocolMessage@, where applicable -** @(RSA15b)@ If the @clientId@ from @TokenDetails@ or @connectionDetails@ contains only a wildcard string @'*'@, then the client is permitted to be either unidentified (i.e. anonymous without a @clientId@) or identified by providing a @clientId@ when communicating with Ably -** @(RSA15c)@ Following an auth request which uses a @TokenDetails@ or @TokenRequest@ object that contains an incompatible @clientId@, the library should in the case of Realtime change the connection state to @FAILED@ and emit an error, and in the case of REST result in an appropriate error response -* @(RSA5)@ TTL for new tokens is specified in milliseconds (REST API default is 1 hour, see "TK2a":#TK2a) -* @(RSA6)@ The @capability@ for new tokens is JSON stringified (REST API default is allow all @{"*":["*"]}@, see "TK2b":#TK2b) -* @(RSA7)@ @clientId@ and authenticated clients: -** @(RSA7a)@ If a @clientId@ is provided in the @ClientOptions@, or is present in the current authentication token, then the client is considered to be identified (it has a @clientId@ that is implicit in all operations). Note that an authentication token @clientId@ wildcard value of @'*'@ is the exception where the client is unidentified and any @clientId@ is permitted in operations with Ably. The following applies to identified clients: -*** @(RSA7a1)@ All operations (such as message publishing or presence) will have an implicit @clientId@. The Ably service automatically updates the @clientId@ attribute (when empty) for all @Message@ and @PresenceMessage@ messages received from that identified client, and any messages then published from the Ably service will have the @clientId@ attribute populated. It is therefore expected that Ably client libraries do not explicitly set the @clientId@ field on messages published when @clientId@ is implicit in the connection or authentication scheme -*** @(RSA7a2)@ If @clientId@ is provided in @ClientOptions@, and an API key is provided along with no other means to generate a token, the client library will authenticate with Ably and obtain a token using the provided @clientId@ ensuring the token is restricted to operations for that @clientId@ -*** @(RSA7a4)@ When a @clientId@ value is provided in both @ClientOptions#clientId@ and @ClientOptions#defaultTokenParams@, the @ClientOptions#clientId@ takes precendence and is used for all Auth operations -** @(RSA12)@ @Auth#clientId@ attribute is @null@ when: -*** @(RSA12a)@ The @clientId@ attribute of a @TokenRequest@ or @TokenDetails@ used for authentication is @null@, or @ConnectionDetails#clientId@ is @null@ following a connection to Ably. In this case, the @null@ value indicates that a @clientId@ identity may not be assumed by this client i.e. the client is anonymous for all operations -*** @(RSA12b)@ The client was instanced without assigning a value for @ClientOptions#clientId@ (@null@), and the client has not yet authenticated or connected to Ably. In this case, the @null@ value indicates that the client has not yet been able to confirm its identity, and therefore may change and become identified following later authentication or establishment of a connection with Ably -** @(RSA7b)@ @Auth#clientId@ is not @null@ when: -*** @(RSA7b1)@ A @clientId@ is provided in the @ClientOptions@. @clientId@ should be a string -*** @(RSA7b2)@ Token authentication is being used, and the @TokenRequest@ or @TokenDetails@ object, used for authentication, has a @clientId@ value that is not @null@ -*** @(RSA7b3)@ Following a realtime connection being established, if the @CONNECTED@ @ProtocolMessages@ contains a @clientId@ that is not @null@. @clientId@ is an attribute of @ProtocolMessage#connectionDetails@ within a @CONNECTED@ @ProtocolMessage@ -*** @(RSA7b4)@ When a wildcard string @'*'@ is present in the @TokenRequest@, @TokenDetails@, or @ProtocolMessage#connectionDetails@ object, then the client does not have an identity but is allowed to assume an identity when performing operations with Ably. As such, @Auth#clientId@ should contain the string value @'*'@ indicating that the current client is allowed to perform operations on behalf of any @clientId@ -** @(RSA7c)@ A @clientId@ provided in the @ClientOptions@ when instancing the library must be either @null@ or a string, and cannot contain only a wildcard @'*'@ string value as that client ID value is reserved -* @(RSA8)@ @Auth#requestToken@ function: -** @(RSA8e)@ Method signature is @requestToken(TokenParams, AuthOptions)@. @TokenParams@ and @AuthOptions@ are optional. When @TokenParams@ or @AuthOptions@ are provided, the values of each attribute are not merged with the configured client library defaults, but instead replace all corresponding values, even when @null@. If the object arguments are omitted, the client library configured defaults are used -** @(RSA8a)@ Implicitly creates a @TokenRequest@ if required, and requests a token from Ably if required. Returns a @TokenDetails@ object -** @(RSA8b)@ Supports all @TokenParams@ in the function arguments, which override defaults for @Client@ @Auth@ -** @(RSA8c)@ When @authUrl@ option is set, it will query the provided URL to obtain a @TokenRequest@ or the token itself (either a token string or a @TokenDetails@). The query is performed using the given URL using the HTTP method in @authMethod@, headers (from @authHeaders@) and supplementary params (from @authParams@). The token retrieved is assumed by the library to be a token string if the response has @Content-Type@ @"text/plain"@, or taken to be a @TokenRequest@ or @TokenDetails@ object if the response has @Content-Type@ @"application/json"@. @authMethod@ can be either @GET@ or @POST@, or if not specified, will default to @GET@. It can be quite difficult to add test coverage for these scenarios - as such, we have developed a simple echo server that can be used in your tests, see the "ably-js authUrl echo tests":https://github.com/ably/ably-js/commit/e77b2c6c197bc71f3d27084fe54524724a00bc92 -*** @(RSA8c1)@ @TokenParams@ and any configured @authParams@ and @authHeaders@ are always sent to the @authUrl@ as follows: -**** @(RSA8c1a)@ When the @authMethod@ is @GET@ or unspecified, the @TokenParams@ and @authParams@ are merged and appened to the URL as query string params, and the @authHeaders@ are sent as HTTP headers -**** @(RSA8c1b)@ When the @authMethod@ is @POST@, the @TokenParams@ and @authParams@ are merged and sent form-encoded in the body of the @POST@ request, and the @authHeaders@ are sent as HTTP headers -*** @(RSA8c2)@ @TokenParams@ take precedence over any configured @authParams@ when a name conflict occurs -*** @(RSA8c3)@ Specifying @authParams@ or @authHeaders@ as part of @AuthOptions@ replaces any configured @authParams@ or @authHeaders@ specified in @ClientOptions@ respectively. As the provided key/value pairs are not merged with the @ClientOptions@ configured key/vaue pairs, this enables a developer to delete @authParams@ or @authHeaders@ where necessary by providing an entire new set of key/value pairs -** @(RSA8d)@ When @authCallback@ option is set, it will invoke the callback, passing in the @TokenParams@, and expects either a token string, a @TokenDetails@ object or a @TokenRequest@ object to be returned, which will in turn be used to request a token from Ably -** @(RSA8f)@ A test should exist for the following: -*** @(RSA8f1)@ Request a token with a @null@ value @clientId@, authenticate a client with the token, publish a message without an explicit @clientId@, and ensure the message published does not have a @clientId@. Check that @Auth#clientId@ is @null@ -*** @(RSA8f2)@ Request a token with a @null@ value @clientId@, authenticate a client with the token, publish a message with an explicit @clientId@ value, and ensure that the message is rejected -*** @(RSA8f3)@ Request a token with a wildcard @'*'@ value @clientId@, authenticate a client with the token, publish a message without an explicit @clientId@, and ensure the message published does not have a @clientId@. Check that @Auth#clientId@ is a string with value @'*'@ -*** @(RSA8f4)@ Request a token with a wildcard @'*'@ value @clientId@, authenticate a client with the token, publish a message with an explicit @clientId@ value, and ensure that the message published has the provided @clientId@ -* @(RSA9)@ @Auth#createTokenRequest@ function: -** @(RSA9h)@ Method signature is @createTokenRequest(TokenParams, AuthOptions)@. @TokenParams@ and @AuthOptions@ are optional.When @TokenParams@ or @AuthOptions@ are provided, the values of each attribute are not merged with the configured client library defaults, but instead replace all corresponding values, even when @null@. If the object arguments are omitted, the client library configured defaults are used -** @(RSA9a)@ Returns a signed @TokenRequest@ object that can be used to obtain a token from Ably. This is useful for servers that can create a @TokenRequest@ signed with the API key without communicating with Ably directly. The @TokenRequest@ can then be passed to a designated client that is then responsible for communicating with Ably and requesting a token for authentication from that @TokenRequest@ -** @(RSA9b)@ Supports all @AuthOptions@ -** @(RSA9c)@ Generates a unique 16+ character @nonce@ if none is provided; the nonce is used to protect against replay attacks -** @(RSA9d)@ Generates a @timestamp@ from current time if not provided, will retrieve the server time if @queryTime@ is true -** @(RSA9e)@ TTL is optional and specified in milliseconds -** @(RSA9f)@ Capability JSON text can be provided that specifies the rights of the token in terms of the channel(s) authorised and the permitted operations on each -** @(RSA9g)@ A valid HMAC is created using the key secret to sign the @TokenRequest@ so that it can be used by any client to request a token without having or exchanging any secrets -** @(RSA9i)@ Adheres to all requirements in @RSA8@ relating to @TokenParams@ -* @(RSA10)@ @Auth#authorise@ function: -** @(RSA10a)@ Instructs the library to create a token if needed and uses Token Auth for all future requests -** @(RSA10j)@ Method signature is @authorise(TokenParams, AuthOptions)@. @TokenParams@ and @AuthOptions@ are optional. When the arguments are present, even if empty, the @TokenParams@ and @AuthOptions@ supersede any previously client library configured @TokenParams@ and @AuthOptions@. For example, if a client is initialised with @TokenParams#ttl@ configured with a custom value, and a @TokenParams@ object is passed in as an argument to @#authorise@ with a @null@ value for @ttl@, then the @ttl@ used for every subsequent authorization will be @null@. See "@RSA10d@":#RSA10d for an exception -** @(RSA10b)@ Supports all @AuthOptions@ and @TokenParams@ in the function arguments -** @(RSA10c)@ Will not create a new token unless no previous token exists or current token has expired. Please note that a buffer of 15s for token expiry is recommended to avoid race conditions where the token is valid at the time of the request, but invalid when it reaches the server. Therefore, we recommend that a token is considered expired 15s before the time field `expires` -** @(RSA10d)@ If the @AuthOption@ argument's @force@ attribute is true, it will force @Auth#authorise@ to issue a new token even if an existing token exists. A special case convenience exists for @AuthOption@ stating that if all its attributes are @null@ apart from @force@, then when passed to @authorise@ as an argument, the previously configured authentication options will remain intact. This behavior takes precedence over "@RSA10j@":#RSA10j -** @(RSA10k)@ If the @AuthOption@ argument's @queryTime@ attribute is true, it will obtain the server time once and persist the offset from the local clock. All future token requests generated directly or indirectly via a call to authorise will not obtain the server time, but instead use the local clock offset to calculate the server time. A client MAY discard the cached local clock offset in situations in which it may have been invalidated, such as if there is a local change to the date, time, or timezone, of the client device -** @(RSA10e)@ Adheres to the implementation of @requestToken@ when issuing new tokens -** @(RSA10f)@ Returns a @TokenDetails@ object that contains the token string + token metadata -** @(RSA10g)@ Stores the @AuthOptions@ and @TokenParams@ arguments as defaults for subsequent authorisations with the exception of the attributes @TokenParams#timestamp@, @AuthOptions#queryTime@ and @AuthOptions#force@ -** @(RSA10h)@ Will use the value from @Auth#clientId@ by default, if not @null@ -** @(RSA10i)@ Adheres to all requirements in @RSA8@ relating to @TokenParams@, @authCallback@ and @authUrl@ - -h3(#rest-channels). Channels - -* @(RSN1)@ @Channels@ is a collection of @Channel@ objects accessible through @Rest#channels@ -* @(RSN2)@ Methods should exist to check if a channel exists or iterate through the existing channels -* @(RSN3)@ @Channels#get@ function: -** @(RSN3a)@ Creates a new @Channel@ object for the specified channel if none exists, or returns the existing channel. @ChannelOptions@ can be specified when instancing a new @Channel@ -** @(RSN3b)@ If options are provided, the options are set on the @Channel@ -** @(RSN3c)@ Accessing an existing @Channel@ with options in the form @Channels#get(channel, options)@ will update the options on the channel and then return the existing @Channel@ object -* @(RSN4)@ @Channels#release@ function: -** @(RSN4a)@ Releases the channel resource i.e. it's deleted and can then be garbage collected - -h3(#rest-channel). Channel - -* @(RSL1)@ @Channels#publish@ function: -** @(RSL1a)@ Expects either an array of @Message@ objects or a @name@ string and @data@ payload -** @(RSL1b)@ When @name@ and @data@ is provided, a single message is published to Ably -** @(RSL1c)@ When an array of @Message@ objects is provided, a single request is made to Ably. When publishing multiple messages, this approach is more efficient. However, a yet to be implemented feature should limit the total number of messages bundled in a single POST based on the default max request size, and would reject the publish and indicate an error if any single message exceeds that limit -** @(RSL1d)@ Indicates an error if the message was not successfully published to Ably -** @(RSL1e)@ Allows @name@ and or @data@ to be @null@. If any of the values are @null@, then key is not sent to Ably i.e. a payload with a @null@ value for @data@ would be sent as follows @{ "name": "click" }@ -** @(RSL1f)@ Unidentified clients using "Basic Auth":https://en.wikipedia.org/wiki/Basic_access_authentication (i.e. any @clientId@ is permitted as no @clientId@ specified): -*** @(RSL1f1)@ When a @Message@ with a @clientId@ value is published, Ably will accept and publish that message with the provided @clientId@. A test should assert via the history API that the @clientId@ of the published @Message@ is populated -** @(RSL1g)@ Identified clients with a @clientId@ (as a result of either an explicitly configured @clientId@ in @ClientOptions@, or implicitly through Token Auth): -*** @(RSL1g1)@ When publishing a @Message@ with the @clientId@ attribute set to @null@: -**** @(RSL1g1a)@ It is unnecessary for the client to set the @clientId@ of the @Message@ before publishing -**** @(RSL1g1b)@ Ably will assign the identified @clientId@ upon receiving the @Message@. A test should assert via the history API that the @clientId@ value is the identified @clientId@ for the @Message@ when received -*** @(RSL1g2)@ When publishing a @Message@ with the @clientId@ attribute value set to the identified client's @clientId@, Ably will accept the message and publish it. A test should assert that the @clientId@ value is populated for the @Message@ when received -*** @(RSL1g3)@ When publishing a @Message@ with a different @clientId@ attribute value to the identified client's @clientId@, the client library should reject the message, and indicate an error. The connection and channel remain available for further operations -*** @(RSL1g4)@ When publishing a message with an explicit @clientId@ that is incompatible with the identified client's @clientId@ (either inferred or explicitly configured in the token or @ClientOptions@), the library will reject the message immediately and indicate an error -** @(RSL1h)@ Where the library language permits, the @Channel#publish(name, data)@ method should provide an optional argument that allows the @clientId@ value to be specified such as @Channel#publish('event', 'data', { clientId: 'John' })@ -* @(RSL2)@ @Channel#history@ function: -** @(RSL2a)@ Returns a @PaginatedResult@ page containing the first page of messages in the @PaginatedResult#items@ attribute returned from the history request -** @(RSL2b)@ Supports the following params: -*** @(RSL2b1)@ @start@ and @end@ are timestamp fields represented as milliseconds since epoch, or where suitable to the language, Time objects. @start@ must be equal to or less than @end@ and is unaffected by the request direction -*** @(RSL2b2)@ @direction@ backwards or forwards; if omitted the direction defaults to the REST API default (backwards) -*** @(RSL2b3)@ @limit@ supports up to 1,000 items; if omitted the direction defaults to the REST API default (100) -* @(RSL3)@ @Channel#presence@ attribute returns a @Presence@ object for this channel -* @(RSL4)@ Message encoding -** @(RSL4a)@ Payloads must be binary, strings, or objects capable of JSON representation, or can be empty (omitted). Any other data type should not be permitted and result in an error -** @(RSL4b)@ If a message is encoded, the @encoding@ attribute represents the encoding(s) applied in right to left format i.e. "utf-8/base64" indicates that the original payload has "utf-8" encoding and has subsequently been encoded in Base64 format -** @(RSL4c)@ When using MessagePack Message encoding -*** @(RSL4c1)@ a binary Message payload is encoded as MessagePack binary type -*** @(RSL4c2)@ a string Message payload is encoded as MessagePack string type -*** @(RSL4c3)@ a JSON Message payload is stringified either as a JSON Object or Array and encoded as MessagePack string type and the @encoding@ attribute is set to "json" -*** @(RSL4c4)@ All messages received will deliver payloads in the format they were sent in i.e. binary, string, or a structured type containing the parsed JSON -** @(RSL4d)@ When using JSON Message encoding -*** @(RSL4d1)@ a binary Message payload is encoded as Base64 and represented as a JSON string the @encoding@ attribute is set to "base64" -*** @(RSL4d2)@ a string Message payload is represented as a JSON string -*** @(RSL4d3)@ a JSON Message payload is stringified either as a JSON Object or Array and represented as a JSON string and the @encoding@ attribute is set to "json" -*** @(RSL4d4)@ All messages received will be decoded based on the @encoding@ field and deliver payloads in the format they were sent in i.e. binary, string, or a structured type containing the parsed JSON -* @(RSL5)@ Message payload encryption -** @(RSL5a)@ When a @Channel@ is instanced with a (non-null) @cipher@ channelOption, message payloads will be automatically encrypted when sent to Ably and decrypted when received on this channel, using the @cipher@ configuration -** @(RSL5b)@ AES 256 and 128 CBC encryption must be supported -** @(RSL5c)@ Tests must exist that encrypt and decrypt the following fixture data for "AES 128":https://github.com/ably/ably-common/blob/master/test-resources/crypto-data-128.json and "AES 256":https://github.com/ably/ably-common/blob/master/test-resources/crypto-data-256.json to ensure the client library encryption is compatible across libraries -* @(RSL6)@ Message decoding -** @(RSL6a)@ All messages received will be decoded automatically based on the @encoding@ field and the payloads will be converted into the format they were originally sent using i.e. binary, string, or JSON -** @(RSL6b)@ If, for example, incompatible encryption details are provided or invalid Base64 is detected in the message payload, an error message will be sent to the logger, but the message will still be delivered with last successful decoding and the @encoding@ field. For example, if a message had a decoding of "utf-8/cipher+aes-128-cbc/base64", and the payload was successfully Base64 decoded but the payload could not be encrypted because the @CipherParam@ details were not configured, the message would be delivered with a binary payload and an @encoding@ with the value "utf-8/cipher+aes-128-cbc" - -h3(#rest-presence). Presence -* @(RSP1)@ Presence object is associated with a single channel and is accessible through @Channel#presence@ -* @(RSP2)@ There is no way to register a member as present on a channel via the REST API -* @(RSP3)@ @Presence#get@ function: -** @(RSP3a)@ Returns a @PaginatedResult@ page containing the first page of members present in the @PaginatedResult#items@ attribute returned from the presence request. Each member is represented as a @PresenceMessage@. Supports the following params: -*** @(RSP3a1)@ @limit@ supports up to 1,000 items; if unspecified it defaults to the REST API default (100) -*** @(RSP3a2)@ @clientId@ filters members by the provided @clientId@ -*** @(RSP3a3)@ @connectionId@ filters members by the provided @connectionId@ -* @(RSP4)@ @Presence#history@ function: -** @(RSP4a)@ Returns a @PaginatedResult@ page containing the first page of messages in the @PaginatedResult#items@ attribute returned from the presence request -** @(RSP4b)@ Supports the following params: -*** @(RSP4b1)@ @start@ and @end@ are timestamp fields represented as milliseconds since epoch, or where appropriate to the language, Date/Time objects. @start@ must be equal to or less than @end@ and is unaffected by the request direction -*** @(RSP4b2)@ @direction@ backwards or forwards; if unspecified defaults to the REST API default (backwards) -*** @(RSP4b3)@ @limit@ supports up to 1,000 items; if unspecified defaults to the REST API default (100) -* @(RSP5)@ Presence Messages retrieved are decoded in the same way that messages are decoded - -h3(#rest-encryption). Encryption -* @(RSE1)@ @Crypto::getDefaultParams@ function: -** @(RSE1a)@ Returns a complete @CipherParams@ instance, using the default values for any field not supplied -** @(RSE1b)@ Takes a hashmap (or language equivalent) consisting of any subset of @CipherParams@ fields that includes a @key@ -** @(RSE1c)@ The @key@ must be either a binary (e.g. a byte array, depending on the language), or a base64-encoded string. If the key is a string, the function should base64-decode it into a binary. Since the conversion to base64 is not under Ably control, this should be done leniently -- in particular, it should work with base64url (RFC 4648 s.5, which uses @-@ and @_@ instead of @+@ and @/@) as well as base64 (RFC 4648 s.4) -** @(RSE1d)@ Calculates a @keyLength@ from the key (its size in bits). -** @(RSE1e)@ Checks that the provided options are valid and self-consistent as best it can, raises an exception if not. At a minimum, this should include checking the calculated @keyLength@ is a valid key length for the encryption algorithm (for example, 128 or 256 for @AES@) -* @(RSE2)@ @Crypto::generateRandomKey@ function -** @(RSE2a)@ Takes an optional @keyLength@ parameter, which is the length in bits of the key to be generated. If unspecified, this is equal to the default @keyLength@ of the default algorithm: for @AES@, 256 bits. -** @(RSE2b)@ Returns (or calls back with, if the language cryptographic randomness primitives are blocking or async) the key as a binary (e.g. a byte array, depending on the language) - -h2(#realtime). Realtime client library features - -The Ably Realtime client libraries establish and maintain a persistent connection to Ably and provide methods to publish and subscribe to messages over a low latency realtime connection. - -The Realtime library is a super-set of the REST library and as such all Realtime libraries provide the functionality available in the REST library in addition to Realtime-specific features. - -The threading and/or asynchronous model for each realtime library will vary by language and it is therefore up to the developer to decide on the best approach for each given client library. For example, Node.js and Ruby (EventMachine) use a similar callback single threaded evented approach that ensures all public methods are non-blocking. Java and .NET use a threaded model whereby the @Connection@ runs in its own thread. Go makes extensive use of goroutines and channels. - -h3(#realtimeclient). RealtimeClient - -* @(RTC1)@ Supports all the same @ClientOptions@ as the @RestClient@ in addition to: -** @(RTC1a)@ @echoMessages@ boolean is true by default. If false, it prevents messages originating from this connection being echoed back on the same connection -** @(RTC1b)@ @autoConnect@ boolean is true by default. If true, as soon as the client library is instanced, it will connect to Ably. If false, the client library will wait for an explicit @Connection#connect@ to be called before connecting -** @(RTC1c)@ @recover@ string, when set, will attempt to recover the connection state of a previous connection -** @(RTC1d)@ @realtimeHost@ string, when set, will modify the realtime endpoint host used by this client library -** @(RTC1e)@ @environment@ string, when set, will modify both the REST and realtime endpoint hosts by prefixing the environment to the default endpoint host with a hypen delimiter. For example, a @RealtimeClient@ with an @environment@ of "sandbox", would use "sandbox-rest.ably.io" as the @restHost@ and @sandbox-realtime.ably.io@ as the @realtimeHost@ -* @(RTC2)@ @RealtimeClient#connection@ attribute provides access to the underlying @Connection@ object -* @(RTC3)@ @RealtimeClient#channels@ attribute provides access to the underlying @Channels@ object -* @(RTC4)@ @RealtimeClient#auth@ attribute provides access to the @Auth@ object that was instanced with the @ClientOptions@ provided in the @RealtimeClient@ constructor -** @(RTC4a)@ Unlike the stateless REST client library, the @Auth#clientId@ is populated when the connection is established. The @CONNECTED@ @ProtocolMessage@ contains the confirmed @clientId@ for this connected client i.e. the client is considered identified. See "@RSA7b@":#RSA7b and "@RSA12@":#RSA12 for futher info -* @(RTC5)@ @RealtimeClient#stats@ function: -** @(RTC5a)@ Proxy to @RestClient#stats@ presented with an async or threaded interface as appropriate -** @(RTC5b)@ Accepts all the same params as @RestClient#stats@ and provides all the same functionality -* @(RTC6)@ @RealtimeClient#time@ function: -** @(RTC6a)@ Proxy to @RestClient#time@ presented with an async or threaded interface as appropriate -* @(RTC7)@ The client library must use the configured timeouts specified in the @ClientOptions@, falling back to the "client library defaults":#defaults and defaults described in @ClientOptions@ below -* @(RTC8)@ Authentication token changes for the current connection are possible when the client is in the @CONNECTED@, @CONNECTING@ or @DISCONNECTED@ states. If @auth.authorise@ is called with @AuthOptions#force@ set to @true@ and the state is @CONNECTED@, @CONNECTING@, or @DISCONNECTED@, the client will obtain a new token, disconnect the current transport and resume the connection (see "@RTN15c@":#RTN15c for details on resume). A test should exist that performs an upgrade of capabilities without any message loss during the upgrade process. A test should also exist for a token change that fails due to an incompatible token, which should result in the connection entering the @FAILED@ state - -h3(#realtime-connection). Connection - -* @(RTN1)@ @Connection@ connects to the Ably service using a websocket connection. The "ably-js library":https://github.ably.io/ably/ably-js supports additional transports such as Comet and XHR streaming; however non-browser client libraries typically use only a websocket transport -* @(RTN2)@ The default host used for realtime websocket connections is @realtime.ably.io@, and the following query string params should be used when opening a new connection: -** @(RTN2a)@ @format@ should be @msgpack@ (default) or @json@ -** @(RTN2b)@ @echo@ should be @true@ by default; @false@ will prevent messages published by the client being echoed back -** @(RTN2d)@ @clientId@ contains the provided @clientId@ option of @ClientOptions@, unless @clientId@ is @null@ -** @(RTN2e)@ Depending on the authentication scheme, either @accessToken@ contains the token string, or @key@ contains the API key -** @(RTN2f)@ API version param @v@ should be @0.8@ -* @(RTN3)@ If connection option @autoConnect@ is true, a connection is initiated immediately; otherwise a connection is only initiated following an explicit call to @connect()@ -* @(RTN4)@ EventEmitter and states: -** @(RTN4a)@ Implements @EventEmitter@ and emits events for state changes @INITIALIZED@, @CONNECTING@, @CONNECTED@, @DISCONNECTED@, @SUSPENDED@, @CLOSING@, @CLOSED@, @FAILED@ -** @(RTN4b)@ A new connection will emit the following events in order when connecting: @CONNECTING@, then @CONNECTED@ -** @(RTN4c)@ A connection will emit the following events when closing the connection: @CLOSING@, then @CLOSED@ -** @(RTN4d)@ @Connection#state@ attribute is the current state of the connection -** @(RTN4e)@ A @ConnectionStateChange@ object is emitted as the first argument for every connection state change -** @(RTN4f)@ Additionally, a @ConnectionStateChange@ can be emitted that contains a @reason@ which contains an @ErrorInfo@ object with details of the error that has occurred for the @Connection@ -* @(RTN5)@ A test should exist that instances many (50+) clients simultaneously and performs a few basic operations such as attaching to a channel, publishing a message, and expecting all of those messages to arrive on all clients to ensure that there are no concurrency issues with the client library -* @(RTN6)@ A @Connection@ is successful and considered @CONNECTED@ once the websocket connection is open and the intial @CONNECTED@ @ProtocolMessage@ has been received -* @(RTN19)@ If the @CONNECTED@ @ProtocolMessage@ contains a @connectionDetails@ property, the attributes within @ConnectionDetails@ will be used as the defaults for this client library, overriding any configured options at the time the @CONNECTED@ @ProtocolMessage@ is received -* @(RTN7)@ @ACK@ and @NACK@: -** @(RTN7a)@ All @ProtocolMessage@ @Presence@ and @Message@ objects sent to Ably expect either an @ACK@ or @NACK@ from Ably to confirm successful receipt and acceptance or failure respectively -** @(RTN7b)@ Every @ProtocolMessage@ sent must contain a unique serially incrementing @msgSerial@ integer value starting at zero. The @msgSerial@ along with the @count@ for incoming @ACK@ and @NACK@ @ProtocolMessages@ indicates which messages succeeded or failed to be delivered -** @(RTN7c)@ If a connection enters the @CLOSED@ or @FAILED@ state, or if the connection state is lost, and a @ACK@ or @NACK@ has not yet been received for a message, the client should consider the delivery of those messages as failed -* @(RTN8)@ @Connection#id@ attribute: -** @(RTN8a)@ Is @null@ until connected -** @(RTN8b)@ Is a unique string provided by Ably. You should have a test to ensure multiple connected clients have unique connection IDs -* @(RTN9)@ @Connection#key@ attribute: -** @(RTN9a)@ Is @null@ until connected -** @(RTN9b)@ Is a unique private connection key provided by Ably that is used to reconnect and retain connection state following an unexpected disconnection. You should have a test to ensure multiple connected clients have unique connection keys -* @(RTN10)@ @Connection#serial@ attribute: -** @(RTN10a)@ Is set to -1 once @CONNECTED@ -** @(RTN10b)@ Is always 0 when the first message has been sent and an @ACK@ has been received confirming receipt of the message. The @serial@ is updated whenever a @ProtocolMessage@ is received that contains a @connectionSerial@ value. A test should exist that checks that the serial number is not updated when a message is sent, but then increments by one when the @ACK@ is received -** @(RTN10c)@ The last known @ProtocolMessage@ @connectionSerial@ is used when restoring connection state -* @(RTN11)@ @Connection#connect@ function: -** @(RTN11a)@ Explicitly connects to the Ably service if not already connected -** @(RTN11b)@ If the state is @CLOSING@, the client should make a new connection with a new transport instance and remove all references to the old one. In particular, it should make sure that, when the @CLOSED@ @ProtocolMessage@ arrives for the old connection, it doesn't affect the new one. -** @(RTN11c)@ If the state is @DISCONNECTED@ or @SUSPENDED@, aborts the retry process described in "RTN14d":#RTN14d and "RTN14e":#RTN14e and immediately tries to reconnect. -** @(RTN11d)@ If the state is @FAILED@, moves all the channels to @INITIALIZED@, sets their @errorReason@ to @null@, and sets the connection's @errorReason@ to @null@. -* @(RTN12)@ @Connection#close@ function: -** @(RTN12f)@ If the connection state is @CONNECTING@, moves immediately to @CLOSING@. If the connection attempt succeeds, ie. a @CONNECTED@ @ProtocolMessage@ arrives from Ably, then do as specified in "RTN12a":#RTN12a. If it doesn't succeed, move to @CLOSED@. -** @(RTN12a)@ If the connection state is @CONNECTED@, sends a @CLOSE@ @ProtocolMessage@ to the server, sets the state to @CLOSING@ and waits for a @CLOSED@ @ProtocolMessage@ to be received -** @(RTN12b)@ If the @CLOSED@ @ProtocolMessage@ is not received within the "default realtime request timeout":#defaults, the transport will be disconnected and the connection will automatically move to the @CLOSED@ state -** @(RTN12c)@ If the transport is abruptly closed following a @CLOSE@ @ProtocolMessage@ being sent, then the connection will automatically move to the @CLOSED@ state -** @(RTN12d)@ If the connection state is @DISCONNECTED@ or @SUSPENDED@, aborts the retry process described in "RTN14d":#RTN14d and "RTN14e":#RTN14e and moves the connection immediately to the @CLOSED@ state -* @(RTN13)@ @Connection#ping@ function: -** @(RTN13c)@ If the connection state is @CONNECTING@ or @DISCONNECTED@, do the operation once the connection state is @CONNECTED@ -** @(RTN13a)@ Will send a @ProtocolMessage@ with action @HEARTBEAT@ the Ably service when connected and expects a @HEARTBEAT@ message in response. If the client library language supports callbacks, then the callback will be called with the response time or error -** @(RTN13b)@ Will indicate an error if in, or has moved to, the @INITIALIZED@, @SUSPENDED@, @CLOSING@, @CLOSED@ or @FAILED@ state -** @(RTN13c)@ Will fail if a @HEARTBEAT@ @ProtocolMessage@ is not received within the "default realtime request timeout":#defaults -* @(RTN14)@ @Connection@ opening failures: -** @(RTN14a)@ If an API key is invalid, then the connection will enter the @FAILED@ state and the @Connection#errorReason@ will be set on the @Connection@ object as well as the emitted @ConnectionStateChange@ -** @(RTN14b)@ If a connection request fails due to an @ERROR@ ProtocolMessage being sent to the client containing a token error (@statusCode@ value of 401 and error @code@ value in the range @40140 <= @code < 40150@), then if the token is renewable, the error should not emitted, a single attempt to create a new token will be made and a new connection attempt will be initiated using the new token. If the token creation fails, the next connection attempt fails again due to a token error, or the token was not renewable, the connection will transition to the @FAILED@ state and the @Connection#errorReason@ will be set -** @(RTN14c)@ A new connection attempt will fail if not connected within the "default realtime request timeout":#defaults -** @(RTN14d)@ If a connection attempt fails for any recoverable reason (i.e. a network failure or a recoverable authentication failure), the @Connection#state@ will change to @DISCONNECTED@, the @Connection#errorReason@ will be updated, a @ConnectionStateChange@ with the @reason@ will be emitted, and new connection attempts will periodically be made until the maximum time in that state threshold is reached. The @retryIn@ attribute of the @ConnectionStateChange@ object will contain the time in milliseconds until the next connection attempt. See the @disconnectedRetryTimeout@ of @ClientOptions@ below. Each time a new connection attempt is made the state will change to @CONNECTING@ and then to @CONNECTED@ if successful, or @DISCONNECTED@ if unsuccessful and the "default @connectionStateTtl@":#defaults has not been exceeded -** @(RTN14e)@ Once the connection state has been in the @DISCONNECTED@ state for more than the "default @connectionStateTtl@":#defaults, the state will change to @SUSPENDED@ and be emitted with the @reason@, and the @Connection#errorReason@ will be updated. In this state, a new connection attempt will be made periodically as specified within @suspendedRetryTimeout@ of @ClientOptions@ -** @(RTN14f)@ The connection will remain in the @SUSPENDED@ state indefinitely, whilst periodically attempting to reestablish a connection -* @(RTN15)@ @Connection@ failures once @CONNECTED@: -** @(RTN15h)@ If a @DISCONNECTED@ message is received from Ably, then that transport will subsequently be closed by Ably. If the @DISCONNECTED@ message contains a token error (@statusCode@ value of 401 and error @code@ value in the range @40140 <= @code < 40150@), if the token is renewable, the error should not emitted, a single attempt to create a new token will be made and a new connection attempt will be initiated using the new token. If the token creation fails, the next connection attempt fails due to a token error, or the token was not renewable, the connection will transition to the @FAILED@ state and the @Connection#errorReason@ will be set -** @(RTN15a)@ If a @Connection@ transport is disconnected unexpectedly or if a token expires, then the @Connection@ manager will immediately attempt to reconnect and restore the connection state. Connection state recovery is provided by the Ably service and ensures that whilst the client is disconnected, all events are queued and channel state is retained on the Ably servers. When a new connection is made with the correct connection recovery key, the client is able to catch up by receiving the queued @ProtocolMessages@ from Ably. Connection state is only maintained for a brief period, up to a minute, so if a client is disconnected for a longer period connection state cannot be resumed -** @(RTN15b)@ In order for a connection to be resumed and connection state to be recovered, the client library reconnects to the websocket endpoint with two additional querystring params: -*** @(RTN15b1)@ @resume@ is the private connection key assigned to the connection when the first @CONNECTED@ @ProtocolMessage@ was received -*** @(RTN15b2)@ @connectionSerial@ is the most recent @ProtocolMessage#connectionSerial@ received from Ably or @Connection#serial@ which should be identical -** @(RTN15c)@ The system's response to a resume request will be one of the following: -**** @(RTN15c1)@ @CONNECTED@ @ProtocolMessage@ with the same @connectionId@ as the current client, and no @error@. In this case, the server is indicating that the resume succeeded, all channels are still attached, and all backlog messages are available. The client should not change the state of attached channels, and immediately process any queued messages for that channel -**** @(RTN15c2)@ @CONNECTED@ @ProtocolMessage@ with the same @connectionId@ as the current client, and an @error@. In this case, the server is indicating that the resume succeeded but with a non-fatal error, all channels are still attached, and some backlog messages may be unavailable. The @ErrorInfo@ received should be emitted on the client @Connection@ and the @Connection#errorReason@ should be set. The client should not change the state of attached channels, and immediately process any queued messages for that channel. Any channels that are not resumed in full may receive an @ATTACHED@ @ProtocolMessage@ with an @error@, see "@RTL12@":#RTL12 -**** @(RTN15c3)@ @CONNECTED@ @ProtocolMessage@ with a new @connectionId@, and an error in @error@. In this case, a new connection has been established, the resume has failed, the channels are no longer attached, and the error indicates the resume problem which should be emitted. The client library should immediately detach all channels, fail any queued messages on those channels, and set the @Channel#errorReason@ on each detached @Channel@. Additionally, the internal @msgSerial@ counter is reset so that the first message published to Ably will contain a @msgSerial@ value of @0@ -**** @(RTN15c4)@ @ERROR@ @ProtocolMessage@ indicating a fatal error in the connection. The server will close the transport immediately after. If the @ERROR@ is non-recoverable, the client will move to the @FAILED@ state triggering all attached channels to move to the @FAILED@ state as well -** @(RTN15g)@ When the connection resume has failed, all channels should be detached with a suitable error reason -** @(RTN15f)@ @ACK@ and @NACK@ responses for published messages can only ever be received on the transport connection on which those messages were sent. Therefore, once a transport drops, the client library must either fail the publish attempt, or re-attempt by re-sending the messages on a new transport if the resume was successful (i.e. the @CONNECTED@ response includes the expected @connectionId@) -** @(RTN15d)@ Client libraries should have test coverage to ensure connection state recovery is working as expected by forciby disconnecting a client and checking that messages published on channels are delivered once the connection is resumed -** @(RTN15e)@ When a connection is resumed, the @Connection#key@ may change and will be provided in the first @CONNECTED@ @ProtocolMessage#connectionDetails@ when the connection is established. The client library must update the @Connection#key@ value with the new @connectionKey@ value every time -* @(RTN20)@ When the client library can subscribe to the Operating System events for network/internet connectivity changes: -** @(RTN20a)@ When @CONNECTED@, @CONNECTING@ or @DISCONNECTING@, if the operating system indicates that the underlying internet connection is no longer available, then the client library should immediately change the state to @DISCONNECTED@ with emit a state change with an appropriate @reason@. This state change will automatically trigger the client library to attempt to reconnect, see @RTN15@ above -** @(RTN20b)@ When @DISCONNECTED@ or @SUSPENDED@, if the operating system indicates that the underlying internet connection is now available, the client library should immediately attempt to connect -* @(RTN16)@ @Connection@ recovery: -** @(RTN16a)@ Connection recovery is similar to the automatic connection resume except that connection state is recovered explicitly because a @recover@ key is passed to the Realtime library when instanced. Once a connection is recovered, all channels must be explicitly attached by the developer, and any messages queued to be delivered whilst the client was disconnected will be delivered -** @(RTN16b)@ @Connection#recoveryKey@ is an attribute composed of the connection key and latest serial received on the connection -** @(RTN16c)@ @Connection#recoveryKey@ becomes @Null@ when a connection is explicitly @CLOSED@ or @CLOSED@ by the server, as connection state is not retained for connections closed intentionally. The @Connection#key@ and @Connection#id@ is set to @Null@ -** @(RTN16d)@ When a connection is successfully recovered, the @Connection#id@ will be identical to the @id@ of the connection that was recovered, and @Connection#key@ will always be updated to the @ConnectionDetails#connectionKey@ provided in the first @CONNECTED@ @ProtocolMessage@ -** @(RTN16e)@ If the @recover@ option is missing or no longer valid when connecting to Ably, the client will connect anyway, but emit a @ConnectionStateChange@ with a @reason@, and will additionally set the @Connection#errorReason@ with an @ErrorInfo@ object describing the failure -* @(RTN17)@ Host Fallback -** @(RTN17b)@ The fallback behavior described below only applies when the default @realtime.ably.io@ endpoint is being used and has not been overriden, see "RTC1d":#RTC1d and "RTC1e":#RTC1e. -** @(RTN17a)@ By default, every connection attempt is first attempted to the primary host @realtime.ably.io@, which, through DNS, is automatically routed to the client's closest data center. The client library must always prefer the default endpoint (closest data center), even if a previous connection attempt to that endpoint has failed -** @(RTN17c)@ In the case of an error necessitating use of an alternative host (see "RTN17d":#RTN17d), the @Connection@ manager should first check if an internet connection is available by issuing a @GET@ request to @https://internet-up.ably-realtime.com/is-the-internet-up.txt@. If the request succeeds and the text "yes" is included in the body, then the client library can assume it has a viable internet connection and should then immediately retry the connection against all fallback hosts to find an alternative healthy data center. The five fallback hosts are @[a-e].ably-realtime.com@ and should be attempted in random order -** @(RTN17d)@ Errors that necessitate use of an alternative host include: host unresolvable or unreachable, connection timeout, or a response but with an "error body @statusCode@":/rest-api#error-response or HTTP response status code in the range @500 <= code <= 504@. Attempting to reconnect to a fallback host for other failure conditions will not fix the problem and will simply increase the load on other data-centers unnecessarily -** @(RTN17e)@ If the realtime client is connected to a fallback host endpoint, then for the duration that the transport is connected to that host, all HTTP requests, such as history or token requests, should be first attempted to the same data center the realtime connection is established with i.e. the same fallback host must be used as the default HTTP request host. If however the HTTP request against that fallback host fails, then the normal fallback host behavior should be followed attempting the request against another fallback host as described in "RSC15":#RSC15 -* @(RTN18)@ Connection state change side effects: -** @(RTN18a)@ When a connection enters the @DISCONNECTED@ state, it will have no effect on the channel states. Channels in the @ATTACHED@ state will queue messages that are sent as soon as the connection is resumed -** @(RTN18b)@ When a connection enters the @CLOSED@ or @SUSPENDED@ state, all channels will move to the @DETACHED@ state. Channels in the @DETACHED@ state should reject publishing of messages -** @(RTN18c)@ When a connection enters the @FAILED@ state, all channels will move to the @FAILED@ state. Channels in the @FAILED@ state should reject publishing of messages -* @(RTN19)@ Transport state side effects - when a transport is upgraded or disconnected for any reason: -** @(RTN19a)@ Any @ProtocolMessage@ that is awaiting an @ACK@/@NACK@ on the old transport will not receive the @ACK@/@NACK@ on the new transport. The client library must therefore resend any @ProtocolMessage@ that is awaiting a @ACK@/@NACK@ to Ably in order to receive the expected @ACK@/@NACK@ for that message. The Ably service is responsible for keeping track of messages, ignoring duplicates and responding with suitable @ACK@/@NACK@ messages -** @(RTN19b)@ If there are any pending channels i.e. in the @ATTACHING@ or @DETACHING@ state, the respective @ATTACH@ or @DETACH@ message should be resent to Ably -** @(RTN19b)@ If a @SYNC@ is underway, ensure the client library adheres to @RTP3@ - -h3(#realtime-channels). Channels - -* @(RTS1)@ @Channels@ is a collection of @Channel@ objects accessible through @Realtime#channels@ -* @(RTS2)@ Methods should exist to check if a channel exists or iterate through the existing channels -* @(RTS3)@ @Channels#get@ function: -** @(RTS3a)@ Creates a new @Channel@ object for the specified channel if none exists, or returns the existing channel. @ChannelOptions@ can be specified when instancing a new @Channel@ -** @(RTS3b)@ If options are provided, the options are set on the @Channel@ when creating a new @Channel@ -** @(RTS3c)@ Accessing an existing @Channel@ with options in the form @Channels#get(channel, options)@ will update the options on the channel and then return the existing @Channel@ object -* @(RTS4)@ @Channels#release@ function: -** @(RTS4a)@ Detaches the channel and then releases the channel resource i.e. it's deleted and can then be garbage collected - -h3(#realtime-channel). Channel - -* @(RTL1)@ As soon as a @Channel@ becomes attached, all incoming messages and presence messages are processed and emitted where applicable. @PRESENCE@ and @SYNC@ messages are passed to the @Presence@ object ensuring it maintains a map of current members on a channel in realtime -* @(RTL2)@ EventEmitter and states: -** @(RTL2a)@ Implements @EventEmitter@ and emits events for state changes @INITIALIZED@, @ATTACHING@, @ATTACHED@, @DETACHING@, @DETACHED@, @FAILED@ -** @(RTL2b)@ @Channel#state@ attribute is the current state of the channel -** @(RTL2c)@ Additionally, an @ERROR@ event is emitted that contains an @ErrorInfo@ object with details on an error that has occurred for the @Channel@ -* @(RTL3)@ Connection state change side effects: -** @(RTL3a)@ If the connection state changes to @FAILED@ then an @ATTACHING@ or @ATTACHED@ channel state will transition to @FAILED@, set the @Channel#errorReason@ and emit the error event -** @(RTL3b)@ If the connection state changes to @CLOSED@ or @SUSPENDED@ then an @ATTACHING@ or @ATTACHED@ channel state will transition to @DETACHED@ -* @(RTL11)@ If a channel enters the @DETACHED@ or @FAILED@ state, then all messages that are still queued for send on that channel should be deleted from the queue triggering a failure for the publish or presence methods invoked for those messages -* @(RTL4)@ @Channel#attach@ function: -** @(RTL4a)@ If already @ATTACHED@ nothing is done -** @(RTL4h)@ If the channel is in a pending state @DETACHING@ or @ATTACHING@, do the attach operation after the completion of the pending request -** @(RTL4g)@ If the channel is in the @FAILED@ state, the @attach@ request sets its @errorReason@ to @null@, and proceeds with a channel attach described in "RTL4b":#RTL4b, "RTL4h":#RTL4h and "RTL4c":#RTL4c -** @(RTL4b)@ If the connection state is @CLOSED@, @CLOSING@, @SUSPENDED@ or @FAILED@, the @attach@ request results in an error -** @(RTL4h)@ If the connection state is @INITIALIZED@, @CONNECTING@ or @DISCONNECTED@, do the operation once the connection state is @CONNECTED@ -** @(RTL4c)@ Otherwise an @ATTACH@ ProtocolMessage is sent to the server, the state changes to @ATTACHING@ and the channel becomes @ATTACHED@ when the confirmation @ATTACHED@ ProtocolMessage is received -** @(RTL4f)@ Once an @ATTACH@ @ProtocolMessage@ is sent, if an @ATTACHED@ @ProtocolMessage@ is not received within the "default realtime request timeout":#defaults, the attach request should be treated as though it has failed and the channel will return to its previous state -** @(RTL4d)@ If the language permits, a callback can be provided that is called when the channel is attached successfully or the attach fails and the @ErrorInfo@ error is passed as an argument to the callback -** @(RTL4e)@ If the user does not have sufficient permissions to attach to the channel, the channel state @FAILED@ is emitted with the error @ErrorInfo@. An error event is also emitted, and the @Channel#errorReason@ attribute of the @Channel@ is set to the error @ErrorInfo@ object -* @(RTL5)@ @Channel#detach@ function: -** @(RTL5a)@ If the channel state is @INITIALIZED@ or @DETACHED@ nothing is done -** @(RTL5i)@ If the channel is in a pending state @DETACHING@ or @ATTACHING@, do the detach operation after the completion of the pending request -** @(RTL5b)@ If the channel state is @FAILED@, the @detach@ request results in an error -** @(RTL5g)@ If the connection state is @CLOSING@ or @FAILED@, the @detach@ request results in an error -** @(RTL5h)@ If the connection state is @INITIALIZED@, @CONNECTING@ or @DISCONNECTED@, do the detach operation once the connection state is @CONNECTED@ -** @(RTL5d)@ Otherwise a @DETACH@ ProtocolMessage is sent to the server, the state changes to @DETACHING@ and the channel becomes @DETACHED@ when the confirmation @DETACHED@ ProtocolMessage is received -** @(RTL5f)@ Once a @DETACH@ @ProtocolMessage@ is sent, if a @DETACHED@ @ProtocolMessage@ is not received within the "default realtime request timeout":#defaults, the detach request should be treated as though it has failed and the channel will return to its previous state -** @(RTL5e)@ If the language permits, a callback can be provided that is called when the channel is detached successfully or the detach fails and the @ErrorInfo@ error is passed as an argument to the callback -* @(RTL6)@ @Channel#publish@ function: -** @(RTL6a)@ Messages are encoded in the same way as the REST @Channel#publish@ method -** @(RTL6b)@ An optional callback can be provided to the @#publish@ method that is called when the message is successfully delivered or upon failure with the appropriate @ErrorInfo@ error. A test should exist to publish lots of messages on a few connections to ensure all message success callbacks are called for all messages published -** @(RTL6i)@ Expects either an array of @Message@ objects or a @name@ string and @data@ payload: -** @(RTL6i1)@ When @name@ and @data@ is provided, a single @ProtocolMessage@ containing one @Message@ is published to Ably -** @(RTL6i2)@ When an array of @Message@ objects is provided, a single @ProtocolMessage@ is used to publish all @Message@ objects in the array. However, a yet to be implemented feature should limit the total number of messages bundled in a single ProtocolMessage based on the default max message size -** @(RTL6i3)@ Allows @name@ and or @data@ to be @null@. If any of the values are @null@, then key is not sent to Ably i.e. a payload with a @null@ value for @data@ would be sent as follows @{ "name": "click" }@ -** @(RTL6c)@ Connection and channel state conditions: -*** @(RTL6c1)@ If the connection is @CONNECTED@ and the channel is @ATTACHED@ then the messages are published immediately -*** @(RTL6c2)@ If the connection is @INITIALIZED@, @CONNECTING@ or @DISCONNECTED@ or the channel is @INITIALIZED@ or @ATTACHING@, and @ClientOptions#queueMessages@ has not been explicitly set to false, then the message will be queued and delivered as soon as the connection state becomes @CONNECTED@ and the channel is @ATTACHED@ -*** @(RTL6c4)@ If the connection is @SUSPENDED@, @CLOSING@, @CLOSED@, or @FAILED@, or the channel is @DETACHING@, @DETACHED@ or @FAILED@, the operation will result in an error -*** @(RTL6c3)@ Implicitly attaches the @Channel@ if the channel is in the @INITIALIZED@ state. However, if the channel is in or moves to the @DETACHED@ or @FAILED@ state before the operation succeeds, it will result in an error -** @(RTL6d)@ Messages are delivered using a single @ProtocolMessage@ where possible by bundling in all messages for that channel into the @ProtocolMessage#messages@ array. However, a yet to be implemented feature should limit the total number of messages bundled per @ProtocolMessage@ based on the default max message size, and would reject the publish and indicate an error if any single message exceeds that limit -** @(RTL6e)@ Unidentified clients using "Basic Auth":https://en.wikipedia.org/wiki/Basic_access_authentication (i.e. any @clientId@ is permitted as no @clientId@ specified): -*** @(RTL6e1)@ When a @Message@ with a @clientId@ value is published, Ably will accept and publish that message with the provided @clientId@. A test should assert that the @clientId@ of the published @Message@ is populated -** @(RTL6g)@ Identified clients with a @clientId@ (as a result of either an explicitly configured @clientId@ in @ClientOptions@, or implicitly through Token Auth): -*** @(RTL6g1)@ When publishing a @Message@ with the @clientId@ attribute set to @null@: -**** @(RTL6g1a)@ It is unnecessary for the client to set the @clientId@ of the @Message@ before publishing -**** @(RTL6g1b)@ Ably will assign a @clientId@ upon receiving the @Message@. A test should assert that the @clientId@ value is populated for the @Message@ when received -*** @(RTL6g2)@ When publishing a @Message@ with the @clientId@ attribute value set to the identified client's @clientId@, Ably will accept the message and publish it. A test should assert that the @clientId@ value is populated for the @Message@ when received -*** @(RTL6g3)@ When publishing a @Message@ with a different @clientId@ attribute value from the identified client's @clientId@, the client library should reject that publish operation immediately. The message should not be sent to Ably and it should result in an error, typically in the form of an error callback. The connection and channel must remain available for further operations -*** @(RTL6g4)@ When using Token Auth, unless a @clientId@ has been provided in @ClientOptions@ or inferred following authentication, the client library is unidentified and will not be constrained when publishing messages with any explicit @clientId@. If a @Message@ with a @clientId@ value is published before the @clientId@ is configured or inferred following authentication, the client library should not reject any explicit @clientId@ specified in a message. A test should instance a library without an explicit @clientId@ and an @authCallback@ that returns a @tokenDetails@ object with a @clientId@, then publish a message with the same @clientId@ before authentication, and ensure that the message is published following authentication and received back with the @clientId@ intact. A further test should follow the same sequence of events, but should instead use an incompatible @clientId@ in the message, expecting that the message is rejected by the Ably service and the message error should contain the server error message, and the connection and channel should remain available for further operations -** @(RTL6h)@ Where the library language permits, the @Channel#publish(name, data)@ method should provide an optional argument that allows the @clientId@ value to be specified such as @Channel#publish('event', 'data', { clientId: 'John' })@ -** @(RTL6f)@ @Message#connectionId@ should match the current @Connection#id@ for all published messages, a test should exist to ensure the @connectionId@ for received messages matches that of the publisher -* @(RTL7)@ @Channel#subscribe@ function: -** @(RTL7a)@ Subscribe with no arguments subscribes a listener to all messages -** @(RTL7b)@ Subscribe with a single name argument subscribes a listener to only messages whose @name@ member matches the string name -** @(RTL7c)@ Implicitly attaches the @Channel@ if the channel is in the @INITIALIZED@ state. However, if the channel is in or moves to the @DETACHED@ or @FAILED@ state before the operation succeeds, it will result in the listener not being registered and an error being indicated, typically to the optional callback where the language permits -** @(RTL7d)@ Messages delivered are automatically decoded based on the @encoding@ attribute; see REST @Channel@ encoding features. If there is an error decoding a message, the message is still delivered, but in addition to sending an error message to the logger, an @ErrorInfo@ error object is emitted as an error on the @Channel@. Tests should exist to publish and subscribe to encoded messages using the "AES 128":https://github.com/ably/ably-common/blob/master/test-resources/crypto-data-128.json and "AES 256":https://github.com/ably/ably-common/blob/master/test-resources/crypto-data-256.json fixture test data -** @(RTL7e)@ If a message cannot be decoded or decrypted successfully, it should be delivered to the listener with the @encoding@ attribute set indicating the residual encoding state, and an error should be emitted on the channel -** @(RTL7f)@ A test should exist ensuring published messages are not echoed back to the subscriber when @echoMessages@ is set to false in the @Realtime@ library constructor -* @(RTL8)@ @Channel#unsubscribe@ function: -** @(RTL8a)@ Unsubscribe with no arguments unsubscribes the provided listener to all messages if subscribed -** @(RTL8b)@ Unsubscribe with a single name argument unsubscribes the provided listener if previously subscribed with a name-specific subscription -* @(RTL9)@ @Channel#presence@ attribute: -** @(RTL9a)@ Returns the @Presence@ object for this channel -* @(RTL10)@ @Channel#history@ function: -** @(RTL10a)@ Supports all the same params as REST @Channel#history@ -** @(RTL10b)@ Additionally supports the param @untilAttach@, which if true, will only retrive messages prior to the moment that the channel was attached. This bound is specified by passing the querystring param @fromSerial@ with the serial number assigned to the channel in the @ATTACHED@ @ProtocolMessage@. If the @untilAttach@ param is specified when the channel is not attached, it results in an error -** @(RTL10c)@ Returns a @PaginatedResult@ page containing the first page of messages in the @PaginatedResult#items@ attribute returned from the history request -** @(RTL10d)@ A test should exist that publishes messages from one client, and upon confirmation of message delivery, a history request should be made on another client to ensure all messages are available -* @(RTL12)@ An attached channel may receive an additional @ATTACHED@ @ProtocolMessage@ from Ably at any point, however this is typically triggered following a transport being upgraded or resumed. If the @ATTACHED@ message contains an @error@, the error should be emitted on the channel, the @Channel#errorReason@ should be set, and the channel should remain attached. An @ATTACHED@ state change event should not be emitted by the @Channel@ if the @Channel@ is already @ATTACHED@ (i.e. no state change has occurred) - -h3(#realtime-presence). Presence - -* @(RTP1)@ When a channel @ATTACHED@ @ProtocolMessage@ is received, the @ProtocolMessage@ may contain a bit flag with value 1 indicating that there are currently members present on the channel. If members are present, subsequent @ProtocolMessage SYNC@ messages will be delivered with presence members (messages) until the @SYNC@ operation is complete. If there is no flag or the right most bit is zero, then the presence map should be considered in sync immediately as there are no members present on the channel at the time of attach -* @(RTP2)@ A "PresenceMap":https://github.com/ably/ably-java/blob/master/src/io/ably/realtime/Presence.java#L384-L529 should be used to maintain a list of members present on a channel. As there are no guarantees that during the @SYNC@ phase presence events will arrive in order i.e. a leave event for a member can arrive before that member is later registered as as present as part of the initial @SYNC@ operation. As such, until the @SYNC@ operation is complete, timestamps must be recorded for all members to ensure the most recent present state is used, see the "Java implementation":https://github.com/ably/ably-java/blob/master/src/io/ably/realtime/Presence.java#L418-L431. Once a @SYNC@ event is complete, the members that are now considered @ABSENT@ can be removed from the map, see the "Java implementation":https://github.com/ably/ably-java/blob/master/src/io/ably/realtime/Presence.java#L504-L509 -* @(RTP3)@ If a @SYNC@ operation is underway but not yet complete, and the transport is disconnected unexpectedly, then if the connection is resumed successfully, it is the responsibility of the client library to complete the @SYNC@ operation. The client library requests a @SYNC@ resume by sending a @SYNC@ @ProtocolMessage@ with the last received sync serial number. See the "Ruby implementation":https://github.com/ably/ably-ruby/blob/7b18a20/lib/ably/realtime/presence/members_map.rb#L169-L176 and the "Ruby test":https://github.com/ably/ably-ruby/blob/7b18a20/spec/acceptance/realtime/presence_spec.rb#L1338-L1357 -* @(RTP4)@ Ensure a test exists that enters 250 members using @Presence#enterClient@ on a single connection, and checks for @PRESENT@ events to be emitted on another connection for each member, and once sync is complete, all 250 members should be present in a @Presence#get@ request -* @(RTP5)@ Channel state change side effects: -** @(RTP5a)@ If the channel enters the @DETACHED@ or @FAILED@ state then all queued presence messages will fail immediately, and the presence map is cleared -** @(RTP5b)@ If a channel enters the @ATTACHED@ state then all queued presence messages will be sent immediately and a presence @SYNC@ will be initiated implicitly -* @(RTP16)@ Connection state conditions: -** @(RTP16a)@ If the connection is @CONNECTED@ and the channel is @ATTACHED@ then all presence messages are published immediately -** @(RTP16b)@ If the connection is @INITIALIZED@, @CONNECTING@ or @DISCONNECTED@ or the channel is @ATTACHING@, and @ClientOptions#queueMessages@ has not been explicitly set to false, then all presence messages will be queued and delivered as soon as the connection state returns to @CONNECTED@ and the channel is @ATTACHED@ -** @(RTP16c)@ Else publishing presence messages will result in an error -* @(RTP6)@ @Presence#subscribe@ function: -** @(RTP6a)@ Subscribe with no arguments subscribes a listener to all presence messages -** @(RTP6b)@ Subscribe with a single action argument - such as @ENTER@, @LEAVE@, @UPDATE@ or @PRESENT@ - subscribes a listener to receive only presence messages with that action -** @(RTP6c)@ Implicitly attaches the @Channel@ if the channel is in the @INITIALIZED@ state. However, if the channel is in or moves to the @FAILED@ state before the operation succeeds, it will result in the listener not being registered and an error being indicated, typically to the optional callback where the language permits -* @(RTP7)@ @Presence#unsubscribe@ function: -** @(RTP7a)@ Unsubscribe with no arguments unsubscribes the listener if previously subscribed with an action-specific subscription -** @(RTP7b)@ Unsubscribe with a single action argument unsubscribes the provided listener to all presence messages for that action -* @(RTP8)@ @Presence#enter@ function: -** @(RTP8a)@ Enters the current client into this channel, optionally with the data provided -** @(RTP8b)@ Optionally a callback can be provided that is called for both success or failure to enter -** @(RTP8c)@ A @PRESENCE ProtocolMessage@ with a @PresenceMessage@ with the action @ENTER@ is sent to the Ably service. The @clientId@ attribute of the @PresenceMessage@ must not be present. Entering without an explicit @PresenceMessage#clientId@, implicitly uses the @clientId@ for the current connection -** @(RTP8d)@ Implicitly attaches the @Channel@ if the channel is in the @INITIALIZED@ state. However, if the channel is in the @DETACHED@ or @FAILED@ state, the @enter@ request results in an error -** @(RTP8e)@ Optional data can be included when entering a channel that will be encoded / decoded as with normal messages. A test should exist to ensure data used with enter is encoded & decoded correctly. Also, when data is provided when entering, but no data is provided when leaving, the data attribute should be emitted in the @LEAVE@ event for this client -** @(RTP8f)@ If the client library is authenticated but unidentified (i.e. @clientId@ is a wildcard @'*'@ or client is anonymous), the @enter@ request results in an error immediately -** @(RTP8g)@ If the channel is @DETACHED@ or @FAILED@, the @enter@ request results in an error immediately -** @(RTP8h)@ If the Ably service determines that the client does not have required presence permission, a @NACK@ is sent to the client resulting in an error -** @(RTP8i)@ If the Ably service determines that the client is unidentified, a @NACK@ is sent to the client resulting in an error -* @(RTP9)@ @Presence#update@ function: -** @(RTP9a)@ Updates the data for the present member with a value or @null@ -** @(RTP9b)@ If the client was not already entered, it enters this client into this channel -** @(RTP9c)@ Optionally a callback can be provided that is called for both success or failure to update -** @(RTP9d)@ A @PRESENCE ProtocolMessage@ with a @PresenceMessage@ with the action @UPDATE@ is sent to the Ably service. The @clientId@ attribute of the @PresenceMessage@ must not be present. Updating without an explicit @PresenceMessage#clientId@, implicitly uses the @clientId@ for the current connection -** @(RTP9e)@ In all other ways, this method is identical to @Presence#enter@ and should have matching tests -* @(RTP10)@ @Presence#leave@ function: -** @(RTP10a)@ Leaves this client from the channel and the data will be updated with the value provided. If the language permits the data argument to be omitted, then the previously set data value will be sent as a convenience -** @(RTP10b)@ Optionally a callback can be provided that is called for both success or failure to leave -** @(RTP10c)@ A @PRESENCE ProtocolMessage@ with a @PresenceMessage@ with the action @LEAVE@ is sent to the Ably service. The @clientId@ attribute of the @PresenceMessage@ must not be present. Leaving without an explicit @PresenceMessage#clientId@, implicitly uses the @clientId@ for the current connection -** @(RTP10d)@ If the client is not currently @ENTERED@, it will result in an error -** @(RTP10e)@ In all other ways, this method is identical to @Presence#enter@ and should have matching tests -* @(RTP11)@ @Presence#get@ function: -** @(RTP11a)@ Returns the list of current members on the channel in a callback. By default, will wait for the @SYNC@ to be completed, see "RTP11c1":#RTP11c1 -** @(RTP11b)@ Implicitly attaches the @Channel@ if the channel is in the @INITIALIZED@ state. However, if the channel is in or moves to the @DETACHED@ or @FAILED@ state before the operation succeeds, it will result in an error -** @(RTP11c)@ An optional set of params can be provided: -*** @(RTP11c1)@ @waitForSync@ (default @true@). When @true@, method will wait until @SYNC@ is complete before returning a list of members. When @false@, known set of presence members is returned immediately, which may be incomplete if the @SYNC@ is not finished -*** @(RTP11c2)@ @clientId@ filters members by the provided @clientId@ -*** @(RTP11c3)@ @connectionId@ filters members by the provided @connectionId@ -* @(RTP12)@ @Presence#history@ function: -** @(RTP12a)@ Supports all the same params as REST @Presence#history@ -** @(RTP12b)@ Additionally supports the param @untilAttach@, which if true, will only retrive messages up to the moment that the channel was attached. This bound is specified by passing the querystring param @fromSerial@ with the serial number assigned to the channel in the @ATTACHED@ @ProtocolMessage@. If the @untilAttach@ param is specified when the channel is not attached, it will result in an error -** @(RTP12c)@ Returns a @PaginatedResult@ page containing the first page of messages in the @PaginatedResult#items@ attribute returned from the history request -** @(RTP12d)@ A test should exist that registers presence with a few clients, and upon confirmation of entering the channel for all clients, a presence history request should be made using another client to ensure all presence events are available -* @(RTP13)@ @Presence#syncComplete@ returns true if the initial @SYNC@ operation has completed for the members present on the channel -* @(RTP14)@ @Presence#enterClient@ function: -** @(RTP14a)@ Enters into presence on a channel on behalf of another @clientId@. This allows a single client with suitable permissions to register presence on behalf of any number of clients using a single connection -** @(RTP14b)@ Optionally a callback can be provided that is called for both success or failure to enter -** @(RTP14c)@ Data can optionally be provided when entering and will follow the normal encoding & decoding rules -** @(RTP14d)@ A test should exist that registers a number of members each with a different @clientId@ on a presence channel, and then a @Presence#get@ should be used to verify that all members are present as expected -* @(RTP15)@ @Presence#enterClient@ @Presence#updateClient@ and @Presence#leaveClient@ function: -** @(RTP15a)@ Performs an enter, update or leave for given @clientId@. These methods apply if the Realtime library was not initialized with a specific @clientId@. This allows a single client with suitable permissions to update presence on behalf of any number of clients using a single connection. Otherwise these are functionality equivalent to the corresponding @enter@, @update@ and @leave@ methods, and equivalent test coverage should be provided -** @(RTP15b)@ Tests should use @enterClient@, @updateClient@ and @leaveClient@ for many members from one @Realtime@ client and check that the operations are reflected in the presence map and the expected events are emitted on a separate client -** @(RTP15c)@ Tests should also ensure that using these methods has no side effects on a client that has entered normally using @Presence#enter@ -** @(RTP15d)@ A callback can be provided that will be called upon success or failure -** @(RTP15e)@ Implicitly attaches the @Channel@ if the channel is in the @INITIALIZED@ state. However, if the channel is in or moves to the @DETACHED@ or @FAILED@ state before the operation succeeds, it will result in an error -** @(RTP15f)@ If the client is identified and has a valid @clientId@, and the @clientId@ argument does not match the client's @clientId@, then it should indicate an error. The connection and channel remain available for further operations - -h3(#eventemitter). EventEmitter mixin / interface - -* @(RTE1)@ @EventEmitter@ is a generic interface for event registration and delivery used in a number of the types in the Realtime client library. For example, the @Connection@ object emits events for connection state using the @EventEmitter@ pattern -* @(RTE2)@ Where objects provide @subscribe@ or @unsubscribe@ methods, they should follow the specification for the @EventEmitter#on@ and @EventEmitter#off@ methods respectively -* @(RTE3)@ @EventEmitter#on@ registers the provided listener for either all events when no @event@ argument is provided, or for only a single named event when an @event@ argument is provided. If @on@ is called more than once with the same listener and @event@, the listener is added multiple times to its listener registry. Therefore, as an example, assuming the same listener is registered twice using @on@, and an event is emitted once, the listener would be invoked twice -* @(RTE4)@ @EventEmitter#once@ registers the provided listener for either the first event that is emitted when no @event@ argument is provided, or for only the first occurrence of a single named event when an @event@ argument is provided. If @once@ is called more than once with the same listener, the listener is added multiple times to its listener registry. Therefore, as an example, assuming the same listener is registered twice using @once@, and an event is emitted once, the listener would be invoked twice. However, all subsequent events emitted would not invoke the listener as @once@ ensures that each registration is only invoked once -* @(RTE5)@ @EventEmitter#off@ deregisters a listener. If called with a specific event and a listener, it removes all registrations that match both the given listener and the given event; if called only with a listener, it removes all registrations matching the given listener, regardless of whether they are associated with an event or not; if called with no arguments, it removes all registrations, for all events and listeners -* @(RTE6)@ @EventEmitter#emit@ emits an event, calling registered listeners with the given event name and any other given arguments. If an exception is raised in any of the listeners, the exception is caught by the @EventEmitter@ and the exception is logged to the Ably logger. Tests must exist to ensure exceptions raised in client code do not propagate and inhibit other event processing within the client library - -h2(#state-conditions-and-operations). State conditions and operations - -h3(#connection-states-operations). @Connection.state@ effects on realtime operations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InitializedConnectingConnectedDisconnectedSuspendedClosingClosedFailed
@connect@"RTN11a":#RTN11aNo-opNo-op"RTN11c":#RTN11c"RTN11c":#RTN11c"RTN11b":#RTN11b"RTN11a":#RTN11a"RTN11d":#RTN11d
@close@No-op"RTN12f":#RTN12f"RTN12a":#RTN12a"RTN12d":#RTN12d"RTN12d":#RTN12dNo-opNo-opNo-op
@ping@"RTN13b":#RTN13b"RTN13c":#RTN13c"RTN13a":#RTN13a"RTN13c":#RTN13c"RTN13b":#RTN13b"RTN13b":#RTN13b"RTN13b":#RTN13b"RTN13b":#RTN13b
Channel @attach@"RTL4h":#RTL4h"RTL4h":#RTL4h"See channel states table":#channel-states-operations"RTL4h":#RTL4h"RTL4b":#RTL4b"RTL4b":#RTL4b"RTL4b":#RTL4b"RTL4b":#RTL4b
Channel @detach@"RTL5h":#RTL5h"RTL5h":#RTL5h"See channel states table":#channel-states-operations"RTL5h":#RTL5h"See channel states table":#channel-states-operations"RTL5g":#RTL5g"See channel states table":#channel-states-operations"RTL5g":#RTL5g
Channel @publish@"RTL6c2":#RTL6c2"RTL6c2":#RTL6c2"See channel states table":#channel-states-operations"RTL6c2":#RTL6c2"RTL6c4":#RTL6c4"RTL6c4":#RTL6c4"RTL6c4":#RTL6c4"RTL6c4":#RTL6c4
Presence ops."RTP16b":#RTP16b"RTP16b":#RTP16b"See channel states table":#channel-states-operations"RTP16b":#RTP16b"RTP16c":#RTP16c"RTP16c":#RTP16c"RTP16c":#RTP16c"RTP16c":#RTP16c
- -h3(#channel-states-operations). @RealtimeChannel.state@ effects on channel operations - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InitializedAttachingAttachedDetachingDetachedFailed
@attach@"RTL4c":#RTL4c"RTL4h":#RTL4h"RTL4a":#RTL4a"RTL4h":#RTL4h"RTL4c":#RTL4c"RTL4g":#RTL4g
@detach@"RTL5h":#RTL5h"RTL5i":#RTL5i"RTL5d":#RTL5d"RTL5i":#RTL5i"RTL5a":#RTL5a"RTL5b":#RTL5b
@publish@"RTL6c2":#RTL6c2"RTL6c2":#RTL6c2"RTL6c1":#RTL6c1"RTL6c4":#RTL6c4"RTL6c4":#RTL6c4"RTL6c3":#RTL6c3
Presence ops."RTP16b":#RTP16b"RTP16b":#RTP16b"RTP16a":#RTP16a"RTP16c":#RTP16c"RTP16c":#RTP16c"RTP16c":#RTP16c
- -h2. Types - -h3(#types). Data types - -h4. Message - -* @(TM1)@ A @Message@ represents an individual message to be sent or received via the Ably Realtime service. See the "Ruby Message documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Message, but bear in mind the attributes following underscore naming in Ruby -* @(TM2)@ Attributes available in a @Message@, see the "Ruby Message documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Message for an explanation of each attribute: -** @(TM2a)@ @id@ string - unique ID for this message -** @(TM2b)@ @clientId@ string -** @(TM2c)@ @connectionId@ string -** @(TM2g)@ @name@ string -** @(TM2d)@ @data@ string, buffer or JSON-encodable object or array -** @(TM2e)@ @encoding@ string -** @(TM2f)@ @timestamp@ time in milliseconds since epoch - -h4. PresenceMessage - -* @(TP1)@ A @PresenceMessage@ represents an individual presence message to be sent or received via the Ably Realtime service. See the "Ruby PresenceMessage documentation":http://www.rubydoc.info/gems/ably/Ably/Models/PresenceMessage, but bear in mind the attributes following underscore naming in Ruby -* @(TP2)@ @PresenceMessage@ @Action@ enum has the following values in order from zero: @ABSENT@, @PRESENT@, @ENTER@, @LEAVE@, @UPDATE@ -* @(TP3)@ Attributes available in a @PresenceMessage@, see the "Ruby PresenceMessage documentation":http://www.rubydoc.info/gems/ably/Ably/Models/PresenceMessage for an explanation of each attribute: -** @(TP3a)@ @id@ string - unique ID for this message -** @(TP3b)@ @action@ enum -** @(TP3c)@ @clientId@ string -** @(TP3d)@ @connectionId@ string -** @(TP3e)@ @data@ string, buffer or JSON-encodable object or array -** @(TP3f)@ @encoding@ string -** @(TP3g)@ @timestamp@ time in milliseconds since epoch -** @(TP3h)@ @memberKey@ string function that combines the @connectionId@ and @clientId@ ensuring multiple connected clients with the same clientId are uniquely identifiable - -h4. ProtocolMessage - -* @(TR1)@ A @ProtocolMessage@ represents the type used to send and receive messages over the Realtime protocol. A ProtocolMessage always relates either to the connection or to a single channel only, but can contain multiple individual Messages or PresenceMessages. See the "Ruby ProtocolMessage documentation":http://www.rubydoc.info/gems/ably/Ably/Models/ProtocolMessage, but bear in mind the attributes following underscore naming in Ruby -* @(TR2)@ @ProtocolMessage@ @Action@ enum has the following values in order from zero: @HEARTBEAT@, @ACK@, @NACK@, @CONNECT@, @CONNECTED@, @DISCONNECT@, @DISCONNECTED@, @CLOSE@, @CLOSED@, @ERROR@, @ATTACH@, @ATTACHED@, @DETACH@, @DETACHED@, @PRESENCE@, @MESSAGE@, @SYNC@ -* @(TR3)@ @ProtocolMessage@ @Flag@ enum has the following values in order from zero: @HAS_PRESENCE@, @HAS_BACKLOG@ -* @(TR4)@ Attributes available in a @ProtocolMessage@, see the "Ruby ProtocolMessage documentation":http://www.rubydoc.info/gems/ably/Ably/Models/ProtocolMessage for an explanation of each attribute: -** @(TR4a)@ @action@ enum -** @(TR4n)@ @id@ string -** @(TR4b)@ @channel@ string -** @(TR4c)@ @channelSerial@ string -** @(TR4d)@ @connectionId@ string -** @(TR4e)@ @connectionKey@ string. Note that this field is soon to be deprecated; when @ConnectionDetails#connectionKey@ is present, it should be considered the definitive @connectionKey@ for the current connection -** @(TR4f)@ @connectionSerial@ long -** @(TR4o)@ @connectionDetails@ @ConnectionDetails@ object - provides details on the constraints or defaults for the connection such as max message size, client ID or connection state TTL -** @(TR4g)@ @count@ integer -** @(TR4h)@ @error@ @ErrorInfo@ object -** @(TR4i)@ @flags@ integer -** @(TR4j)@ @msgSerial@ long -** @(TR4k)@ @messages@ Array of @Message@ objects -** @(TR4l)@ @presence@ Array of @PresenceMessage@ objects -** @(TR4m)@ @timestamp@ time in milliseconds since epoch - -h4. PaginatedResult - -* @(TG1)@ A @PaginatedResult@ is a type that represents a page of results from a "paginated query":/rest-api/#pagination. The response is accompanied by metadata that indicates the relative queries available -* @(TG2)@ @PaginatedResult@ wraps all message and presence history, stats and REST presence requests. Instancing this type should not result in an error if paging headers are not returned from the REST API -* @(TG3)@ @PaginatedResult#items@ attribute contains a page of results (for example an Array of @Message@ objects for a channel history request) -* @(TG4)@ @PaginatedResult#next@ function returns a new @PaginatedResult@ loaded with the next page of results. If there are no further pages, then @null@ is returned -* @(TG5)@ @PaginatedResult#first@ function returns a new @PaginatedResult@ for the first page of results -* @(TG6)@ @PaginatedResult#hasNext@ function returns @true@ if there are further pages -* @(TG7)@ @PaginatedResult#isLast@ function returns @true@ if this page is the last page i.e. @!hasNext@ - -h4. TokenRequest - -* @(TE1)@ @TokenRequest@ is a type containing the token request details sent to the "REST requestToken endpoint":/rest-api/#request-token -* @(TE2)@ String attributes @keyName@, @clientId@, @nonce@ and @mac@ -* @(TE3)@ @capability@ is a string attribute containing capabilities JSON stringified -* @(TE5)@ @timestamp@ long - The timestamp (in milliseconds since the epoch) of this request. Timestamps, in conjunction with the @nonce@, are used to prevent requests from being replayed -* @(TE4)@ @ttl@ attribute represents time to live (expiry) of this token in milliseconds - -h4. TokenDetails - -* @(TD1)@ @TokenDetails@ is a type containing the token request response from the "REST requestToken endpoint":/rest-api/#request-token -* @(TD2)@ @TokenDetails#token@ attribute contains the token string -* @(TD3)@ @TokenDetails#expires@ attribute contains the expiry time in milliseconds. Where idiomatic in the language, this can be a Date/Time object -* @(TD4)@ @TokenDetails#issued@ attribute contains the time the token was issued in milliseconds. Where idiomatic in the language, this can be a Date/Time object -* @(TD5)@ @TokenDetails#capability@ attribute contains the capability JSON stringified -* @(TD6)@ @TokenDetails#clientId@ attribute contains the @clientId@ assigned to the token. If @clientId@ is @null@ or omitted, then the token is prohibited from assuming a @clientId@ in any operations, however if @clientId@ is a wildcard string @'*'@, then the token is permitted to assume any @clientId@. Any other string value for @clientId@ implies that the @clientId@ is both enforced and assumed for all operations for this token - -h4. Stats - -* @(TS1)@ @Stats@ is a type encapsulating a statistics datapoint retrieved from the "REST stats endpoint":/rest-api/#stats. See "example statistics in JSON format":/general/statistics/ -* @(TS2)@ All stats values default to zero when no underlying JSON value exists. We send sparse JSON to stats requests omitting fields where the value is zero to reduce bandwidth and optimize JSON parsing, however the API exposed to developers ensures that all properties of the @Stats@ object such as @stats.all.messages.count@ will always return an @Integer@ value i.e. all attributes are non-nullable -* @(TS3)@ See the "Ruby Stats type documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats for a list of attributes and their types for the @Stats@ object -* @(TS4)@ @Stats.ConnectionTypes@ - see the "Ruby ConnectionTypes documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats/ConnectionTypes -* @(TS5)@ @Stats.MessageCount@ - see the "Ruby MessageCount documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats/MessageCount -* @(TS6)@ @Stats.MessageTypes@ - see the "Ruby MessageTypes documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats/MessageTypes -* @(TS7)@ @Stats.MessageTraffic@ - see the "Ruby MessageTraffic documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats/MessageTraffic -* @(TS8)@ @Stats.RequestCount@ - see the "Ruby RequestCount documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats/RequestCount -* @(TS9)@ @Stats.ResourceCount@ - see the "Ruby ResourceCount documentation":http://www.rubydoc.info/gems/ably/Ably/Models/Stats/ResourceCount - -h4. ErrorInfo - -* @(TI1)@ Provides a generic Ably @ErrorInfo@ object that contains Ably @code@, @statusCode@ (analogous to HTTP status code) and @message@ attributes -* @(TI2)@ Errors returned from the Ably server are compatible with the @ErrorInfo@ structure and should result in errors that inherit from @ErrorInfo@ -* @(TE3)@ "Ably-common":https://github.com/ably/ably-common should be included as a submodule so that "consistent error codes":https://github.com/ably/ably-common/blob/master/protocol/errors.json can be used - -h4. ConnectionStateChange - -* @(TA1)@ Whenever the connection state changes, a @ConnectionStateChange@ object is emitted on the @Connection@ object -* @(TA2)@ The @ConnectionStateChange@ object contains the current state in attribute @current@, the previous state in attribute @previous@, and when the client is not connected and a connection attempt will be made automatically by the library, the amount of time in milliseconds until the next retry in the attribute @retryIn@ -* @(TA3)@ If the connection state change includes error information, then the @reason@ attribute will contain an @ErrorInfo@ object describing the reason for the error -* @(TA4)@ See the "Java library implementation":https://github.com/ably/ably-java/blob/245a3f20a6dce0d34413ddfed19c5da8ea647422/src/io/ably/realtime/ConnectionStateListener.java#L15-L20 of this object - -h4. Capability - *API not defined yet* -* @(TC1)@ This type represents a capability for a key or token -* @(TC2)@ For now a string representation of the JSON will suffice wherever @capability@ is used - -h4. ConnectionDetails - -* @(CD1)@ Connection details are optionally passed to the client library in the @CONNECTED@ @ProtocolMessage#connectionDetails@ attribute to inform the client about any constraints it should adhere to, and provide additional metadata about the connection. For example, if a request is made to publish a message that exceeds the @maxMessageSize@, the client library can reject the message immediately, without communicating with the Ably service -* @(CD2)@ Attributes available in @ConnectionDetails@: -** @(CD2a)@ @clientId@ contains the client ID assigned to the token. If @clientId@ is @null@ or omitted, then the client is prohibited from assuming a @clientId@ in any operations, however if @clientId@ is a wildcard string @'*'@, then the client is permitted to assume any @clientId@. Any other string value for @clientId@ implies that the @clientId@ is both enforced and assumed for all operations from this client -** @(CD2b)@ @connectionKey@ is the connection secret key string that is used to resume a connection and its state. When present, this @connectionKey@ should be considered the definitive @connectionKey@ for the current connection and the soon to be deprecated @ProtocolMessage#connectionKey@ should be ignored -** @(CD2c)@ @maxMessageSize@ is the maximum individual message size in bytes -** @(CD2d)@ @maxFrameSize@ is the maximum size for a single frame of data sent to Ably. This restriction applies to a @ProtocolMessage@ sent over a realtime connection, or the total body size for a REST request -** @(CD2e)@ @maxInboundRate@ is the maximum allowable number of requests per second from a client or Ably. In the case of a realtime connection, this restriction applies to the number of @ProtocolMessage@ objects sent, whereas in the case of REST, it is the total number of REST requests per second -** @(CD2f)@ @connectionStateTtl@ is the duration that Ably will persist the connection state when a Realtime client is abruptly disconnected -** @(CD2g)@ @serverId@ string is a unique identifier for the front-end server that the client has connected to. This server ID is only used for the purposes of debugging - -h3(#options). Option types - -h4. ClientOptions -* @(TO1)@ Ably library options used when instancing a REST or Realtime client library, see "Java ClientOptions":https://github.com/ably/ably-java/blob/master/src/io/ably/types/ClientOptions.java which extends "Java AuthOptions":https://github.com/ably/ably-java/blob/0e9d961a02f4b87a59a45fe59e23a5553590102d/src/io/ably/rest/Auth.java#L44-L129 as a reference -* @(TO2)@ Note: @ClientOptions@ does not currently define a default for max message size or request size. This will be added in the future to ensure that REST requests does not exceed the limits before the request is made to the server. In the case of realtime, the connection constraints will be sent to the client in the initial @CONNECTED@ @ProtocolMessage@ -* @(TO3)@ The attributes of @ClientOptions@ consist of: -** @(TO3a)@ @clientId@ string - the id of the client represented by this instance -** @(TO3b)@ @logLevel@ - controls the level of verbosity of log messages from the library. The implementation of this is likely to vary by platform -** @(TO3c)@ @logHandler@ - allows the client to intercept log messages and handle them in a client-specific way. The implementation of this is likely to vary by platform -** @(TO3d)@ @tls@ boolean - defaults to true. If false, will not use TLS for all connections -** @(TO3e)@ @autoConnect@ boolean - defaults to true. If false, suppresses the automatic initiation of a connection when the library is instanced -** @(TO3f)@ @useBinaryProtocol@ boolean - defaults to true. If false, forces the library to use the JSON encoding for REST and Realtime operations, instead of the default binary msgpack encoding -** @(TO3g)@ @queueMessages@ boolean - defaults to true. If false, suppresses the default queueing of messages when connection states that anticipate imminent connection (connecting and disconnected). Instead, publish and presence state changes will fail immediately if not in the connected state -** @(TO3h)@ @echoMessages@ boolean - defaults to true. If false, suppresses messages originating from this connection being echoed back on the same connection -** @(TO3i)@ @recover@ string - A connection recovery string, specified with the intention of inheriting the state of an earlier connection -** @(TO3j)@ Auth option attributes: -*** @(TO3j1)@ @key@ string - Full Ably key string as obtained from dashboard -*** @(TO3j2)@ @token@ string - An authentication token string issued for this application -*** @(TO3j3)@ @tokenDetails@ @TokenDetails@ - An authentication token issued for this application -*** @(TO3j4)@ @useTokenAuth@ boolean - When true, token authentication will always be used by the client. If @clientId@ is unspecified, then the token issued will inherently be anonymous i.e. it will contain an empty @clientId@ -*** @(TO3j5)@ @authCallback@ - A callback to call to obtain a signed @TokenRequest@, @TokenDetails@ or a token string. This enables a client to obtain token requests or tokens from another entity, so tokens can be renewed without the client requiring a key -*** @(TO3j6)@ @authUrl@ string - A URL to query to obtain a signed @TokenRequest@, @TokenDetails@ or a token string. This enables a client to obtain token request or token from another entity, so tokens can be renewed without the client requiring a key -*** @(TO3j7)@ @authMethod@ - The HTTP verb to be used when a request is made by the library to the @authUrl@. Defaults to @GET@, supports @GET@ and @POST@ -*** @(TO3j8)@ @authHeaders@ - Headers to be included in any request made by the library to the @authUrl@ -*** @(TO3j9)@ @authParams@ - Additional params to be included in any request made by the library to the @authUrl@, either as query params added to the URL in the case of @GET@, or form-encoded in the body in the case of @POST@ -*** @(TO3j10)@ @queryTime@ - If true, the library will query the Ably system for the current time instead of relying on a locally-available time of day -*** @(TO3j11)@ @defaultTokenParams@ - When a "TokenParams":#token-params object is provided, it will override the client library defaults described in "TokenParams":#token-params -** @(TO3k)@ Development environment attributes: -*** @(TO3k1)@ @environment@ string - for development environments only; allows a non-default Ably environment to be used such as @sandbox@ -*** @(TO3k2)@ @restHost@ string - for development environments only; allows a non-default Ably REST host to be specified. It is never valid to provide both a @restHost@ and @environment@ value -*** @(TO3k3)@ @realtimeHost@ string - for development environments only; allows a non-default Ably Realtime host to be specified. It is never valid to provide both a @realtimeHost@ and @environment@ value -*** @(TO3k4)@ @port@ integer - for development environments only; allows a non-default Ably non-TLS port to be specified -*** @(TO3k5)@ @tlsPort@ integer - for development environments only; allows a non-default Ably TLS port to be specified -** @(TO3l)@ The follow attributes, if set, are used to change the default behavior of the library: -*** @(TO3l1)@ @disconnectedRetryTimeout@ integer - default 15,000 (15s). When the connection enters the @DISCONNECTED@ state, after this delay in milliseconds, if the state is still @DISCONNECTED@, the client library will attempt to reconnect automatically -*** @(TO3l2)@ @suspendedRetryTimeout@ integer - default 30,000 (30s). When the connection enters the @SUSPENDED@ state, after this delay in milliseconds, if the state is still @SUSPENDED@, the client library will attempt to reconnect automatically -*** @(TO3l3)@ @httpOpenTimeout@ integer - default 4,000 (4s). Timeout for opening the connection, available in the client library if supported by the transport -*** @(TO3l4)@ @httpRequestTimeout@ integer - default 15,000 (15s). Timeout for any single HTTP request and response -*** @(TO3l5)@ @httpMaxRetryCount@ integer - default 3. Max number of fallback hosts to use as a fallback when an HTTP request to the primary host is unreachable or indicates that it is unserviceable -*** @(TO3l6)@ @httpMaxRetryDuration@ integer - default 10,000 (10s). Max elapsed time in which fallback host retries for HTTP requests will be attempted i.e. if the first default host attempt takes 5s, and then the subsequent fallback retry attempt takes 7s, no further fallback host attempts will be made as the total elapsed time of 12s exceeds the default 10s limit - -h4(#token-params). TokenParams -* @(TK1)@ A class providing parameters of a token request. These params are used when invoking @Auth#authorise@, @Auth#requestToken@ and @Auth#createTokenRequest@ -* @(TK2)@ The attributes of @TokenParams@ consist of: -* @(TK2a)@ @ttl@ long - Requested time to live for the token in milliseconds. When omitted, the REST API default of 60 minutes is applied by Ably -* @(TK2b)@ @capability@ string - Capability requirements JSON stringified for the token. When omitted, the REST API default to allow all operations is applied by Ably, with the string value @{"*":["*"]}@ -* @(TK2c)@ @clientId@ string - A @clientId@ string to associate with this token. If @clientId@ is @null@ or omitted, then the token is prohibited from assuming a @clientId@ in any operations, however if @clientId@ is a wildcard string @'*'@, then the token is permitted to assume any @clientId@. Any other string value for @clientId@ implies that the @clientId@ is both enforced and assumed for all operations for this token -* @(TK2d)@ @timestamp@ long - The timestamp (in milliseconds since the epoch) of this request. Timestamps, in conjunction with the @nonce@, are used to prevent requests from being replayed. @timestamp@ is a "one-time" value, and is valid in a request, but is not validly a member of any default token params such as @ClientOptions#defaultTokenParams@ - -h4. AuthOptions -* @(AO1)@ A class providing configurable authentication options used when authenticating or issuing tokens explicitly. These options are used when invoking @Auth#authorise@, @Auth#requestToken@ and @Auth#createTokenRequest@ -* @(AO2)@ The attributes of @AuthOptions@ consist of: -** @(AO2a)@ @key@ string - Full Ably key string, as obtained from dashboard, used when signing token requests locally -** @(AO2b)@ @authCallback@ - A callback to call to obtain a signed @TokenRequest@, @TokenDetails@ or a token string. This enables a client to obtain token requests or tokens from another entity, so tokens can be renewed without the client requiring a key -** @(AO2c)@ @authUrl@ string - A URL to query to obtain a signed @TokenRequest@, @TokenDetails@ or a token string. This enables a client to obtain token request or token from another entity, so tokens can be renewed without the client requiring a key -** @(AO2d)@ @authMethod@ - The HTTP verb to be used when a request is made by the library to the @authUrl@. Defaults to @GET@, supports @GET@ and @POST@ -** @(AO2e)@ @authHeaders@ - Headers to be included in any request made by the library to the @authUrl@ -** @(AO2f)@ @authParams@ - Additional params to be included in any request made by the library to the @authUrl@, either as query params in the case of @GET@, or form-encoded in the body in the case of @POST@ -** @(AO2g)@ @queryTime@ - If true, the library will query the Ably system for the current time instead of relying on a locally-available time of day -** @(AO2h)@ @force@ - when true, indicates that a new token should be requested - -h4. ChannelOptions -* @(TB1)@ options provided when instancing a channel, see "Java ChannelOptions":https://github.com/ably/ably-java/blob/master/src/io/ably/types/ChannelOptions.java as a reference -* @(TB2)@ The attributes of @ChannelOptions@ consist of: -** @(TB2b)@ @cipher@, which is either: -*** @(TB2b1)@ A @CipherParams@ instance, or -*** @(TB2b2)@ an options hash (or language equivalent) consisting of any subset of @CipherParams@ fields that includes a @key@. In this case, the client library should call `getDefaultParams`, passing it the options hash, to obtain a @CipherParams@ instance -* @(TB3)@ The client lib may optionally provide an alternative constructor @withCipherKey@ for ChannelOptions that takes a @key@ only. (This must be differentiated from the normal constructor such that it is clear that the value being passed in is a key). (This is intended for languages where requiring a hash map is unidiomatic) - -h4. CipherParams -* @(TZ1)@ params to configure encryption for a channel, see "Java CipherParams class":https://github.com/ably/ably-java/blob/8a151b4edfa228ddef806fa10d2f9ce2be1ac09c/lib/src/main/java/io/ably/lib/util/Crypto.java as a reference -* @(TZ2)@ The attributes of @CipherParams@ consist of anything necessary to implement the supported algorithms, in addition to the following standardised attributes: -** @(TZ2a)@ @algorithm@ string - Default is @AES@. Optionally specify the algorithm to use for encryption, currently only @AES@ is supported -** @(TZ2b)@ @keyLength@ integer - the length in bits of the @key@ -** @(TZ2d)@ @key@ binary - private key used to encrypt and decrypt payloads -** @(TZ2c)@ @mode@ string - Default is @CBC@. Optionally specify cipher mode, currently only @CBC@ is supported - -h3(#defaults). Client Library defaults - -The following default values are configured for the client library: - -* @(DF1)@ Realtime defaults: -** @(DF1a)@ @connectionStateTtl@ integer - default 60s. The duration that Ably will persist the connection state when a Realtime client is abruptly disconnected. When the client is in the @DISCONNECTED@ state, once this TTL has passed, the client should change the state to the @SUSPENDED@ state signifying that the state is now lost i.e. channels need to be re-attached manually. Note that this default is overriden by @connectionStateTtl@, if specified in the @ConnectionDetails@ of the @CONNECTED@ @ProtocolMessage@ -** @(DF1b)@ @realtimeRequestTimeout@ - default 10s. When a realtime client library is establishing a connection with Ably, or sending a @HEARTBEAT@, @CONNECT@, @ATTACH@, @DETACH@ or @CLOSE@ @ProtocolMessage@ to Ably, this is the amount of time that the client library will wait before considering that request as failed and triggering a suitable failure condition - -h2(#idl). Interface Definition - -The following bespoke IDL (Interface Definition Language) describes the types and classes present in the Rest and Realtime client libraries. - -Please note the following conventions: - -* Types are capitalized -* Attribute and method names are lowercase -* Attributes are denoted as @attributeName: Type@ -* Instance methods are denoted as @methodName(argName: Type, argName: Type) -> ReturnType@ (@ReturnType@ may be omitted) -* Callback functions / closures are denoted as @(argName: Type, argName: Type) -> ReturnType@ (@ReturnType@ is usually omitted) -* Values produced by I/O (e.g. a request) are prefixed with @=> io@. In some platforms (JS) those values are passed as arguments to a callback argument, instead of being returned. I/O always can fail, but how do they fail is undefined in the spec, so it's also undefined here -* Enums are denoted as @.A | .B | .C@ -* @Type?@ denotes a nullable type -* @Type default value@ denotes that the thing being annotated with @Type@ has @value@ as default. @Type api-default value@ denotes that the Ably server API uses those defaults and therefore it is unnecessary for the client library to send these default values to the API -* Class fields (as opposed to instance fields) are prefixed with a @+@ -* @Duration@ and @Time@ types are typically represented as milliseconds since the epoch. Where needed, a more idiomatic language specific duration may be used such as @seconds@ or @Time@ respectively for Ruby -* @Data@ is a message payload type, see "RSL4a":#RSL4a for a list of supported payload types - -```[python] -class Rest: - constructor(keyStr: String) // RSC1 - constructor(tokenStr: String) // RSC1 - constructor(ClientOptions) // RSC1 - auth: Auth // RSC5 - channels: Channels // RSN1 - stats( - start: Time, // RSC6b1 - end: Time api-default now(), // RSC6b1 - direction: .Backwards | .Forwards api-default .Backwards, // RSC6b2 - limit: int api-default 100, // RSC6b3 - unit: .Minute | .Hour | .Day | .Month api-default .Minute // RSC6b4 - ) => io PaginatedResult // RSC6a - time() => io Time // RSC16 - -class Realtime: - constructor(keyStr: String) // RSC1 - constructor(tokenStr: String) // RSC1 - constructor(ClientOptions) // RSC1 - auth: Auth // RTC4 - channels: Channels // RTC3, RTS1 - clientId: String? // proxy for RSA7 - connection: Connection // RTC2 - stats: // Same as Rest.stats, RTC5a - close() // proxy for RTN12 - connect() // proxy for RTN11 - time() => io Time // RTC6a - -class ClientOptions: - embeds AuthOptions // TO3j - autoConnect: Bool default true // RTC1b, TO3e - clientId: String? // RSC17, RSA4, RSA15, TO3a - defaultTokenParams: TokenParams? // TO3j11 - echoMessages: Bool default true // RTC1a, TO3h - environment: String? // RSC15b, TO3k1 - logHandler: // platform specific - TO3c - logLevel: // platform specific - TO3b - port: Int default 80 // TO3k4 - queueMessages: Bool default true // RTP16b, TO3g - restHost: String default "rest.ably.io" // RSC12, TO3k2 - realtimeHost: String default "realtime.ably.io" // RTC1d, TO3k3 - recover: String? // RTC1c, TO3i - tls: Bool default true // RSC18, TO3d - tlsPort: Int default 443 // TO3k5 - useBinaryProtocol: Bool default true // TO3f - // configurable retry and failure defaults - disconnectedRetryTimeout: Duration default 15s // TO311 - suspendedRetryTimeout: Duration default 30s // RTN14d, TO312 - httpOpenTimeout: Duration default 4s // TO313 - httpRequestTimeout: Duration default 15s // TO314 - httpMaxRetryCount: Int default 3 // TO315 - httpMaxRetryDuration: Duration default 10s // TO315 - -class AuthOptions: // RSA8e - authCallback: (String | TokenDetails | TokenRequest) ->? // RSC14c, RSA4, TO3j5, AO2b - authHeaders: [(String, String)]? // RSA8c3, TO3j8, AO2e - authMethod: .GET | .POST default .GET // RSA8c, TO3j7, AO2d - authParams: [String: [String]]? // RSA8c3, RSA8c1, TO3j9, AO2f - authUrl: String? // RSC14c, RSA4, RSA8c, TO3j6, AO2c - force: Bool default false // RSA10d, AO2h - key: String? // RSC14a, RSA14, TO3j1, AO2a - queryTime: Bool default false // RSA9d, TO3j10, AO2a - token: String? | TokenDetails? // RSC14c, RSA4, TO3j2 - tokenDetails: TokenDetails? // RSC14c, RSA4, TO3j3 - useTokenAuth: Bool? // RSA4, RSA14, TO3j4 - -class TokenParams: // RSAA8e - capability: String api-default '{"*":["*"]}' // RSA9f, TK2b - clientId: String? // TK2c - nonce: String? // RSA9c, Tk2d - timestamp: Time? // RSA9d, Tk2d - ttl: Duration api-default 60min // RSA9e, TK2a - -class Auth: - clientId: String? // RSA7, RSC17, RSA12 - authorise(TokenParams?, AuthOptions?) => io TokenDetails // RSA10 - createTokenRequest(TokenParams?, AuthOptions?) => io TokenRequest // RSA9 - requestToken(TokenParams?, AuthOptions?) => io TokenDetails // RSA8e - -class TokenDetails: - capability: String // TD5 - clientId: String? // TD6 - expires: Time // TD3 - issued: Time // TD4 - token: String // TD2 - -class TokenRequest: - capability: String // TE3 - clientId: String? // TE2 - keyName: String // TE2 - mac: String // TE2 - nonce: String // TE2 - timestamp: Time? // TE5 - ttl: Duration? api-default 60min // TE4 - -class Channels: - exists(String) -> Bool // RSN2, RTS2 - get(String) -> ChannelType // RSN3a, RTS3a - get(String, ChannelOptions) -> ChannelType // RSN3c, RTS3c - iterate() -> Iterator // RSN2, RTS2 - release(String) // RSN4, RTS4 - -class RestChannel: - name: String? - presence: RestPresence // RSL3 - history( - start: Time, // RSL2b1 - end: Time api-default now(), // RSL2b1 - direction: .Backwards | .Forwards api-default .Backwards, // RSL2b2 - limit: int api-default 100 // RSL2b3 - ) => io PaginatedResult // RSL2a - publish([Message]) => io // RSL1 - publish(name: String?, data: Data?) => io // RSL1 - publish(name: String?, data: Data?, clientId: String) => io // RSL1h - -class RealtimeChannel: - embeds EventEmitter // RTL2 - errorReason: ErrorInfo? // RTL4e - state: ChannelState // RTL2b - presence: RealtimePresence // RTL9 - attach() => io // RTL4d - detach() => io // RTL5e - history( - start: Time, // RTL10a - end: Time api-default now(), // RTL10a - direction: .Backwards | .Forwards api-default .Backwards, // RTL10a - limit: int api-default 100, // RTL10a - untilAttach: Bool default false // RTL10b - ) => io PaginatedResult // RSL2a - publish([Message]) => io // RTL6i - publish(name: String?, data: Data?) => io // RTL6i - publish(name: String?, data: Data?, clientId: String) => io // RTL6h - subscribe((Message) ->) => io // RTL7a - subscribe(String, (Message) ->) => io // RTL7b - unsubscribe() // RTL8a, RTE5 - unsubscribe((Message) ->) // RTL8a - unsubscribe(String, (Message) ->) // RTL8a - -enum ChannelState: - INITIALIZED - ATTACHING - ATTACHED - DETACHING - DETACHED - FAILED - -enum ChannelEvent: - embeds ChannelState - ERROR // RTL2c - -class ChannelOptions: - +withCipherKey(key: Binary | String)? -> ChannelOptions // TB3 - cipher: (CipherParams | Params)? // RSL5a, TB2b - -class CipherParams: - algorithm: String default "AES" // TZ2a - key: Binary // TZ2d - keyLength: Int // TZ2b - mode: String default "CBC" // TZ2c - -class Crypto: - +getDefaultParams(Params) -> CipherParams // RSE1 - +generateRandomKey(keyLength: Int?) => io Binary // RSE2 - -class RestPresence: - get( - limit: int api-default 100, // RSP3a - clientId: String?, // RSP3a2 - connectionId: String?, // RSP3a3 - ) => io PaginatedResult // RSPa - history( - start: Time, // RSP4b1 - end: Time api-default now(), // RSP4b1 - direction: .Backwards | .Forwards api-default .Backwards, // RSP4b2 - limit: int api-default 100, // RSP4b3 - ) => io PaginatedResult // RSP4a - -class RealtimePresence: - syncComplete: Bool // RTP13 - get( - waitForSync: Bool default true, // RTP11c1 - clientId: String?, // RTP11c2 - connectionId: String?, // RTP11c3 - ) => io [PresenceMessage] // RTP11 - history( - start: Time, // RTP12a - end: Time, // RTP12a - direction: .Backwards | .Forwards api-default .Backwards, // RTP12a - limit: int api-default 100, // RTP12a - untilAttach: Bool default false // RTP12b - ) => io PaginatedResult // RTP12c - subscribe((PresenceMessage) ->) => io // RTP6a - subscribe(PresenceAction, (PresenceMessage) ->) => io // RTP6b - unsubscribe() // RTP7a, RTE5 - unsubscribe((PresenceMessage) ->) // RTP7a - unsubscribe(PresenceAction, (PresenceMessage) ->) // RTP7b - // presence state modifiers - enter(Data?) => io // RTP8 - update(Data?) => io // RTP9 - leave(Data?) => io // RTP10 - enterClient(clientId: String, Data?) => io // RTP4, RTP14, RTP15 - updateClient(clientId: String, Data?) => io // RTP15 - leaveClient(clientId: String, Data?) => io // RTP15 - -enum PresenceAction: - ABSENT // TP2 - PRESENT // TP2 - ENTER // TP2 - LEAVE // TP2 - UPDATE // TP2 - -class ConnectionDetails: - clientId: String? // RSA12a, CD2a - connectionKey: String // RTN15e, CD2b - connectionStateTtl: Duration // CD2f, RTN14e, DF1a - maxFrameSize: Int // CD2d - maxInboundRate: Int // CD2e - maxMessageSize: Int // CD2c - serverId: String // CD2g - -class Message: - constructor(name: String?, data: Data?) // TM2 - constructor(name: String?, data: Data?, clientId: String?) // TM2 - clientId: String? // RSL1g1, TM2b - connectionId: String? // TM2c - data: Data? // TM2d - encoding: String? // TM2e - id: String // TM2a - name: String? // TM2g - timestamp: Time // TM2f - -class PresenceMessage - action: PresenceAction // TP3b - clientId: String // TP3c - connectionId: String // TP3d - data: Data? // TP3e - encoding: String? // TP3f - id: String // TP3a - timestamp: Time // TP3g - memberKey() -> String // TP3h - -class ProtocolMessage: - action: ProtocolMessageAction // TR2, TR4a - channel: String? // TR4b - channelSerial: String? // TR4c - connectionDetails: ConnectionDetails? // RSA7b3, RTN19, TR4o - connectionId: String? // RTN15c1, TR4d - connectionKey: String? // TR4e - connectionSerial: Int? // RTN10c, TR4f - count: Int? // TR4g - error: ErrorInfo? // RTN15c2, TR4h - flags: .HAS_PRESENCE & .HAS_BACKLOG ? // RTP1, TR3, TR4i - id: String? // TR4b - messages: [Message]? // TR4k - msgSerial: Int? // RTN7b, TR4j - presence: [PresenceMessage]? // TR4l - timestamp: Time? // TR4m - -enum ProtocolMessageAction: - HEARTBEAT // TR2 - ACK // TR2 - NACK // TR2 - CONNECT // TR2 - CONNECTED // TR2 - DISCONNECT // TR2 - DISCONNECTED // TR2 - CLOSE // TR2 - CLOSED // TR2 - ERROR // TR2 - ATTACH // TR2 - ATTACHED // TR2 - DETACH // TR2 - DETACHED // TR2 - PRESENCE // TR2 - MESSAGE // TR2 - SYNC // TR2 - -class Connection: - embeds EventEmitter // RTN4a, RTN4e - errorReason: ErrorInfo? // RTN14a - id: String? // RTN8 - key: String? // RTN9 - recoveryKey: String? // RTN16b, RTN16c - serial: Int // RTN10 - state: ConnectionState // RTN4d - close() // RTN12 - connect() // RTC1b, RTN3, RTN11 - ping() => io // RTN13 - -enum ConnectionState: - INITIALIZED - CONNECTING - CONNECTED - DISCONNECTED - SUSPENDED - CLOSING - CLOSED - FAILED - -class ConnectionStateChange: - current: ConnectionState // TA2 - previous: ConnectionState // TA2 - reason: ErrorInfo? // RTN4f, TA3 - retryIn: Duration? // RTN14d, TA2 - -class Stats: - all: StatsMessageTypes // http://goo.gl/TpIh5I - apiRequests: StatsRequestCount // http://goo.gl/lFhZLC - channels: StatsResourceCount // http://goo.gl/jfu0q1 - connections: StatsConnectionTypes // http://goo.gl/72fQ7Z - inbound: StatsMessageTraffic // http://goo.gl/8SjQAJ - intervalGranularity: StatsIntervalGranularity - intervalId: String - intervalTime: Time - outbound: StatsMessageTraffic // http://goo.gl/8SjQAJ - persisted: StatsMessageTypes // http://goo.gl/TpIh5I - tokenRequests: StatsRequestCount // http://goo.gl/lFhZLC - -enum StatsIntervalGranularity: - MINUTE - HOUR - DAY - MONTH - -class ErrorInfo: - code: Int // TI1 - message: String // TI1 - statusCode: Int // TI1 - -class EventEmitter: - on((Data...) ->) // RTE4 - on(Event, (Data...) ->) // RTE4 - once((Data...) ->) // RTE4 - once(Event, (Data...) ->) // RTE4 - off() // RTE5 - off((Data...) ->) // RTE5 - off(Event, (Data...) ->) // RTE5 - emit(Event, Data...) // RTE6 - -class PaginatedResult: - items: [T] // TG3 - first() => io PaginatedResult // TG5 - hasNext() -> Bool // TG6 - isLast() -> Bool // TG7 - next() => io PaginatedResult? // TG4 -```