From a3e847ddb8bbfde7385d5988fce51daa079aaed1 Mon Sep 17 00:00:00 2001 From: tomC Date: Tue, 5 May 2020 17:13:02 +0100 Subject: [PATCH 01/47] Add new structure for realtime/channel details Adds sub-directories for realtime/channels containing pages pertaining to channels, namely channel parameters and channel metadata. --- content/code/realtime/rewind.code | 2 +- content/core-features/pubsub.textile | 2 +- .../versions/v1.1/pubsub.textile | 2 +- content/general/events/ifttt.textile | 2 +- content/general/firehose.textile | 2 +- content/general/queues.textile | 4 +- content/general/versions/v0.8/queues.textile | 2 +- .../general/versions/v1.0/firehose.textile | 2 +- .../general/versions/v1.0/functions.textile | 4 +- content/general/versions/v1.0/queues.textile | 4 +- .../general/versions/v1.0/webhooks.textile | 4 +- .../versions/v1.1/events/ifttt.textile | 2 +- .../general/versions/v1.1/firehose.textile | 2 +- content/general/versions/v1.1/queues.textile | 4 +- content/mqtt/index.textile | 2 +- .../types/_channel_state_change.textile | 2 +- .../v0.8/types/_channel_state_change.textile | 2 +- .../v1.0/types/_channel_state_change.textile | 2 +- .../v1.1/types/_channel_state_change.textile | 2 +- .../{ => channels}/channel-metadata.textile | 0 .../channel-parameters/deltas.textile | 222 ++++++++++++++++ .../channel-parameters/overview.textile | 247 ++++++++++++++++++ .../channel-parameters/rewind.textile | 79 ++++++ .../overview.textile} | 8 +- content/realtime/encryption.textile | 2 +- content/realtime/history.textile | 6 +- content/realtime/index.textile | 2 +- content/realtime/messages.textile | 2 +- content/realtime/presence.textile | 2 +- content/realtime/usage.textile | 2 +- .../realtime/versions/v0.8/encryption.textile | 2 +- .../realtime/versions/v0.8/history.textile | 4 +- content/realtime/versions/v0.8/index.textile | 2 +- .../realtime/versions/v0.8/presence.textile | 2 +- content/realtime/versions/v0.8/usage.textile | 2 +- .../realtime/versions/v1.0/encryption.textile | 2 +- .../realtime/versions/v1.0/history.textile | 2 +- content/realtime/versions/v1.0/index.textile | 2 +- .../realtime/versions/v1.0/messages.textile | 2 +- .../realtime/versions/v1.0/presence.textile | 2 +- content/realtime/versions/v1.0/usage.textile | 2 +- .../realtime/versions/v1.1/encryption.textile | 2 +- .../realtime/versions/v1.1/history.textile | 2 +- content/realtime/versions/v1.1/index.textile | 2 +- .../realtime/versions/v1.1/messages.textile | 2 +- .../realtime/versions/v1.1/presence.textile | 2 +- content/realtime/versions/v1.1/usage.textile | 2 +- content/rest/versions/v0.8/usage.textile | 2 +- content/rest/versions/v1.0/usage.textile | 2 +- content/root/best-practice-guide.textile | 2 +- .../channel-enumeration-rest.textile | 2 +- .../channel-lifecycle-events.textile | 2 +- .../channel-occupancy-events.textile | 2 +- content/tutorials/newsfeed-react.textile | 2 +- content/tutorials/presence.textile | 4 +- content/tutorials/publish-subscribe.textile | 4 +- .../reactjs-realtime-commenting.textile | 2 +- .../tutorials/sse-and-http-streaming.textile | 2 +- content/tutorials/trainapp-fitbit.textile | 2 +- content/tutorials/vue-tictactoe.textile | 2 +- data/jsbins.yaml | 4 +- 61 files changed, 619 insertions(+), 71 deletions(-) rename content/realtime/{ => channels}/channel-metadata.textile (100%) create mode 100644 content/realtime/channels/channel-parameters/deltas.textile create mode 100644 content/realtime/channels/channel-parameters/overview.textile create mode 100644 content/realtime/channels/channel-parameters/rewind.textile rename content/realtime/{channels.textile => channels/overview.textile} (98%) diff --git a/content/code/realtime/rewind.code b/content/code/realtime/rewind.code index f6186c7539..8a8157b127 100644 --- a/content/code/realtime/rewind.code +++ b/content/code/realtime/rewind.code @@ -58,7 +58,7 @@ function show(status, color, box) {

Ably Rewind demo

-

In this example, we demonstrate the simplest way to subscribe to a message using rewind in libraries older than v1.2. See our Rewind documentation for more details. +

In this example, we demonstrate the simplest way to subscribe to a message using rewind in libraries older than v1.2. See our Rewind documentation for more details.

diff --git a/content/core-features/pubsub.textile b/content/core-features/pubsub.textile index 4394be227e..00bfa3853b 100644 --- a/content/core-features/pubsub.textile +++ b/content/core-features/pubsub.textile @@ -16,6 +16,6 @@ For instance, consider a location tracking application. The subscriber will cont Pub/Sub in Ably -As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). +As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels/overview and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). Read our "Realtime Library":/realtime documentation to learn how you can implement Pub/Sub in your applications. You can also jump into our "Pub/Sub tutorial":https://www.ably.io/tutorials/publish-subscribe#lang-javascript or check out a "quick bit video":https://www.youtube.com/watch?v=_70uOFiBeo8&t=0s&list=PLv7MaB8onr7krKzzwswsLYFsB_KmgEu44&index=2 to see it in action. \ No newline at end of file diff --git a/content/core-features/versions/v1.1/pubsub.textile b/content/core-features/versions/v1.1/pubsub.textile index 4394be227e..00bfa3853b 100644 --- a/content/core-features/versions/v1.1/pubsub.textile +++ b/content/core-features/versions/v1.1/pubsub.textile @@ -16,6 +16,6 @@ For instance, consider a location tracking application. The subscriber will cont Pub/Sub in Ably -As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). +As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels/overview and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). Read our "Realtime Library":/realtime documentation to learn how you can implement Pub/Sub in your applications. You can also jump into our "Pub/Sub tutorial":https://www.ably.io/tutorials/publish-subscribe#lang-javascript or check out a "quick bit video":https://www.youtube.com/watch?v=_70uOFiBeo8&t=0s&list=PLv7MaB8onr7krKzzwswsLYFsB_KmgEu44&index=2 to see it in action. \ No newline at end of file diff --git a/content/general/events/ifttt.textile b/content/general/events/ifttt.textile index 717f1fd2a5..bd26a882f6 100644 --- a/content/general/events/ifttt.textile +++ b/content/general/events/ifttt.textile @@ -46,7 +46,7 @@ In addition, if you are wanting data to be passed through and processed by IFTTT } ``` -In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. +In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels/overview to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. h2(#example). Example diff --git a/content/general/firehose.textile b/content/general/firehose.textile index 0e8856871e..bcffd22f88 100644 --- a/content/general/firehose.textile +++ b/content/general/firehose.textile @@ -6,7 +6,7 @@ index: 26 Our Firehose can stream your realtime data published within the Ably platform directly to another streaming or queueing service. For example, all messages published by any device on a channel could be immediately streamed to Amazon Kinesis allowing you to process this data in realtime. Firehose is offered as part of our "Ably Reactor service":https://www.ably.io/reactor but is only available to "Enterprise customers":https://www.ably.io/pricing/enterprise. -Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. +Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. As each message is delivered once to your streaming or queueing server, this design is commonly used to process realtime data published by Ably asynchronously. For example, using workers consuming from your stream or queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. Find out why we think streams and message queues help solve many of the challenges associated with consuming pub/sub data server-side in our article: "Message queues — the right way to process and work with realtime data on your servers":https://blog.ably.io/message-queues-the-right-way-to-process-and-work-with-realtime-data-on-your-servers-2d15985301f8. diff --git a/content/general/queues.textile b/content/general/queues.textile index a799d630fd..6c4bcfd6cc 100644 --- a/content/general/queues.textile +++ b/content/general/queues.textile @@ -46,7 +46,7 @@ All Ably accounts have access to Reactor Queue functionality, however to get sta h3(#provisioning). Provisioning Reactor Queues -Unlike "pub/sub channels":/realtime/channels that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. +Unlike "pub/sub channels":/realtime/channels/overview that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. Queues are setup "within your app dashboard":https://support.ably.io/support/solutions/articles/3000030053-how-do-i-access-my-app-dashboard and you will need to configure: @@ -404,7 +404,7 @@ When using Reactor Queues, please bear in mind that: * There is a default TTL (time-to-live) applied to all messages that is configured when you provision your queue. If a message has not been consumed from a queue within this period, it will be moved to the deadletter queue. If the TTL of the deadletter queue passes, the message is discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * There is a max message limit configured when you provision your queue. If the max message limit is reached for your queue, new messages will be moved to the deadletter queue. Once the deadletter queue reaches its max message limit, new messages will be discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * With the AMQP protocol, it is possible to consume multiple queues from a single connection, and also to consume more than one message at a time. You will need to refer to your client library's documentation to enable these capabilities. See "this StackOverFlow answer":http://stackoverflow.com/a/17011833/139607 as a good starting point. -* Unlike our Ably "pub/sub channels":/realtime/channels which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. +* Unlike our Ably "pub/sub channels":/realtime/channels/overview which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. * Each message published to the queue will count towards you monthly message quota. See "billing info for more details":#below. h3(#scalability-availability). Queue Scalability and High Availability diff --git a/content/general/versions/v0.8/queues.textile b/content/general/versions/v0.8/queues.textile index 2a604c4af9..80b50051a5 100644 --- a/content/general/versions/v0.8/queues.textile +++ b/content/general/versions/v0.8/queues.textile @@ -6,7 +6,7 @@ index: 19 Message queues provide a reliable mechanism for customers to process, store, augment or reroute realtime data efficiently and asynchronously by workers. -Using configurable rules, you can ensure that your messages, presence and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events are enqueued on an Ably message queue. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our "message queues":https://en.wikipedia.org/wiki/Message_queue operate on the basis that each messages is delivered to only one subscriber. +Using configurable rules, you can ensure that your messages, presence and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events are enqueued on an Ably message queue. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our "message queues":https://en.wikipedia.org/wiki/Message_queue operate on the basis that each messages is delivered to only one subscriber. As each message is delivered once to a single subscriber, queues are commonly used by one or more workers to process realtime data published by Ably asynchronously. For example, using workers subscribed to a queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. diff --git a/content/general/versions/v1.0/firehose.textile b/content/general/versions/v1.0/firehose.textile index b526bc812e..e5451a7ceb 100644 --- a/content/general/versions/v1.0/firehose.textile +++ b/content/general/versions/v1.0/firehose.textile @@ -6,7 +6,7 @@ index: 26 Our Firehose can stream your realtime data published within the Ably platform directly to another streaming or queueing service. For example, all messages published by any device on a channel could be immediately streamed to Amazon Kinesis allowing you to process this data in realtime. Firehose is offered as part of our "Ably Reactor service":https://www.ably.io/reactor but is only available to "Enterprise customers":https://www.ably.io/pricing/enterprise. -Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. +Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. As each message is delivered once to your streaming or queueing server, this design is commonly used to process realtime data published by Ably asynchronously. For example, using workers consuming from your stream or queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. Find out why we think streams and message queues help solve many of the challenges associated with consuming pub/sub data server-side in our article: "Message queues — the right way to process and work with realtime data on your servers":https://blog.ably.io/message-queues-the-right-way-to-process-and-work-with-realtime-data-on-your-servers-2d15985301f8. diff --git a/content/general/versions/v1.0/functions.textile b/content/general/versions/v1.0/functions.textile index dd54e80d32..380388061d 100644 --- a/content/general/versions/v1.0/functions.textile +++ b/content/general/versions/v1.0/functions.textile @@ -44,7 +44,7 @@ _Please note that the @messages@ attribute is an @Array@ so that future envelope h3(#decoding-messages). Decoding messages -Each member of @messages@ is a 'raw' message, with the contents of your "@Message@":/rest/messages#properties within it. Messages sent "over the realtime service":/realtime/channels are automatically decoded into the "@Message@":/realtime/types#message object by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded on an individual member of that array. This will transform them into an array of "@Message@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). Using the Ably client library to decode messages has several advantages: +Each member of @messages@ is a 'raw' message, with the contents of your "@Message@":/rest/messages#properties within it. Messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into the "@Message@":/realtime/types#message object by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded on an individual member of that array. This will transform them into an array of "@Message@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). Using the Ably client library to decode messages has several advantages: * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) * If you are using "encryption":/realtime/encryption, you can pass your encryption key to the method and it will decrypt the @data@ for you @@ -79,7 +79,7 @@ _Please note that the @presence@ attribute is an @Array@ so that future envelope h3(#decoding-presence). Decoding presence events -Each member of @presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels are automatically decoded into "@PresenceMessage@":/realtime/types#presence-message objects by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded on an individual member of that array. This will transform them into an array of "@PresenceMessage@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). Using the Ably client library to decode @presence@ has several advantages: +Each member of @presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into "@PresenceMessage@":/realtime/types#presence-message objects by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded on an individual member of that array. This will transform them into an array of "@PresenceMessage@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). Using the Ably client library to decode @presence@ has several advantages: * It will decode the (numerical) action into a "@PresenceAction@":/realtime/presence#presence-action string (such as "@enter@", "@update@", or "@leave@") * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) diff --git a/content/general/versions/v1.0/queues.textile b/content/general/versions/v1.0/queues.textile index d1dac78fc4..67c7f944f5 100644 --- a/content/general/versions/v1.0/queues.textile +++ b/content/general/versions/v1.0/queues.textile @@ -46,7 +46,7 @@ All Ably accounts have access to Reactor Queue functionality, however to get sta h3(#provisioning). Provisioning Reactor Queues -Unlike "pub/sub channels":/realtime/channels that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. +Unlike "pub/sub channels":/realtime/channels/overview that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. Queues are setup "within your app dashboard":https://support.ably.io/support/solutions/articles/3000030053-how-do-i-access-my-app-dashboard and you will need to configure: @@ -404,7 +404,7 @@ When using Reactor Queues, please bear in mind that: * There is a default TTL (time-to-live) applied to all messages that is configured when you provision your queue. If a message has not been consumed from a queue within this period, it will be moved to the deadletter queue. If the TTL of the deadletter queue passes, the message is discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * There is a max message limit configured when you provision your queue. If the max message limit is reached for your queue, new messages will be moved to the deadletter queue. Once the deadletter queue reaches its max message limit, new messages will be discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * With the AMQP protocol, it is possible to consume multiple queues from a single connection, and also to consume more than one message at a time. You will need to refer to your client library's documentation to enable these capabilities. See "this StackOverFlow answer":http://stackoverflow.com/a/17011833/139607 as a good starting point. -* Unlike our Ably "pub/sub channels":/realtime/channels which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. +* Unlike our Ably "pub/sub channels":/realtime/channels/overview which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. * Each message published to the queue will count towards you monthly message quota. See "billing info for more details":#below. h3(#scalability-availability). Queue Scalability and High Availability diff --git a/content/general/versions/v1.0/webhooks.textile b/content/general/versions/v1.0/webhooks.textile index 61c4a802a7..21fd308e9e 100644 --- a/content/general/versions/v1.0/webhooks.textile +++ b/content/general/versions/v1.0/webhooks.textile @@ -125,7 +125,7 @@ Each member of @data.presence@ has the following fields: h3(#decoding-presence). Decoding presence events -Each member of @data.presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels are automatically decoded into "@PresenceMessages@":/realtime/types#presence-message object by the Ably client library. With webhooks you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @data.presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded or an individual member of that array. This will transform them into an array of "@PresenceMessages@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). This has several advantages, e.g.: +Each member of @data.presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into "@PresenceMessages@":/realtime/types#presence-message object by the Ably client library. With webhooks you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @data.presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded or an individual member of that array. This will transform them into an array of "@PresenceMessages@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). This has several advantages, e.g.: * It will decode the (numerical) action into a "@Presence action@":/realtime/presence#presence-action string (such as "@enter@", "@update@", or "@leave@") * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) @@ -259,7 +259,7 @@ Each member of @data.messages@ has the following fields: h3(#decoding-messages). Decoding messages -Each member of @data.messages@ is a 'raw' message. Messages sent "over the realtime service":/realtime/channels are automatically decoded into "@Messages@":/realtime/types#message object by the Ably client library. With webhooks you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @data.messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded or an individual member of that array. This will transform them into an array of "@Messages@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). This has several advantages, e.g.: +Each member of @data.messages@ is a 'raw' message. Messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into "@Messages@":/realtime/types#message object by the Ably client library. With webhooks you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @data.messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded or an individual member of that array. This will transform them into an array of "@Messages@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). This has several advantages, e.g.: * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) * If you are using "encryption":/realtime/encryption, you can pass your encryption key to the method and it will decrypt the @data@ for you diff --git a/content/general/versions/v1.1/events/ifttt.textile b/content/general/versions/v1.1/events/ifttt.textile index b9478fa644..9db4040953 100644 --- a/content/general/versions/v1.1/events/ifttt.textile +++ b/content/general/versions/v1.1/events/ifttt.textile @@ -46,7 +46,7 @@ In addition, if you are wanting data to be passed through and processed by IFTTT } ``` -In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. +In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels/overview to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. h2(#example). Example diff --git a/content/general/versions/v1.1/firehose.textile b/content/general/versions/v1.1/firehose.textile index 0e8856871e..bcffd22f88 100644 --- a/content/general/versions/v1.1/firehose.textile +++ b/content/general/versions/v1.1/firehose.textile @@ -6,7 +6,7 @@ index: 26 Our Firehose can stream your realtime data published within the Ably platform directly to another streaming or queueing service. For example, all messages published by any device on a channel could be immediately streamed to Amazon Kinesis allowing you to process this data in realtime. Firehose is offered as part of our "Ably Reactor service":https://www.ably.io/reactor but is only available to "Enterprise customers":https://www.ably.io/pricing/enterprise. -Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. +Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. As each message is delivered once to your streaming or queueing server, this design is commonly used to process realtime data published by Ably asynchronously. For example, using workers consuming from your stream or queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. Find out why we think streams and message queues help solve many of the challenges associated with consuming pub/sub data server-side in our article: "Message queues — the right way to process and work with realtime data on your servers":https://blog.ably.io/message-queues-the-right-way-to-process-and-work-with-realtime-data-on-your-servers-2d15985301f8. diff --git a/content/general/versions/v1.1/queues.textile b/content/general/versions/v1.1/queues.textile index a799d630fd..6c4bcfd6cc 100644 --- a/content/general/versions/v1.1/queues.textile +++ b/content/general/versions/v1.1/queues.textile @@ -46,7 +46,7 @@ All Ably accounts have access to Reactor Queue functionality, however to get sta h3(#provisioning). Provisioning Reactor Queues -Unlike "pub/sub channels":/realtime/channels that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. +Unlike "pub/sub channels":/realtime/channels/overview that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. Queues are setup "within your app dashboard":https://support.ably.io/support/solutions/articles/3000030053-how-do-i-access-my-app-dashboard and you will need to configure: @@ -404,7 +404,7 @@ When using Reactor Queues, please bear in mind that: * There is a default TTL (time-to-live) applied to all messages that is configured when you provision your queue. If a message has not been consumed from a queue within this period, it will be moved to the deadletter queue. If the TTL of the deadletter queue passes, the message is discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * There is a max message limit configured when you provision your queue. If the max message limit is reached for your queue, new messages will be moved to the deadletter queue. Once the deadletter queue reaches its max message limit, new messages will be discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * With the AMQP protocol, it is possible to consume multiple queues from a single connection, and also to consume more than one message at a time. You will need to refer to your client library's documentation to enable these capabilities. See "this StackOverFlow answer":http://stackoverflow.com/a/17011833/139607 as a good starting point. -* Unlike our Ably "pub/sub channels":/realtime/channels which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. +* Unlike our Ably "pub/sub channels":/realtime/channels/overview which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. * Each message published to the queue will count towards you monthly message quota. See "billing info for more details":#below. h3(#scalability-availability). Queue Scalability and High Availability diff --git a/content/mqtt/index.textile b/content/mqtt/index.textile index 4ff76badc7..e94705fc93 100644 --- a/content/mqtt/index.textile +++ b/content/mqtt/index.textile @@ -46,7 +46,7 @@ This will connect using TLS through MQTT to Ably. h2(#pub-sub). Publishing and Subscribing with MQTT -"Ably's channels":/realtime/channels correlate to topics in MQTT. An example of how to publish and subscribe with the NodeJS "MQTT package":https://www.npmjs.com/package/mqtt would be as follows: +"Ably's channels":/realtime/channels/overview correlate to topics in MQTT. An example of how to publish and subscribe with the NodeJS "MQTT package":https://www.npmjs.com/package/mqtt would be as follows: bc[nodejs]. { const mqtt = require('mqtt'); diff --git a/content/partials/types/_channel_state_change.textile b/content/partials/types/_channel_state_change.textile index d3d50a88dc..a8f57fa7bf 100644 --- a/content/partials/types/_channel_state_change.textile +++ b/content/partials/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/partials/versions/v0.8/types/_channel_state_change.textile b/content/partials/versions/v0.8/types/_channel_state_change.textile index ddb7444c5d..035783cf03 100644 --- a/content/partials/versions/v0.8/types/_channel_state_change.textile +++ b/content/partials/versions/v0.8/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/partials/versions/v1.0/types/_channel_state_change.textile b/content/partials/versions/v1.0/types/_channel_state_change.textile index 878d6106c1..666d641852 100644 --- a/content/partials/versions/v1.0/types/_channel_state_change.textile +++ b/content/partials/versions/v1.0/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/partials/versions/v1.1/types/_channel_state_change.textile b/content/partials/versions/v1.1/types/_channel_state_change.textile index d3d50a88dc..a8f57fa7bf 100644 --- a/content/partials/versions/v1.1/types/_channel_state_change.textile +++ b/content/partials/versions/v1.1/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/realtime/channel-metadata.textile b/content/realtime/channels/channel-metadata.textile similarity index 100% rename from content/realtime/channel-metadata.textile rename to content/realtime/channels/channel-metadata.textile diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile new file mode 100644 index 0000000000..8fa589921e --- /dev/null +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -0,0 +1,222 @@ +--- +title: Delta mode subscription +section: realtime +index: 2 +jump_to: + Help with: + - Overview#overview + - Examples#examples + Parameters: + - delta#delta +--- + +h2(#overview). Overview + +Often a channel carries messages that represent a series updates to a particular object or document and, as such, there is a significant degree of similarily between successive messages. Delta mode is a way for a client to subscribe to a channel so that message payloads sent over the wire contain only the difference (ie the delta) between the present message and the previous message on the channel. The client can then apply the delta to the previous message to obtain the full payload. Using delta mode can signficantly reduce the encoded size of each message in the case that message payloads change by differences that are small relative to the size of the value. This reduction in size can reduce bandwidth costs, reduce transit latencies, and enable greater message throughput on a connection. + +The present delta mode implementation supports a single representation of a delta, [VCDIFF](https://tools.ietf.org/html/rfc3284). However, the protocol and API are designed to allow other representations to be used in the future. + +Since version 1.2, Ably libraries support delta subscriptions; subscribing in delta mode is enabled for a given channel by specifying a "delta channel param":/realtime/channels/channel-parameters with the value @vcdiff@. This will cause delta messages to be generated by the server and sent to the client, and the library reconstitutes the original message payload. The end result is that messages on the channel are delivered to the subscriber's listener in just the same way as happens with a normal subscription. + +h2(#delta-processing). Delta processing + +Deltas apply to the principal payload of a @Message@ published via Ably, which is the @data@ member. Other elements of a message, such as @clientId@, @name@, or @extras@ are unchanged by use of deltas and are not compressed. + +Deltas are supported for realtime subscriptions only. Messages retrieved via the history API, and messages delivered to Reactor endpoints, are not compressed. Support for delta-compressed messages via Reactor is under consideration for the future. + +Delta compression via @vcdiff@ is supported for all payloads, whether string or binary, or JSON-encoded. The delta algorithm processes message payloads as opaque binaries and has no dependency on the stucture of the payload - it does not process line-oriented diffs, for example. In principle, @vcdiff@ deltas can be applied to encrypted message payloads, but in practice this provides no benefit because there is no similarity between successive encrypted payloads even on identical or near-identical plaintext message payloads. + +Delta compression is a subscriber-specified option only - the publisher has no control over whether or not deltas are generated for any given message; the processing is performed if there is at least one subscriber on a channel that has requested a delta-mode subscription. + +There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question, for the region in question. When there are multiple publishers in multiple regions, publishing messages nearly simultaneously, the ordering of messages delievred to subscribers can be different in different regions, depending on actual region-to-region transit latencies; in this case, deltas are generated based on the actual message order in each region, and subscribers are delivered a sequence of delta messages that reflects that regional order. + +Delta processing, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. Effectiveness of delta processing - that is, whether or not there is a material saving in payload size - is dependent on the level of similarity between successive payloads. Therefore, if a channel carries messages from multiple sources or streams that are dissimilar, then delta processing might not result in a useful size reduction, even if the messages in each individual stream are similar; it depends on the specific sequence of messages that occurs in the channel, in the region in question. + +If a delta is generated and it results in a difference that is not appreciably smaller than the original message, or is even larger than the original message (which can happen if successive messages are completely different), then the delta will not be sent - clients will receive the original, unprocessed message. Therefore, in general, the sequence of messages that will be delivered to a client for any given channel will be a combination of regular messages and delta-compressed messages, with the delta messages only being present when they achieve a payload size reduction in comparison with the unmodified message. + +On some occasions a channel subscriber can experience a discontinuity in the sequence of messages it receives on any given channel. There are several possible reasons for this: the connection can drop, and there will be a discontinuity of the client is unable to reconnect within the two-minute window it is allowed to preserve connection continuity; the outbound connection might have been rate-limited, which causes some messages to be dropped; or there might have been some internal error in the Ably system which leads to the server being unable to preserve continuity on the channel. In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. If a subscriber has a delta-mode subscription and the channel in question experiences a discontunity, then a non-delta message will be delivered to the client as the first message after the discontinuity, so that lost messages do not prevent the client from reconstituting messages from deltas. + +h2(#using-deltas). Using deltas + +h3(#using-deltas-12). Via an Ably library from v1.2 (via the delta channel parameter) + +The most common way to subscribe to Ably channels is via a realtime connection, using an Ably realtime library. + +From version 1.2, Ably libraries support the ability to subscribe to a channel in delta mode. For many libraries this requires no change on the part of the caller except to specify the "delta channel param":/realtime/channels/channel-parameters when subscribing to the channel. In some libraries, the @vcdiff@ delta decoding library is excluded from the default library distribution in order to avoid bloating the library; in these cases, it is also necessary to supply the delta decoder plugin when instancing the Ably library. + + +```[jsall] + const vcdiffPlugin = require('{{vcdiff-plugin}}') + const realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); + realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { + delta: 'vcdiff' + }).subscribe(msg => console.log("Received message: ", msg)); +``` + +```[java] + AblyRealtime ably = new AblyRealtime("{{API_KEY}}"") + Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", new ChannelOptions{{params = Map.of("delta", "vcdiff")}}); + channel.subscribe(new MessageListener() { + @Override + public void onMessage(Message message) { + System.out.println("Received `" + message.name + "` message with data: " + message.data); + } + }); +``` + +```[obj-c] +TBD +``` + +```[dotnet] +TBD +``` + +h3(#using-deltas-11). Via an Ably library before v1.2 (via a qualified channel name) + +```[jsall] + const realtime = new Ably.Realtime({key: '{{API_KEY}}'}); + const channel = realtime.channels.get('[?delta=vcdiff]{{RANDOM_CHANNEL_NAME}}'); + channel.subscribe(msg => console.log("Received message: ", msg)); +``` + +```[java] + AblyRealtime ably = new AblyRealtime("{{API_KEY}}"") + Channel channel = ably.channels.get("[?delta=vcdiff]{{RANDOM_CHANNEL_NAME}}"); + channel.subscribe(new MessageListener() { + @Override + public void onMessage(Message message) { + System.out.println("Received `" + message.name + "` message with data: " + message.data); + } + }); +``` + +```[obj-c] +TBD +``` + +```[dotnet] +TBD +``` + +h3(#using-deltas-non-ably). Via a subscription that does not use an Ably library + +If subscribing to a channel in delta mode using [SSE](https://www.ably.io/documentation/sse) or one of the protocol adaptors such as [MQTT](https://www.ably.io/documentation/mqtt), then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the [download](https://www.ably.io/download) section for details. If you need to decode @vcdiff@-formatted delta messages in languages for which there is no decoder available from Ably, then any compliant open-source implementation of the standard will work. + +Messages that contain a @vcdiff@ delta have that delta payload in their @data@ attribute; in the case of @vcdiff@ deltas this will be a binary value, even if the @data@ in the original meessage was text. in addition, there is metadata in the message @extras@ attribute that indicate that the payload is a delta, and which message the delta is relative to. The format of the `extras` attribute is as follows: + +```[jsall] + +extras: { + format: 'vcdiff', + from: '{{previous message id}}' +} +``` + +In order to reconstruct the original message, the @vcdiff@ decoder algorithm needs to be applied to the given @data@ @vcdiff@ value, together with the @data@ for the previous message (on the assumption that that message had already beein decoded if it itself was also a delta). If the original form of the present message was text, then this is indicated in the `encoding` attribute of the message, so the original text can be reconstructed by @utf-8@ decoding, once the @vcdiff@ decoding is complete. The decoder libraries that are available to [download]() simplify this process, and more detailed information can be found in the @README@ of each of those libraries. + +When subscribing without an Ably library, then the channel @delta@ param must be specified using a "qualified channel name":/realtime/channels/channel-parameters. In the case of [SSE](https://www.ably.io/documentation/sse), it is also possible to specify channel params as regular query params on the connection URL. + +Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. Examples of such transports are [MQTT](https://www.ably.io/documentation/mqtt), and [SSE](https://www.ably.io/documentation/sse) in non-enveloped mode. In order to assist applications that use these transports, the @vcdiff@ decoder libraries can check for the @vcdiff@ magic number at the start of the message payload as an inexact method of determining whether or not the message is a regular message or a delta. Note that, in order to rely on that check, you need to know that that magic number will not be present in any valid (uncompressed) message in your app. No valid JSON value, for example, will match the @vcdiff@ header check, so it is safe to perform this sniffing on JSON message payloads. + +h4(#delta-example-sse). Delta example with SSE + +You can subscribe to messages in delta mode, using the [SSE](https://www.ably.io/documentation/sse) transport, as follows. + + +``` +(() => { + const key = '{{API_KEY}}'; + const channel = 'sample-app-sse'; + const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; + const eventSource = new EventSource(url); + const channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); + + eventSource.onmessage = (event) => { + /* event.data is JSON-encoded Ably Message (see https://www.ably.io/documentation/realtime/types#message) */ + const message = JSON.parse(event.data); + const { id, extras } = message; + let { data } = message; + + try { + if (extras && extras.delta) { + data = channelDecoder.applyBase64Delta(data, id, extras.delta.from).asUtf8String(); + } else { + channelDecoder.setBase(data, id); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); + }; +})(); +``` + +h4(#delta-example-unenv-sse). Delta example with unenveloped SSE + +```(() => { + const key = '{{API_KEY}}'; + const channel = 'sample-app-sse'; + const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; + const eventSource = new EventSource(url); + const channelDecoder = new DeltaCodec.VcdiffDecoder(); + + eventSource.onmessage = (event) => { + let data = event.data; + + try { + if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { + data = channelDecoder.applyBase64Delta(data).asUtf8String(); + } else { + channelDecoder.setBase(data); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); + }; +})(); +``` + +h4(#delta-example-mqtt). Delta example with MQTT + +``` +const mqtt = require('mqtt'); +const { VcdiffDecoder } = require('./lib'); + +const options = { + keepalive: 30, + username: 'FIRST_HALF_OF_API_KEY', + password: 'SECOND_HALF_OF_API_KEY', + port: 8883 +}; +const client = mqtt.connect('mqtts:mqtt.ably.io', options); +const channelName = 'sample-app-mqtt'; +const channelDecoder = new VcdiffDecoder(); + +client.on('message', (_, payload) => { + let data = payload; + + try { + if (VcdiffDecoder.isDelta(data)) { + data = channelDecoder.applyDelta(data).asUint8Array(); + } else { + channelDecoder.setBase(data); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); +}); + +client.subscribe(`[?delta=vcdiff]${channelName}`); +``` diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile new file mode 100644 index 0000000000..8465867df9 --- /dev/null +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -0,0 +1,247 @@ +--- +title: Channel Parameters +section: realtime +index: 1 +jump_to: + Help with: + - Overview#overview + - Using params with v1.1 or earlier Ably libraries#using-params-with-lib-v11 + - Using params with non-Ably transports#using-params-with-other-transports + - Examples#examples + Parameters: + - rewind#rewind +--- + +h2(#overview). Overview + +Channel parameters are a general mechanism by which a client can express properties of a channel, or of its attachment to a channel. A set of channel parameters is simply a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines. + +The methods provided for specifying channel parameters, and the currently available features, are outlined below. + +h2(#supported-params). Currently supported channel params + +- rewind := Used to request that an attachment start from some number of messages or point in time in the past. See "rewind":#rewind for more information +- delta := **In an experimental state**. Used to request that data payloads should be sent as deltas to the previous payload. "Contact us":https://www.ably.io/contact for more information and supported values + +h2(#using-params-with-lib-v11). Using channel params with v1.1 or earlier Ably client libraries + +The current Ably libraries, at version 1.1, do not expose an API for expressing channel parameters. This means that it is necessary to specify parameters in a way that is opaque to the library. + +A set of params is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. + +For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. + +Using this syntax with the Ably library means that channel parameters are specified for the lifetime of the @Channel@ instance; in order to reference the same channel, but with different channel parameters, it is necessary to get a new @Channel@ instance, using a qualified name that includes the new channel parameters. + +h3. Example + +For example, to specify the @rewind@ channel param with the value @"1"@: + +```[javascript] + const realtime = new Ably.Realtime('{{API_KEY}}'); + const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); +``` + +h2(#using-params-with-other-transports). Using params with non-Ably transports + +It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. + +A set of params is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. + +For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. + +In an SSE connection, it is also possible to specify channel parameters as a query string in the connection URL, instead of as a qualifier on an individual channel name. In this case, the given channel parameters apply to all channel attachments associated with that connection. + +h3. SSE example + +For example, to specify the @rewind@ channel param with the value @"1"@ using a querystring parameter, where it will apply to all channels: + +```[javascript] +var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; +var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); +``` + +Or to specify the same parameter but only applying to one channel of two, using a qualified channel name: + +```[javascript] + var channelOne = encodeURIComponent('[?rewind=1]channel1'); + var channelTwo = 'channel2'; + var channels = channelOne + ',' + channelTwo; + var querystring = 'v=1.2&key={{API_KEY}}&channels=' + channels'; + var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); +``` + +h2(#rewind). Rewind parameter + +The @rewind@ channel parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). + +A @rewind@ parameter can express a channel position in terms of a number of messages, or a time interval. + +A @rewind@ value that is simply a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If that attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. + +If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. + +A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. + +If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel param. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. + +At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. + +By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + +The channel position expressed by a @rewind@ parameter has an effect only on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). + +Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier represents an error, and any attachment request will fail with an error. + +h3(#rewind-example-ably). Rewind example with an Ably client library + +To subscribe to a channel, getting the most recent message if available: + +```[jsall] + // only with ably-js v1.2 or later + const realtime = new Ably.Realtime('{{API_KEY}}'); + realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { + rewind: '1' + }).subscribe(msg => console.log("Received message: ", msg)); +``` + +```[jsall] + // with ably-js v1.1 or below + const realtime = new Ably.Realtime('{{API_KEY}}'); + const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); + channel.subscribe(msg => console.log("Received message: ", msg)); +``` + +h3(#rewind-example-sse). Rewind example with SSE + +To subscribe to a channel, getting the most recent message if available: + +```[javascript] + var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; + var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); +``` + +h3(#rewind-examples-mqtt). Rewind example with MQTT + +```[nodejs] + var mqtt = require('mqtt'); + var options = { + keepalive: 30, + username: 'FIRST_HALF_OF_API_KEY', + password: 'SECOND_HALF_OF_API_KEY', + port: 8883 + }; + var client = mqtt.connect('mqtts:mqtt.ably.io', options); + client.on('connect', () => { + client.subscribe('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); + }); + client.on('message', (topic, message) => { + ... + }); +``` + +h2(#delta). Delta parameter + +The @delta@ channel parameter allows subscribers to expresse their desire to receive deltas (diffs) between the previous and current message instead of the current message in full on a given channel. The effects of this parameter are invisible to message senders and only affect subscribers that specify it - i.e. the sender sends messages in full and Ably computes and sends the message deltas to any subscriber which subscribed using this parameter. + +Note that requesting deltas does not guarantee that every message received will be a delta, as the server may chose to send some messages in full depending on system load and other factors. Therefore a subscriber using the @delta@ parameter should be prepared to handle a random mix of delta and full messages. + +The @delta@ parameter can take only the value @vcdiff@. VCDIFF is the format of the deltas. It is an open format specified in "RFC 3284":https://tools.ietf.org/html/rfc3284. + +Ably provides a JavaScript "delta codec library":https://github.com/ably/delta-codec-js to help you avoid writing boilerplate VCDIFF handling code. Some examples follow. + +h3(#delta-example-sse). Delta example with enveloped SSE + +```[jsall] +const key = '{{API_KEY}}'; +const channel = 'sample-app-sse'; +const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.2&key=${key}&delta=vcdiff`; +const eventSource = new EventSource(url); +const channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); + +eventSource.onmessage = (event) => { + /* event.data is JSON-encoded Ably Message (see https://www.ably.io/documentation/realtime/types#message) */ + const message = JSON.parse(event.data); + const { id, extras } = message; + let { data } = message; + + try { + if (extras && extras.delta) { + data = channelDecoder.applyBase64Delta(data, id, extras.delta.from).asUtf8String(); + } else { + channelDecoder.setBase(data, id); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); +}; +``` + +h3(#delta-example-unenv-sse). Delta example with unenveloped SSE + +```[jsall] +const key = '{{API_KEY}}'; +const channel = 'sample-app-sse'; +const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.2&key=${key}&delta=vcdiff&enveloped=false`; +const eventSource = new EventSource(url); +const channelDecoder = new DeltaCodec.VcdiffDecoder(); + +eventSource.onmessage = (event) => { + let data = event.data; + + try { + if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { + data = channelDecoder.applyBase64Delta(data).asUtf8String(); + } else { + channelDecoder.setBase(data); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); +}; +``` + +h3(#delta-example-mqtt). Delta example with MQTT + +```[jsall] +const mqtt = require('mqtt'); +const { VcdiffDecoder } = require('./lib'); + +const options = { + keepalive: 30, + username: 'FIRST_HALF_OF_API_KEY', + password: 'SECOND_HALF_OF_API_KEY', + port: 8883 +}; +const client = mqtt.connect('mqtts:mqtt.ably.io', options); +const channelName = 'sample-app-mqtt'; +const channelDecoder = new VcdiffDecoder(); + +client.on('message', (_, payload) => { + let data = payload; + + try { + if (VcdiffDecoder.isDelta(data)) { + data = channelDecoder.applyDelta(data).asUint8Array(); + } else { + channelDecoder.setBase(data); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); +}); + +client.subscribe(`[?delta=vcdiff]${channelName}`); +``` diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile new file mode 100644 index 0000000000..416e31765d --- /dev/null +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -0,0 +1,79 @@ +--- +title: Rewind +section: realtime +index: 3 +jump_to: + Help with: + - Overview#overview +--- + +h2(#overview). Overview + +Channels support a parameter that applies at the time of attachment that requests that an attachment start from some number of messages or point in time in the past. The @rewind@ param is specified via the "channel params":/realtime/channels/channel-parameters mechanism. + +The @rewind@ channel parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). + +A @rewind@ parameter can express a channel position in terms of a number of messages, or a time interval. + +A @rewind@ value that is simply a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If that attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. + +If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. + +A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. + +If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel param. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. + +At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. + +By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + +The channel position expressed by a @rewind@ parameter has an effect only on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). + +Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier represents an error, and any attachment request will fail with an error. + +h3(#rewind-example-ably). Rewind example with an Ably client library + +To subscribe to a channel, getting the most recent message if available: + +```[jsall] + // only with ably-js v1.2 or later + const realtime = new Ably.Realtime('{{API_KEY}}'); + realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { + rewind: '1' + }).subscribe(msg => console.log("Received message: ", msg)); +``` + +```[jsall] + // with ably-js v1.1 or below + const realtime = new Ably.Realtime('{{API_KEY}}'); + const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); + channel.subscribe(msg => console.log("Received message: ", msg)); +``` + +h3(#rewind-example-sse). Rewind example with SSE + +To subscribe to a channel, getting the most recent message if available: + +```[javascript] + var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; + var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); +``` + +h3(#rewind-examples-mqtt). Rewind example with MQTT + +```[nodejs] + var mqtt = require('mqtt'); + var options = { + keepalive: 30, + username: 'FIRST_HALF_OF_API_KEY', + password: 'SECOND_HALF_OF_API_KEY', + port: 8883 + }; + var client = mqtt.connect('mqtts:mqtt.ably.io', options); + client.on('connect', () => { + client.subscribe('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); + }); + client.on('message', (topic, message) => { + ... + }); +``` diff --git a/content/realtime/channels.textile b/content/realtime/channels/overview.textile similarity index 98% rename from content/realtime/channels.textile rename to content/realtime/channels/overview.textile index 0332e35ed4..f1567d900d 100644 --- a/content/realtime/channels.textile +++ b/content/realtime/channels/overview.textile @@ -238,14 +238,14 @@ channel.subscribe { message in h4(#rewind). Subscribing to a channel with the rewind option enabled -It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-params#rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. +It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-parameters#rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. minimize. View details - "Rewind":/realtime/channel-params has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. + "Rewind":/realtime/channel-parameters has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. - In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-params with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-params documentation. + In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel parameters directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-parameters with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-parameters documentation. - *Note* that "rewind":/realtime/channel-params is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + *Note* that "rewind":/realtime/channel-parameters is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. In addition, rewind will only apply upon *attaching* to a channel, so any subsequent subscriptions post-attach will not fetch old messages. diff --git a/content/realtime/encryption.textile b/content/realtime/encryption.textile index 3bb493d4d6..2160fa922d 100644 --- a/content/realtime/encryption.textile +++ b/content/realtime/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/history.textile b/content/realtime/history.textile index 64bea8d240..d5d4a859dd 100644 --- a/content/realtime/history.textile +++ b/content/realtime/history.textile @@ -130,7 +130,7 @@ If you would prefer to just dive into code and see some examples of how to use h h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history @@ -142,11 +142,11 @@ To enable history on a channel, it is necessary to add a channel rule in the set h3(#continuous-history). Continuous history -By using "rewind":/realtime/channel-params#rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. +By using "rewind":/realtime/channel-parameters#rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. h4(#rewind). Rewind -If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-params#rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-params#rewind for further details. +If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-parameters#rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-parameters#rewind for further details. In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if the channel were @[some_metadata]my_channel@, you would specify the use of rewind via @[some_metadata?rewind=1]my_channel@. You can specify either a number of messages up to 100 to rewind to (for example @10@), or a time specifier of either seconds (@10s@), or minutes (@2m@) up to 2 minutes. diff --git a/content/realtime/index.textile b/content/realtime/index.textile index c88fb8da68..a69921ee9b 100644 --- a/content/realtime/index.textile +++ b/content/realtime/index.textile @@ -27,7 +27,7 @@ These concepts are illustrated in the diagram below: An Ably Realtime client library is responsible for: - Connection state management := Actively managing the "WebSocket":/concepts/websockets connection by reconnecting "automatically to an available datacenter":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues when a connection drops and restoring the connection state. Find out more about "the connection object and its state":/realtime/connection and "connection state recovery which provides message continuity over changing network conditions":https://support.ably.io/solution/articles/3000044639-connection-state-recovery. -- Channel management := Providing "publish and subscribe":/realtime/channels capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. +- Channel management := Providing "publish and subscribe":/realtime/channels/overview capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. - Presence := Allowing a client to "register itself as present on a channel":/realtime/presence and actively ensuring all members present on a channel are kept in-sync locally. The library proactively restores presence state on suspended channels due to long periods of disconnectedness. - Data interoperabilty := Ensuring messages and their payloads (JSON, strings or binary data) are encoded and decoded in a uniform way to ensure interoperability between all supported platforms. - Encryption := "Encrypting payloads with the optional user-generated encryption key":/realtime/encryption ensuring payloads cannot be decrypted whilst in transit or by any party without the private key. diff --git a/content/realtime/messages.textile b/content/realtime/messages.textile index ed9613264c..1c2725ec3b 100644 --- a/content/realtime/messages.textile +++ b/content/realtime/messages.textile @@ -34,7 +34,7 @@ The Ably Realtime service allows for clients to send information with @messages@ h2(#getting-started). Getting started -The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels does not exist at the time the client is attached, a "channel":/realtime/channels will be created in the Ably system immediately. +The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels/overview does not exist at the time the client is attached, a "channel":/realtime/channels/overview will be created in the Ably system immediately. ```[javascript](code-editor:realtime/channel-publish) var realtime = new Ably.Realtime('{{API_KEY}}'); diff --git a/content/realtime/presence.textile b/content/realtime/presence.textile index f44a674c29..57295f23f3 100644 --- a/content/realtime/presence.textile +++ b/content/realtime/presence.textile @@ -41,7 +41,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/usage.textile b/content/realtime/usage.textile index 7043e01c58..95b5ecffac 100644 --- a/content/realtime/usage.textile +++ b/content/realtime/usage.textile @@ -262,7 +262,7 @@ h6(#channels). default: channels csharp: Channels -"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels and "messages":/realtime/messages/ for more information. +"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels/overview and "messages":/realtime/messages/ for more information. h6(#connection). default: connection diff --git a/content/realtime/versions/v0.8/encryption.textile b/content/realtime/versions/v0.8/encryption.textile index 74c88101bc..d521e7302d 100644 --- a/content/realtime/versions/v0.8/encryption.textile +++ b/content/realtime/versions/v0.8/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/versions/v0.8/history.textile b/content/realtime/versions/v0.8/history.textile index 80b615b653..6ca5a98f9d 100644 --- a/content/realtime/versions/v0.8/history.textile +++ b/content/realtime/versions/v0.8/history.textile @@ -121,7 +121,7 @@ channel.publish("example", data: "message data") { error in h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history @@ -227,7 +227,7 @@ inline-toc. h2. Channel object -The "Realtime @Channel@ object":/realtime/channels exposes the following public method to obtain "@Message@":#message history. +The "Realtime @Channel@ object":/realtime/channels/overview exposes the following public method to obtain "@Message@":#message history. h3. Methods diff --git a/content/realtime/versions/v0.8/index.textile b/content/realtime/versions/v0.8/index.textile index a8b6cc004c..c3eafd5390 100644 --- a/content/realtime/versions/v0.8/index.textile +++ b/content/realtime/versions/v0.8/index.textile @@ -4,7 +4,7 @@ section: realtime index: 0 --- -The Ably Realtime client libraries establish and maintain a persistent connection to Ably enabling extremely low latency broadcasting of messages and presence state. All official client library APIs are consistent across every language, provide "pub/sub functionality":/realtime/channels and "presence on channels":/realtime/presence, handle both "basic and token authentication":/realtime/authentication, "manage changing network conditions":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues, include optional "symmetric encryption":/realtime/encryption and provide access to "channel, presence and metrics history":/realtime/history. +The Ably Realtime client libraries establish and maintain a persistent connection to Ably enabling extremely low latency broadcasting of messages and presence state. All official client library APIs are consistent across every language, provide "pub/sub functionality":/realtime/channels/overview and "presence on channels":/realtime/presence, handle both "basic and token authentication":/realtime/authentication, "manage changing network conditions":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues, include optional "symmetric encryption":/realtime/encryption and provide access to "channel, presence and metrics history":/realtime/history. The Ably Realtime client library is available in "most popular languages and platforms":https://www.ably.io/download including "Javascript browser library":https://github.com/ably/ably-js, "Java":https://github.com/ably/ably-java, ".NET":https://github.com/ably/ably-dotnet, "Node.js":https://github.com/ably/ably-js, "iOS":https://github.com/ably/ably-ios, "Ruby":https://github.com/ably/ably-ruby, "Go":https://github.com/ably/ably-go and "more...":https://www.ably.io/download diff --git a/content/realtime/versions/v0.8/presence.textile b/content/realtime/versions/v0.8/presence.textile index 889e30aa22..8bcd2fc3ad 100644 --- a/content/realtime/versions/v0.8/presence.textile +++ b/content/realtime/versions/v0.8/presence.textile @@ -38,7 +38,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/versions/v0.8/usage.textile b/content/realtime/versions/v0.8/usage.textile index 8db5d046f3..14815aa715 100644 --- a/content/realtime/versions/v0.8/usage.textile +++ b/content/realtime/versions/v0.8/usage.textile @@ -291,7 +291,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/realtime/channels and "messages":/realtime/messages for more information. +A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/realtime/channels/overview and "messages":/realtime/messages for more information. h6(#client-id). default: clientId diff --git a/content/realtime/versions/v1.0/encryption.textile b/content/realtime/versions/v1.0/encryption.textile index e0679bd130..20bc546d0c 100644 --- a/content/realtime/versions/v1.0/encryption.textile +++ b/content/realtime/versions/v1.0/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/versions/v1.0/history.textile b/content/realtime/versions/v1.0/history.textile index 2d0d69d9dd..a8ff464f99 100644 --- a/content/realtime/versions/v1.0/history.textile +++ b/content/realtime/versions/v1.0/history.textile @@ -130,7 +130,7 @@ If you would prefer to just dive into code and see some examples of how to use h h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history diff --git a/content/realtime/versions/v1.0/index.textile b/content/realtime/versions/v1.0/index.textile index 563d681832..b0e8d73af7 100644 --- a/content/realtime/versions/v1.0/index.textile +++ b/content/realtime/versions/v1.0/index.textile @@ -27,7 +27,7 @@ These concepts are illustrated in the diagram below: An Ably Realtime client library is responsible for: - Connection state management := Actively managing the "WebSocket":/concepts/websockets connection by reconnecting "automatically to an available datacenter":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues when a connection drops and restoring the connection state. Find out more about "the connection object and its state":/realtime/connection and "connection state recovery which provides message continuity over changing network conditions":https://support.ably.io/solution/articles/3000044639-connection-state-recovery. -- Channel management := Providing "publish and subscribe":/realtime/channels capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. +- Channel management := Providing "publish and subscribe":/realtime/channels/overview capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. - Presence := Allowing a client to "register itself as present on a channel":/realtime/presence and actively ensuring all members present on a channel are kept in-sync locally. The library proactively restores presence state on suspended channels due to long periods of disconnectedness. - Data interoperabilty := Ensuring messages and their payloads (JSON, strings or binary data) are encoded and decoded in a uniform way to ensure interoperability between all supported platforms. - Encryption := "Encrypting payloads with the optional user-generated encryption key":/realtime/encryption ensuring payloads cannot be decrypted whilst in transit or by any party without the private key. diff --git a/content/realtime/versions/v1.0/messages.textile b/content/realtime/versions/v1.0/messages.textile index 23b7b5ba55..3a84116ea4 100644 --- a/content/realtime/versions/v1.0/messages.textile +++ b/content/realtime/versions/v1.0/messages.textile @@ -34,7 +34,7 @@ The Ably Realtime service allows for clients to send information with @messages@ h2(#getting-started). Getting started -The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels does not exist at the time the client is attached, a "channel":/realtime/channels will be created in the Ably system immediately. +The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels/overview does not exist at the time the client is attached, a "channel":/realtime/channels/overview will be created in the Ably system immediately. ```[javascript](code-editor:realtime/channel-publish) var realtime = new Ably.Realtime('{{API_KEY}}'); diff --git a/content/realtime/versions/v1.0/presence.textile b/content/realtime/versions/v1.0/presence.textile index 0c91215230..f149817fec 100644 --- a/content/realtime/versions/v1.0/presence.textile +++ b/content/realtime/versions/v1.0/presence.textile @@ -41,7 +41,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/versions/v1.0/usage.textile b/content/realtime/versions/v1.0/usage.textile index 336bfc33b2..4dd7b42754 100644 --- a/content/realtime/versions/v1.0/usage.textile +++ b/content/realtime/versions/v1.0/usage.textile @@ -247,7 +247,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/realtime/channels and "messages":/realtime/messages/ for more information. +A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/realtime/channels/overview and "messages":/realtime/messages/ for more information. h6(#client-id). default: clientId diff --git a/content/realtime/versions/v1.1/encryption.textile b/content/realtime/versions/v1.1/encryption.textile index 3bb493d4d6..2160fa922d 100644 --- a/content/realtime/versions/v1.1/encryption.textile +++ b/content/realtime/versions/v1.1/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/versions/v1.1/history.textile b/content/realtime/versions/v1.1/history.textile index 64bea8d240..07e2a2e08b 100644 --- a/content/realtime/versions/v1.1/history.textile +++ b/content/realtime/versions/v1.1/history.textile @@ -130,7 +130,7 @@ If you would prefer to just dive into code and see some examples of how to use h h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history diff --git a/content/realtime/versions/v1.1/index.textile b/content/realtime/versions/v1.1/index.textile index c88fb8da68..a69921ee9b 100644 --- a/content/realtime/versions/v1.1/index.textile +++ b/content/realtime/versions/v1.1/index.textile @@ -27,7 +27,7 @@ These concepts are illustrated in the diagram below: An Ably Realtime client library is responsible for: - Connection state management := Actively managing the "WebSocket":/concepts/websockets connection by reconnecting "automatically to an available datacenter":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues when a connection drops and restoring the connection state. Find out more about "the connection object and its state":/realtime/connection and "connection state recovery which provides message continuity over changing network conditions":https://support.ably.io/solution/articles/3000044639-connection-state-recovery. -- Channel management := Providing "publish and subscribe":/realtime/channels capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. +- Channel management := Providing "publish and subscribe":/realtime/channels/overview capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. - Presence := Allowing a client to "register itself as present on a channel":/realtime/presence and actively ensuring all members present on a channel are kept in-sync locally. The library proactively restores presence state on suspended channels due to long periods of disconnectedness. - Data interoperabilty := Ensuring messages and their payloads (JSON, strings or binary data) are encoded and decoded in a uniform way to ensure interoperability between all supported platforms. - Encryption := "Encrypting payloads with the optional user-generated encryption key":/realtime/encryption ensuring payloads cannot be decrypted whilst in transit or by any party without the private key. diff --git a/content/realtime/versions/v1.1/messages.textile b/content/realtime/versions/v1.1/messages.textile index ed9613264c..1c2725ec3b 100644 --- a/content/realtime/versions/v1.1/messages.textile +++ b/content/realtime/versions/v1.1/messages.textile @@ -34,7 +34,7 @@ The Ably Realtime service allows for clients to send information with @messages@ h2(#getting-started). Getting started -The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels does not exist at the time the client is attached, a "channel":/realtime/channels will be created in the Ably system immediately. +The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels/overview does not exist at the time the client is attached, a "channel":/realtime/channels/overview will be created in the Ably system immediately. ```[javascript](code-editor:realtime/channel-publish) var realtime = new Ably.Realtime('{{API_KEY}}'); diff --git a/content/realtime/versions/v1.1/presence.textile b/content/realtime/versions/v1.1/presence.textile index f44a674c29..57295f23f3 100644 --- a/content/realtime/versions/v1.1/presence.textile +++ b/content/realtime/versions/v1.1/presence.textile @@ -41,7 +41,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/versions/v1.1/usage.textile b/content/realtime/versions/v1.1/usage.textile index c640dd5091..e3b3fd73a4 100644 --- a/content/realtime/versions/v1.1/usage.textile +++ b/content/realtime/versions/v1.1/usage.textile @@ -262,7 +262,7 @@ h6(#channels). default: channels csharp: Channels -"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels and "messages":/realtime/messages/ for more information. +"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels/overview and "messages":/realtime/messages/ for more information. h6(#connection). default: connection diff --git a/content/rest/versions/v0.8/usage.textile b/content/rest/versions/v0.8/usage.textile index fa8b6b3214..1bdbae579d 100644 --- a/content/rest/versions/v0.8/usage.textile +++ b/content/rest/versions/v0.8/usage.textile @@ -238,7 +238,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. +A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. h6(#client-id). default: clientId diff --git a/content/rest/versions/v1.0/usage.textile b/content/rest/versions/v1.0/usage.textile index 75c67a2edf..9942830a03 100644 --- a/content/rest/versions/v1.0/usage.textile +++ b/content/rest/versions/v1.0/usage.textile @@ -274,7 +274,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. +A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. h6(#client-id). default: clientId diff --git a/content/root/best-practice-guide.textile b/content/root/best-practice-guide.textile index 4b3fadcae5..afe101c81c 100644 --- a/content/root/best-practice-guide.textile +++ b/content/root/best-practice-guide.textile @@ -21,7 +21,7 @@ Ably Realtime is a cloud-based platform that allows you to easily integrate real h3(#pubsub). Publish and Subscribe (Pub/Sub) -You can publish data to named "channels":/realtime/channels within Ably's platform and the platform will make sure that all clients subscribed to these channels will receive the data in realtime. +You can publish data to named "channels":/realtime/channels/overview within Ably's platform and the platform will make sure that all clients subscribed to these channels will receive the data in realtime. h3(#notifications). Notifications diff --git a/content/tutorials/channel-enumeration-rest.textile b/content/tutorials/channel-enumeration-rest.textile index e535f424b4..fa4ea862ed 100644 --- a/content/tutorials/channel-enumeration-rest.textile +++ b/content/tutorials/channel-enumeration-rest.textile @@ -152,7 +152,7 @@ Make sure that you've enabled the channel metadata permission on your API key. h2(#next-steps). Next Steps -1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels & "messages":https://www.ably.io/documentation/realtime/messages documentation. +1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels/overview & "messages":https://www.ably.io/documentation/realtime/messages documentation. 2. If you would like to check out the other related tutorials to work with channel metadata, see the "Channel Lifecycle Events":/tutorials/channel-lifecycle-events and "Channel Occupancy Events":/tutorials/channel-occupancy-events tutorials. 3. Learn more about "Ably features":https://www.ably.io/features by going through our other "Ably tutorials":https://www.ably.io/tutorials 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/channel-lifecycle-events.textile b/content/tutorials/channel-lifecycle-events.textile index 6b32e8d5c7..2610561b4d 100644 --- a/content/tutorials/channel-lifecycle-events.textile +++ b/content/tutorials/channel-lifecycle-events.textile @@ -177,7 +177,7 @@ h2(#live-demo). Step - 5 Live Demo h2(#next-steps). Next Steps -1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels & "messages":https://www.ably.io/documentation/realtime/messages documentation. +1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels/overview & "messages":https://www.ably.io/documentation/realtime/messages documentation. 2. If you would like to check out the other related tutorials to work with channel metadata, see the "Channel Occupancy Events":/tutorials/channel-occupancy-events and "Channel Enumeration":/tutorials/channel-enumeration-rest tutorials . 3. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/channel-occupancy-events.textile b/content/tutorials/channel-occupancy-events.textile index 9e6c74a191..d4f592a34b 100644 --- a/content/tutorials/channel-occupancy-events.textile +++ b/content/tutorials/channel-occupancy-events.textile @@ -223,7 +223,7 @@ Ably Channel Occupancy Events - Demo h2(#next-steps). Next Steps -1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels & "messages":https://www.ably.io/documentation/realtime/messages documentation. +1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels/overview & "messages":https://www.ably.io/documentation/realtime/messages documentation. 2. If you would like to check out the other related tutorials to work with channel metadata, see the "Channel Lifecycle Events":/tutorials/channel-lifecycle-events and "Channel Enumeration":/tutorials/channel-enumeration-rest tutorials. 3. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/newsfeed-react.textile b/content/tutorials/newsfeed-react.textile index 543ec4de9b..a900a6f389 100644 --- a/content/tutorials/newsfeed-react.textile +++ b/content/tutorials/newsfeed-react.textile @@ -570,7 +570,7 @@ To try this example yourself, @@ -792,7 +792,7 @@ blang[python]. h2(#next-steps). Next steps -1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels & "messages":/realtime/messages documentation +1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels/overview & "messages":/realtime/messages documentation 2. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 3. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works 4. "Get in touch if you need help":https://www.ably.io/contact diff --git a/content/tutorials/reactjs-realtime-commenting.textile b/content/tutorials/reactjs-realtime-commenting.textile index 23499ff368..a2701d507e 100644 --- a/content/tutorials/reactjs-realtime-commenting.textile +++ b/content/tutorials/reactjs-realtime-commenting.textile @@ -474,7 +474,7 @@ to start the web server and open the browser. h2. Next steps -1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels & "messages":/realtime/messages documentation +1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels/overview & "messages":/realtime/messages documentation 2. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 3. Learn more about Ably's "history feature":https://www.ably.io/tutorials/history#lang-javascript 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/sse-and-http-streaming.textile b/content/tutorials/sse-and-http-streaming.textile index 3be96f190c..3e015a5936 100644 --- a/content/tutorials/sse-and-http-streaming.textile +++ b/content/tutorials/sse-and-http-streaming.textile @@ -192,7 +192,7 @@ blang[python]. print("Channel: %s - Message: %s - %s " % (message['channel'], message['name'], message['data'])) ``` - Here, we defined the @apiKey@ variable, which should be replaced with your Ably API key. We then defined our Ably "channels":/realtime/channels with a variable named @channels@. We've added a simple check to see if the API key was in fact replaced. Next, we defined a variable called @url@, which is a template string, feeding in our @apiKey@ and @channels@. Notice that the route of this URL is @/sse@, which means we want to listen to the HTTP event streams from the server. + Here, we defined the @apiKey@ variable, which should be replaced with your Ably API key. We then defined our Ably "channels":/realtime/channels/overview with a variable named @channels@. We've added a simple check to see if the API key was in fact replaced. Next, we defined a variable called @url@, which is a template string, feeding in our @apiKey@ and @channels@. Notice that the route of this URL is @/sse@, which means we want to listen to the HTTP event streams from the server. We then feed this URL to our @with_urllib3@ function, which attempts to fetch the stream, then passing the response to our @sseclient@, listening for the events. Once we get any of these events, we print the details to our console. To see this in action, run the python file with the @pythong subscriber.py@ command. You should get a log of new messages being published by the publisher we earlier set up. Note that in our subscriber, we've not included the Ably SDK but directly subscribed to the data stream. diff --git a/content/tutorials/trainapp-fitbit.textile b/content/tutorials/trainapp-fitbit.textile index 2f7dc5f762..859c497ae4 100644 --- a/content/tutorials/trainapp-fitbit.textile +++ b/content/tutorials/trainapp-fitbit.textile @@ -559,7 +559,7 @@ to start the web server and open the browser. h2. Next steps -1. If you would like to find out more about how channels and how publishing & subscribing works, see the realtime "channels":/realtime/channels & "messages":/realtime/messages documentation +1. If you would like to find out more about how channels and how publishing & subscribing works, see the realtime "channels":/realtime/channels/overview & "messages":/realtime/messages documentation 2. Learn more about "Channel Occupancy Events":https://www.ably.io/tutorials/channel-occupancy-events 3. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 4. Learn more about "Fitbit":https://community.fitbit.com/t5/SDK-Development/bd-p/sdk diff --git a/content/tutorials/vue-tictactoe.textile b/content/tutorials/vue-tictactoe.textile index 3c52b4e36c..4382449e0c 100644 --- a/content/tutorials/vue-tictactoe.textile +++ b/content/tutorials/vue-tictactoe.textile @@ -1248,7 +1248,7 @@ And then run the demo locally by adding your "Ably API key":https://support.ably h2. Next steps -1. Find out more about Realtime "channels":/realtime/channels & "messages":/realtime/messages +1. Find out more about Realtime "channels":/realtime/channels/overview & "messages":/realtime/messages 2. "Find out more about Presence":/realtime/presence 3. "Find out more about History":/realtime/history 4. "Find out more about Authentication":/realtime/authentication diff --git a/data/jsbins.yaml b/data/jsbins.yaml index 5c14ebb605..3059eaa581 100644 --- a/data/jsbins.yaml +++ b/data/jsbins.yaml @@ -31,7 +31,6 @@ jsbin_hash: "+7edQ0/+RVdXbSaumOltjdMtYW8=": udenus J6B4SjIgGXie5DHoSF30sGPzb64=: akutul dqNcZL3zwOeS3PmMAzJ54wVDkNg=: utizit - fDq9P84O672WgwAsIhYmPxnPLRA=: azifaq 1vHSWAcT6EJzqWwQU4oqY1onx1o=: akimez eBxLJU1YqdX+JW9JQY70S4iQfmU=: omedab pzHKfCW4/o2wDnCfbg1m0Pkl7v8=: ovucin @@ -43,6 +42,7 @@ jsbin_hash: Sf9QPfpwxOvNcKy+KTQKXHq8dbc=: umikub 6voT8sjZ4GnNONoP3sW/Uaq2GkE=: aqalul 5SY9KnghzlKVnF/NlXih5jySnug=: utulow + L26ZVUkYlizKBpvX2MKx6qwqn50=: ufosih jsbin_id: adapters/pusher-pub-sub: eBxLJU1YqdX+JW9JQY70S4iQfmU= adapters/pubnub-pub-sub: pzHKfCW4/o2wDnCfbg1m0Pkl7v8= @@ -84,6 +84,6 @@ jsbin_id: sse/sse: 5SY9KnghzlKVnF/NlXih5jySnug= sse/eventstream: 6voT8sjZ4GnNONoP3sW/Uaq2GkE= rest/batch-presence: cHvxfaSCnHR6qzdutJZ/TZWK0FE= - realtime/rewind: fDq9P84O672WgwAsIhYmPxnPLRA= + realtime/rewind: L26ZVUkYlizKBpvX2MKx6qwqn50= authentication/jwt-token: Q0XIw74KKfK3Zv34fqKSck4ip5U= realtime/connection-recover: Sf9QPfpwxOvNcKy+KTQKXHq8dbc= From aa718d88933313b893dc74aa3ab87a2a4b0bb1a9 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Tue, 19 May 2020 18:50:02 +0100 Subject: [PATCH 02/47] Updated channels/overview page --- content/realtime/channels/overview.textile | 28 ++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/content/realtime/channels/overview.textile b/content/realtime/channels/overview.textile index f1567d900d..6ea3893876 100644 --- a/content/realtime/channels/overview.textile +++ b/content/realtime/channels/overview.textile @@ -140,9 +140,29 @@ bc[objc]. ARTRealtimeChannel *channel = [realtime.channels get:@"channelName"]; bc[swift]. let channel = realtime.channels.get("channelName") -h4(#setting-channel). Setting channel options and encryption +h4(#setting-channel-options). Setting channel options -A set of "channel options":#channel-options may also be passed to configure a channel for encryption. Find out more about "symmetric message encryption":/realtime/encryption. +You can set "channel options":#channel-options in one of two ways: + +* Initially, when you first obtain a channel using "channels.get":#obtaining-channel. +* After creation, when you update a channel using "channels.setOptions":#modifying-options. + +h5(#setting-channel-parameters). Setting channel parameters + +Channel parameters allow a client to set the properties of a channel. The are two parameters that can be specified: + +* "rewind":/realtime/channels/channel-parameters/rewind +* "deltas":/realtime/channels/channel-parameters/deltas + +bc[jsall]. const realtime = new Ably.Realtime('{{API_KEY}}'); +const channelOpts = {params: {rewind: '1'}} +const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); + +h5(#setting-encryption-options). Setting channel encryption options + +You can enable encryption on a channel using the "channel options":#channel-options. + +Find out more about "symmetric message encryption":/realtime/encryption. bc[jsall]. Ably.Realtime.Crypto.generateRandomKey(function(err, key) { var options = { cipher: { key: key } }; @@ -515,6 +535,10 @@ channel.publish("action", data: "boom!") Normally, errors in attaching to a channel are communicated through the attach callback. For implicit attaches (and other cases where a channel is attached or reattached automatically, e.g. following the library reconnecting after a period in the @suspended@ state), there is no callback, so if you want to know what happens, you'll need to listen for channel state changes. +h3(#modifying-options). Modifying channel options + +You can modify the @ChannelOptions@ associated with a given channel instance by calling @setOptions@ and passing a new @ChannelOptions@. The modified options will either take effect at the time of attachment (if an attach for that channel has not yet been initiated), or the @setOptions@ call will trigger an immediate attach operation to apply the modified options. Success or failure of any triggered attach operation triggered is indicated in the result of the @setOptions@ call. + h3(#multi-publish). Publishing to multiple channels Often it is necessary to publish a single message in multiple channels at the same time. In the realtime API, this is achieved simply by making multiple separate "publish":#publish requests. If a separate publish is made in each of the channels in question, the realtime protocol will allow for those concurrent requests to be in-flight simultaneously. This ensures that a publish on a channel is not delayed waiting for completion of operations in other channels. From 4628497df2805ba709caf0309c2f2717ed6fee74 Mon Sep 17 00:00:00 2001 From: MarkWoulfeAbly <63646324+MarkWoulfeAbly@users.noreply.github.com> Date: Wed, 20 May 2020 15:45:21 +0100 Subject: [PATCH 03/47] Update overview.textile --- content/realtime/channels/overview.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/overview.textile b/content/realtime/channels/overview.textile index 6ea3893876..e9ac5b5c26 100644 --- a/content/realtime/channels/overview.textile +++ b/content/realtime/channels/overview.textile @@ -152,7 +152,7 @@ h5(#setting-channel-parameters). Setting channel parameters Channel parameters allow a client to set the properties of a channel. The are two parameters that can be specified: * "rewind":/realtime/channels/channel-parameters/rewind -* "deltas":/realtime/channels/channel-parameters/deltas +* "delta":/realtime/channels/channel-parameters/deltas bc[jsall]. const realtime = new Ably.Realtime('{{API_KEY}}'); const channelOpts = {params: {rewind: '1'}} From ebeba626faafb910660719058c3c9c3946a29c8f Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Wed, 20 May 2020 16:10:05 +0100 Subject: [PATCH 04/47] Updated channel options partial --- content/partials/types/_channel_options.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/partials/types/_channel_options.textile b/content/partials/types/_channel_options.textile index 2ff18322ef..6b54f8b6e3 100644 --- a/content/partials/types/_channel_options.textile +++ b/content/partials/types/_channel_options.textile @@ -1,4 +1,4 @@ -Currently the supported channel options are only used for "configuring encryption":/realtime/encryption. +Channel options are used for setting "channel parameters":/realtime/channels/channel-parameters/overview and "configuring encryption":/realtime/encryption. blang[jsall]. @ChannelOptions@, a plain Javascript object, may optionally be specified when instancing a "@Channel@":/realtime/channels, and this may be used to specify channel-specific options. The following attributes can be defined on the object: From c6fc36e3d0f186d85bba97b3cc04f3ba1dd7071b Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Wed, 20 May 2020 17:33:11 +0100 Subject: [PATCH 05/47] Updted channel parameters page --- .../channel-parameters/overview.textile | 223 +++--------------- 1 file changed, 29 insertions(+), 194 deletions(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 8465867df9..5d2d6ccf2e 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -5,33 +5,26 @@ index: 1 jump_to: Help with: - Overview#overview - - Using params with v1.1 or earlier Ably libraries#using-params-with-lib-v11 - - Using params with non-Ably transports#using-params-with-other-transports - - Examples#examples - Parameters: - - rewind#rewind + - Supported channel parameters#supported-parameters + - Using channel parameters#using-parameters + - Using channel parameters with non-Ably transports#using-parameters-with-other-transports + - Next steps#next-steps --- h2(#overview). Overview -Channel parameters are a general mechanism by which a client can express properties of a channel, or of its attachment to a channel. A set of channel parameters is simply a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines. +Channel parameters allow a client to set the properties of a channel. A set of channel parameters is a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines. -The methods provided for specifying channel parameters, and the currently available features, are outlined below. +The methods provided for specifying channel parameters are outlined below. -h2(#supported-params). Currently supported channel params +h2(#supported-parameters). Supported channel parameters -- rewind := Used to request that an attachment start from some number of messages or point in time in the past. See "rewind":#rewind for more information -- delta := **In an experimental state**. Used to request that data payloads should be sent as deltas to the previous payload. "Contact us":https://www.ably.io/contact for more information and supported values +- rewind := Used to request that an attachment start from a given number of messages or point in time in the past. See "rewind":/realtime/channels/channel-parameters/rewind for more information. +- delta := Used to request that data payloads should be sent as deltas to the previous payload. See "deltas":/realtime/channels/channel-parameters/deltas for more information. -h2(#using-params-with-lib-v11). Using channel params with v1.1 or earlier Ably client libraries +h2(#using-parameters). Using channel parameters -The current Ably libraries, at version 1.1, do not expose an API for expressing channel parameters. This means that it is necessary to specify parameters in a way that is opaque to the library. - -A set of params is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. - -For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. - -Using this syntax with the Ably library means that channel parameters are specified for the lifetime of the @Channel@ instance; in order to reference the same channel, but with different channel parameters, it is necessary to get a new @Channel@ instance, using a qualified name that includes the new channel parameters. +You can specify channel parameters in the @ChannelOptions@ when obtaining a @Channel@. A collection of channel parameters is expressed as a map of string key/value pairs. The @ChannelOptions@ associated with a channel may also be updated by calling "setOptions":/realtime/channels/overview#modifying-options. The parameters associated with a channel take effect when the channel is first attached; if the parameters are subsequently modified via a call to @setOptions@, then that call triggers an attach operation that applies the updated parameters, if successful. h3. Example @@ -39,10 +32,23 @@ For example, to specify the @rewind@ channel param with the value @"1"@: ```[javascript] const realtime = new Ably.Realtime('{{API_KEY}}'); - const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); + const channelOpts = {params: {rewind: '1'}} + const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); +``` + +To modify the @rewind@ channel param with the value @"15s"@: + +```[javascript] + const realtime = new Ably.Realtime('{{API_KEY}}'); + const channelOpts = {params: {rewind: '15s'}} + channel.setOptions(channelOpts, (err) => { + if(!err) { + console.log('channel params updated') + } + }); ``` -h2(#using-params-with-other-transports). Using params with non-Ably transports +h2(#using-parameters-with-other-transports). Using parameters with non-Ably transports It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. @@ -70,178 +76,7 @@ Or to specify the same parameter but only applying to one channel of two, using var querystring = 'v=1.2&key={{API_KEY}}&channels=' + channels'; var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); ``` +h2(#next-steps). Next steps -h2(#rewind). Rewind parameter - -The @rewind@ channel parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). - -A @rewind@ parameter can express a channel position in terms of a number of messages, or a time interval. - -A @rewind@ value that is simply a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If that attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. - -If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. - -A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. - -If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel param. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. - -At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. - -By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. - -The channel position expressed by a @rewind@ parameter has an effect only on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). - -Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier represents an error, and any attachment request will fail with an error. - -h3(#rewind-example-ably). Rewind example with an Ably client library - -To subscribe to a channel, getting the most recent message if available: - -```[jsall] - // only with ably-js v1.2 or later - const realtime = new Ably.Realtime('{{API_KEY}}'); - realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { - rewind: '1' - }).subscribe(msg => console.log("Received message: ", msg)); -``` - -```[jsall] - // with ably-js v1.1 or below - const realtime = new Ably.Realtime('{{API_KEY}}'); - const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); - channel.subscribe(msg => console.log("Received message: ", msg)); -``` - -h3(#rewind-example-sse). Rewind example with SSE - -To subscribe to a channel, getting the most recent message if available: - -```[javascript] - var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; - var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); -``` - -h3(#rewind-examples-mqtt). Rewind example with MQTT - -```[nodejs] - var mqtt = require('mqtt'); - var options = { - keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', - port: 8883 - }; - var client = mqtt.connect('mqtts:mqtt.ably.io', options); - client.on('connect', () => { - client.subscribe('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); - }); - client.on('message', (topic, message) => { - ... - }); -``` - -h2(#delta). Delta parameter - -The @delta@ channel parameter allows subscribers to expresse their desire to receive deltas (diffs) between the previous and current message instead of the current message in full on a given channel. The effects of this parameter are invisible to message senders and only affect subscribers that specify it - i.e. the sender sends messages in full and Ably computes and sends the message deltas to any subscriber which subscribed using this parameter. - -Note that requesting deltas does not guarantee that every message received will be a delta, as the server may chose to send some messages in full depending on system load and other factors. Therefore a subscriber using the @delta@ parameter should be prepared to handle a random mix of delta and full messages. - -The @delta@ parameter can take only the value @vcdiff@. VCDIFF is the format of the deltas. It is an open format specified in "RFC 3284":https://tools.ietf.org/html/rfc3284. - -Ably provides a JavaScript "delta codec library":https://github.com/ably/delta-codec-js to help you avoid writing boilerplate VCDIFF handling code. Some examples follow. - -h3(#delta-example-sse). Delta example with enveloped SSE - -```[jsall] -const key = '{{API_KEY}}'; -const channel = 'sample-app-sse'; -const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.2&key=${key}&delta=vcdiff`; -const eventSource = new EventSource(url); -const channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); - -eventSource.onmessage = (event) => { - /* event.data is JSON-encoded Ably Message (see https://www.ably.io/documentation/realtime/types#message) */ - const message = JSON.parse(event.data); - const { id, extras } = message; - let { data } = message; - - try { - if (extras && extras.delta) { - data = channelDecoder.applyBase64Delta(data, id, extras.delta.from).asUtf8String(); - } else { - channelDecoder.setBase(data, id); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); -}; -``` - -h3(#delta-example-unenv-sse). Delta example with unenveloped SSE - -```[jsall] -const key = '{{API_KEY}}'; -const channel = 'sample-app-sse'; -const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.2&key=${key}&delta=vcdiff&enveloped=false`; -const eventSource = new EventSource(url); -const channelDecoder = new DeltaCodec.VcdiffDecoder(); - -eventSource.onmessage = (event) => { - let data = event.data; - - try { - if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { - data = channelDecoder.applyBase64Delta(data).asUtf8String(); - } else { - channelDecoder.setBase(data); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); -}; -``` - -h3(#delta-example-mqtt). Delta example with MQTT - -```[jsall] -const mqtt = require('mqtt'); -const { VcdiffDecoder } = require('./lib'); - -const options = { - keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', - port: 8883 -}; -const client = mqtt.connect('mqtts:mqtt.ably.io', options); -const channelName = 'sample-app-mqtt'; -const channelDecoder = new VcdiffDecoder(); - -client.on('message', (_, payload) => { - let data = payload; - - try { - if (VcdiffDecoder.isDelta(data)) { - data = channelDecoder.applyDelta(data).asUint8Array(); - } else { - channelDecoder.setBase(data); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); -}); - -client.subscribe(`[?delta=vcdiff]${channelName}`); -``` +* Request that an attachment start from a given number of messages or point in time in the past using "rewind":/realtime/channels/channel-parameters/rewind. +* Request that data payloads should be sent as deltas to the previous payload using "deltas":/realtime/channels/channel-parameters/deltas. \ No newline at end of file From 9af0551cf20935f031e43facc046f01262352fb6 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Thu, 21 May 2020 13:19:55 +0100 Subject: [PATCH 06/47] Updated rewind page --- .../channel-parameters/rewind.textile | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 416e31765d..a482ad1376 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -1,35 +1,43 @@ --- title: Rewind section: realtime -index: 3 +index: 2 jump_to: Help with: - Overview#overview + - Examples#examples --- h2(#overview). Overview -Channels support a parameter that applies at the time of attachment that requests that an attachment start from some number of messages or point in time in the past. The @rewind@ param is specified via the "channel params":/realtime/channels/channel-parameters mechanism. +The @rewind@ parameter allows you to specify, at the time of attaching to a channel, where to start the attachment from. -The @rewind@ channel parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). +You can specify either: -A @rewind@ parameter can express a channel position in terms of a number of messages, or a time interval. +* A given number of messages. +* A point in time in the past, as a time interval. -A @rewind@ value that is simply a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If that attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. +The @rewind@ parameter is specified using "channel parameters":/realtime/channels/channel-parameters/overview. + +The parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). + +A @rewind@ value that is a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If the attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. -If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel param. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. +If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel parameter. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. -The channel position expressed by a @rewind@ parameter has an effect only on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). +The channel position expressed by a @rewind@ parameter only has an effect on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). + +Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier will cause the attachment request to fail and return an error. -Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier represents an error, and any attachment request will fail with an error. +h2(#examples). Examples h3(#rewind-example-ably). Rewind example with an Ably client library From b29e1f65d0d6d126fd22664057b8765f71fb5cee Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Thu, 21 May 2020 18:28:37 +0100 Subject: [PATCH 07/47] Updated deltas page --- .../channel-parameters/deltas.textile | 81 ++++++++----------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 8fa589921e..dc59f42856 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -1,48 +1,60 @@ --- -title: Delta mode subscription +title: Delta compression section: realtime -index: 2 +index: 3 jump_to: Help with: - Overview#overview + - Delta processing#delta-processing + - Using deltas#using-deltas - Examples#examples - Parameters: - - delta#delta --- h2(#overview). Overview -Often a channel carries messages that represent a series updates to a particular object or document and, as such, there is a significant degree of similarily between successive messages. Delta mode is a way for a client to subscribe to a channel so that message payloads sent over the wire contain only the difference (ie the delta) between the present message and the previous message on the channel. The client can then apply the delta to the previous message to obtain the full payload. Using delta mode can signficantly reduce the encoded size of each message in the case that message payloads change by differences that are small relative to the size of the value. This reduction in size can reduce bandwidth costs, reduce transit latencies, and enable greater message throughput on a connection. +The @delta@ parameter enables delta compression. It is applied on the channel you are subscribing to, enabling delta mode. -The present delta mode implementation supports a single representation of a delta, [VCDIFF](https://tools.ietf.org/html/rfc3284). However, the protocol and API are designed to allow other representations to be used in the future. +Delta mode is a way for a client to subscribe to a channel so that message payloads sent contain only the difference (ie the delta) between the present message and the previous message on the channel. -Since version 1.2, Ably libraries support delta subscriptions; subscribing in delta mode is enabled for a given channel by specifying a "delta channel param":/realtime/channels/channel-parameters with the value @vcdiff@. This will cause delta messages to be generated by the server and sent to the client, and the library reconstitutes the original message payload. The end result is that messages on the channel are delivered to the subscriber's listener in just the same way as happens with a normal subscription. +This is useful for channels that carry messages representing a series of updates to a particular object or document with a significant degree of similarily between successive messages. The client can apply the delta to the previous message to obtain the full payload. Using delta mode can signficantly reduce the encoded size of each message in the case that message payloads change by differences that are small relative to the size of the value. This reduction in size can reduce bandwidth costs, reduce transit latencies, and enable greater message throughput on a connection. + +Currently the delta mode implementation supports a single representation of a delta, "VCDIFF":https://tools.ietf.org/html/rfc3284. However, the protocol and API are designed to allow other representations to be used in the future. + +Subscribing in delta mode is enabled for a given channel by specifying a @delta@ "channel parameter":/realtime/channels/channel-parameters/overview with the value @vcdiff@. This will cause delta messages to be generated by the server and sent to the client, and the library reconstitutes the original message payload. Messages on the channel are delivered to the subscriber's listener in the same way as with a normal subscription. h2(#delta-processing). Delta processing Deltas apply to the principal payload of a @Message@ published via Ably, which is the @data@ member. Other elements of a message, such as @clientId@, @name@, or @extras@ are unchanged by use of deltas and are not compressed. -Deltas are supported for realtime subscriptions only. Messages retrieved via the history API, and messages delivered to Reactor endpoints, are not compressed. Support for delta-compressed messages via Reactor is under consideration for the future. +Deltas are supported for realtime subscriptions only. Messages retrieved via the history API, and messages delivered to Reactor endpoints, are not compressed. -Delta compression via @vcdiff@ is supported for all payloads, whether string or binary, or JSON-encoded. The delta algorithm processes message payloads as opaque binaries and has no dependency on the stucture of the payload - it does not process line-oriented diffs, for example. In principle, @vcdiff@ deltas can be applied to encrypted message payloads, but in practice this provides no benefit because there is no similarity between successive encrypted payloads even on identical or near-identical plaintext message payloads. +Delta compression via @vcdiff@ is supported for all payloads, whether string, binary, or JSON-encoded. The delta algorithm processes message payloads as opaque binaries and has no dependency on the stucture of the payload - it does not process line-oriented diffs, for example. In principle, @vcdiff@ deltas can be applied to encrypted message payloads, but in practice this provides no benefit because there is no similarity between successive encrypted payloads even on identical or near-identical plaintext message payloads. Delta compression is a subscriber-specified option only - the publisher has no control over whether or not deltas are generated for any given message; the processing is performed if there is at least one subscriber on a channel that has requested a delta-mode subscription. There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question, for the region in question. When there are multiple publishers in multiple regions, publishing messages nearly simultaneously, the ordering of messages delievred to subscribers can be different in different regions, depending on actual region-to-region transit latencies; in this case, deltas are generated based on the actual message order in each region, and subscribers are delivered a sequence of delta messages that reflects that regional order. -Delta processing, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. Effectiveness of delta processing - that is, whether or not there is a material saving in payload size - is dependent on the level of similarity between successive payloads. Therefore, if a channel carries messages from multiple sources or streams that are dissimilar, then delta processing might not result in a useful size reduction, even if the messages in each individual stream are similar; it depends on the specific sequence of messages that occurs in the channel, in the region in question. +Delta mode, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. The effectiveness of delta mode - that is, whether or not there is a material saving in payload size - is dependent on the level of similarity between successive payloads. Therefore, if a channel carries messages from multiple sources or streams that are dissimilar, then delta processing might not result in a useful size reduction, even if the messages in each individual stream are similar; it depends on the specific sequence of messages that occurs in the channel, in the region in question. + +If a delta is generated and it results in a difference that is not appreciably smaller than the original message, or is even larger than the original message (which can happen if successive messages are completely different), then the delta will not be sent and clients will receive the original, unprocessed message. Therefore, the sequence of messages that will be delivered to a client for any given channel will be a combination of regular messages and delta-compressed messages. + +A channel subscriber can experience a discontinuity in the sequence of messages it receives on a given channel for the following reasons: -If a delta is generated and it results in a difference that is not appreciably smaller than the original message, or is even larger than the original message (which can happen if successive messages are completely different), then the delta will not be sent - clients will receive the original, unprocessed message. Therefore, in general, the sequence of messages that will be delivered to a client for any given channel will be a combination of regular messages and delta-compressed messages, with the delta messages only being present when they achieve a payload size reduction in comparison with the unmodified message. +* The connection can drop, and there will be a discontinuity of the client is unable to reconnect within the two-minute window it is allowed to preserve connection continuity. +* The outbound connection might have been rate-limited, which causes some messages to be dropped +* There might have been some internal error in the Ably system which leads to the server being unable to preserve continuity on the channel. -On some occasions a channel subscriber can experience a discontinuity in the sequence of messages it receives on any given channel. There are several possible reasons for this: the connection can drop, and there will be a discontinuity of the client is unable to reconnect within the two-minute window it is allowed to preserve connection continuity; the outbound connection might have been rate-limited, which causes some messages to be dropped; or there might have been some internal error in the Ably system which leads to the server being unable to preserve continuity on the channel. In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. If a subscriber has a delta-mode subscription and the channel in question experiences a discontunity, then a non-delta message will be delivered to the client as the first message after the discontinuity, so that lost messages do not prevent the client from reconstituting messages from deltas. +In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. + +If a subscriber has a delta-mode subscription and the channel in question experiences a discontunity, then a non-delta message will be delivered to the client as the first message after the discontinuity. This ensures that lost messages do not prevent the client from reconstituting messages from deltas. h2(#using-deltas). Using deltas -h3(#using-deltas-12). Via an Ably library from v1.2 (via the delta channel parameter) +h3(#using-deltas-ably). Via an Ably library The most common way to subscribe to Ably channels is via a realtime connection, using an Ably realtime library. -From version 1.2, Ably libraries support the ability to subscribe to a channel in delta mode. For many libraries this requires no change on the part of the caller except to specify the "delta channel param":/realtime/channels/channel-parameters when subscribing to the channel. In some libraries, the @vcdiff@ delta decoding library is excluded from the default library distribution in order to avoid bloating the library; in these cases, it is also necessary to supply the delta decoder plugin when instancing the Ably library. +For many libraries this requires no change on the part of the caller except to specify the @delta@ "channel parameter":/realtime/channels/channel-parameters/overview when subscribing to the channel. In some libraries, the @vcdiff@ delta decoding library is excluded from the default library distribution in order to avoid bloating the library. In these cases, it is also necessary to supply the delta decoder plugin when instancing the Ably library. ```[jsall] @@ -72,57 +84,30 @@ TBD TBD ``` -h3(#using-deltas-11). Via an Ably library before v1.2 (via a qualified channel name) - -```[jsall] - const realtime = new Ably.Realtime({key: '{{API_KEY}}'}); - const channel = realtime.channels.get('[?delta=vcdiff]{{RANDOM_CHANNEL_NAME}}'); - channel.subscribe(msg => console.log("Received message: ", msg)); -``` - -```[java] - AblyRealtime ably = new AblyRealtime("{{API_KEY}}"") - Channel channel = ably.channels.get("[?delta=vcdiff]{{RANDOM_CHANNEL_NAME}}"); - channel.subscribe(new MessageListener() { - @Override - public void onMessage(Message message) { - System.out.println("Received `" + message.name + "` message with data: " + message.data); - } - }); -``` - -```[obj-c] -TBD -``` - -```[dotnet] -TBD -``` - h3(#using-deltas-non-ably). Via a subscription that does not use an Ably library -If subscribing to a channel in delta mode using [SSE](https://www.ably.io/documentation/sse) or one of the protocol adaptors such as [MQTT](https://www.ably.io/documentation/mqtt), then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the [download](https://www.ably.io/download) section for details. If you need to decode @vcdiff@-formatted delta messages in languages for which there is no decoder available from Ably, then any compliant open-source implementation of the standard will work. +If subscribing to a channel in delta mode using "SSE":/sse or one of the protocol adaptors such as "MQTT":/mqtt, then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the "download":https://www.ably.io/download section for details. If you need to decode @vcdiff@-formatted delta messages in languages for which there is no decoder available from Ably, then any compliant open-source implementation of the standard will work. Messages that contain a @vcdiff@ delta have that delta payload in their @data@ attribute; in the case of @vcdiff@ deltas this will be a binary value, even if the @data@ in the original meessage was text. in addition, there is metadata in the message @extras@ attribute that indicate that the payload is a delta, and which message the delta is relative to. The format of the `extras` attribute is as follows: ```[jsall] - extras: { format: 'vcdiff', from: '{{previous message id}}' } ``` -In order to reconstruct the original message, the @vcdiff@ decoder algorithm needs to be applied to the given @data@ @vcdiff@ value, together with the @data@ for the previous message (on the assumption that that message had already beein decoded if it itself was also a delta). If the original form of the present message was text, then this is indicated in the `encoding` attribute of the message, so the original text can be reconstructed by @utf-8@ decoding, once the @vcdiff@ decoding is complete. The decoder libraries that are available to [download]() simplify this process, and more detailed information can be found in the @README@ of each of those libraries. +In order to reconstruct the original message, the @vcdiff@ decoder algorithm needs to be applied to the given @data@ @vcdiff@ value, together with the @data@ for the previous message (on the assumption that that message had already been decoded if it itself was also a delta). If the original form of the present message was text, then this is indicated in the `encoding` attribute of the message, so the original text can be reconstructed by @utf-8@ decoding, once the @vcdiff@ decoding is complete. The decoder libraries that are available to download simplify this process, and more detailed information can be found in the @README@ of each of those libraries. -When subscribing without an Ably library, then the channel @delta@ param must be specified using a "qualified channel name":/realtime/channels/channel-parameters. In the case of [SSE](https://www.ably.io/documentation/sse), it is also possible to specify channel params as regular query params on the connection URL. +When subscribing without an Ably library, then the channel @delta@ parameter must be specified using a "qualified channel name":/realtime/channels/channel-parameters/overview. In the case of SSE, it is also possible to specify channel parameters as regular query parameters on the connection URL. -Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. Examples of such transports are [MQTT](https://www.ably.io/documentation/mqtt), and [SSE](https://www.ably.io/documentation/sse) in non-enveloped mode. In order to assist applications that use these transports, the @vcdiff@ decoder libraries can check for the @vcdiff@ magic number at the start of the message payload as an inexact method of determining whether or not the message is a regular message or a delta. Note that, in order to rely on that check, you need to know that that magic number will not be present in any valid (uncompressed) message in your app. No valid JSON value, for example, will match the @vcdiff@ header check, so it is safe to perform this sniffing on JSON message payloads. +Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. -h4(#delta-example-sse). Delta example with SSE +Examples of such transports are MQTT, and SSE in non-enveloped mode. In order to assist applications that use these transports, the @vcdiff@ decoder libraries can check for the @vcdiff@ magic number at the start of the message payload as an inexact method of determining whether or not the message is a regular message or a delta. Note that, in order to rely on that check, you need to know that that magic number will not be present in any valid (uncompressed) message in your app. No valid JSON value, for example, will match the @vcdiff@ header check, so it is safe to perform this sniffing on JSON message payloads. -You can subscribe to messages in delta mode, using the [SSE](https://www.ably.io/documentation/sse) transport, as follows. +h4(#delta-example-sse). Delta example with SSE +You can subscribe to messages in delta mode, using the SSE transport, as follows. ``` (() => { From 6a252c11362964e2f88ff955f41e5452c2581d6c Mon Sep 17 00:00:00 2001 From: MarkWoulfeAbly <63646324+MarkWoulfeAbly@users.noreply.github.com> Date: Fri, 22 May 2020 14:38:38 +0100 Subject: [PATCH 08/47] Updated channel parameter example Updated the example to include delta as well as rewind. --- content/realtime/channels/overview.textile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/content/realtime/channels/overview.textile b/content/realtime/channels/overview.textile index e9ac5b5c26..7a075013f0 100644 --- a/content/realtime/channels/overview.textile +++ b/content/realtime/channels/overview.textile @@ -155,8 +155,13 @@ Channel parameters allow a client to set the properties of a channel. The are tw * "delta":/realtime/channels/channel-parameters/deltas bc[jsall]. const realtime = new Ably.Realtime('{{API_KEY}}'); -const channelOpts = {params: {rewind: '1'}} -const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); +const channelOptions = { + params: { + delta: 'vcdiff', + rewind: '1' + } +}; +const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOptions); h5(#setting-encryption-options). Setting channel encryption options From 2b25a80314eac129407c1d421029fa0e46c616bd Mon Sep 17 00:00:00 2001 From: tomC Date: Fri, 29 May 2020 12:43:11 +0100 Subject: [PATCH 09/47] Revert overview changes to realtime docs --- content/code/realtime/rewind.code | 2 +- content/core-features/pubsub.textile | 2 +- .../versions/v1.1/pubsub.textile | 2 +- content/general/events/ifttt.textile | 2 +- content/general/firehose.textile | 2 +- content/general/queues.textile | 4 +- content/general/versions/v0.8/queues.textile | 2 +- .../general/versions/v1.0/firehose.textile | 2 +- .../general/versions/v1.0/functions.textile | 4 +- content/general/versions/v1.0/queues.textile | 4 +- .../general/versions/v1.0/webhooks.textile | 4 +- .../versions/v1.1/events/ifttt.textile | 2 +- .../general/versions/v1.1/firehose.textile | 2 +- content/general/versions/v1.1/queues.textile | 4 +- content/mqtt/index.textile | 2 +- .../types/_channel_state_change.textile | 2 +- .../v0.8/types/_channel_state_change.textile | 2 +- .../v1.0/types/_channel_state_change.textile | 2 +- .../v1.1/types/_channel_state_change.textile | 2 +- .../{channels => }/channel-metadata.textile | 0 content/realtime/channel-params.textile | 247 ------------------ .../overview.textile => channels.textile} | 8 +- content/realtime/encryption.textile | 2 +- content/realtime/history.textile | 6 +- content/realtime/index.textile | 2 +- content/realtime/messages.textile | 2 +- content/realtime/presence.textile | 2 +- content/realtime/usage.textile | 2 +- .../realtime/versions/v0.8/encryption.textile | 2 +- .../realtime/versions/v0.8/history.textile | 4 +- content/realtime/versions/v0.8/index.textile | 2 +- .../realtime/versions/v0.8/presence.textile | 2 +- content/realtime/versions/v0.8/usage.textile | 2 +- .../realtime/versions/v1.0/encryption.textile | 2 +- .../realtime/versions/v1.0/history.textile | 2 +- content/realtime/versions/v1.0/index.textile | 2 +- .../realtime/versions/v1.0/messages.textile | 2 +- .../realtime/versions/v1.0/presence.textile | 2 +- content/realtime/versions/v1.0/usage.textile | 2 +- .../realtime/versions/v1.1/encryption.textile | 2 +- .../realtime/versions/v1.1/history.textile | 2 +- content/realtime/versions/v1.1/index.textile | 2 +- .../realtime/versions/v1.1/messages.textile | 2 +- .../realtime/versions/v1.1/presence.textile | 2 +- content/realtime/versions/v1.1/usage.textile | 2 +- content/rest/versions/v0.8/usage.textile | 2 +- content/rest/versions/v1.0/usage.textile | 2 +- content/root/best-practice-guide.textile | 2 +- .../channel-enumeration-rest.textile | 2 +- .../channel-lifecycle-events.textile | 2 +- .../channel-occupancy-events.textile | 2 +- content/tutorials/newsfeed-react.textile | 2 +- content/tutorials/presence.textile | 4 +- content/tutorials/publish-subscribe.textile | 4 +- .../reactjs-realtime-commenting.textile | 2 +- .../tutorials/sse-and-http-streaming.textile | 2 +- content/tutorials/trainapp-fitbit.textile | 2 +- content/tutorials/vue-tictactoe.textile | 2 +- data/jsbins.yaml | 4 +- 59 files changed, 71 insertions(+), 318 deletions(-) rename content/realtime/{channels => }/channel-metadata.textile (100%) delete mode 100644 content/realtime/channel-params.textile rename content/realtime/{channels/overview.textile => channels.textile} (98%) diff --git a/content/code/realtime/rewind.code b/content/code/realtime/rewind.code index 8a8157b127..aa2deb94df 100644 --- a/content/code/realtime/rewind.code +++ b/content/code/realtime/rewind.code @@ -58,7 +58,7 @@ function show(status, color, box) {

Ably Rewind demo

-

In this example, we demonstrate the simplest way to subscribe to a message using rewind in libraries older than v1.2. See our Rewind documentation for more details. +

In this example, we demonstrate the simplest way to subscribe to a message using rewind in libraries older than v1.2. See our Rewind documentation for more details.

diff --git a/content/core-features/pubsub.textile b/content/core-features/pubsub.textile index 00bfa3853b..4394be227e 100644 --- a/content/core-features/pubsub.textile +++ b/content/core-features/pubsub.textile @@ -16,6 +16,6 @@ For instance, consider a location tracking application. The subscriber will cont Pub/Sub in Ably -As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels/overview and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). +As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). Read our "Realtime Library":/realtime documentation to learn how you can implement Pub/Sub in your applications. You can also jump into our "Pub/Sub tutorial":https://www.ably.io/tutorials/publish-subscribe#lang-javascript or check out a "quick bit video":https://www.youtube.com/watch?v=_70uOFiBeo8&t=0s&list=PLv7MaB8onr7krKzzwswsLYFsB_KmgEu44&index=2 to see it in action. \ No newline at end of file diff --git a/content/core-features/versions/v1.1/pubsub.textile b/content/core-features/versions/v1.1/pubsub.textile index 00bfa3853b..4394be227e 100644 --- a/content/core-features/versions/v1.1/pubsub.textile +++ b/content/core-features/versions/v1.1/pubsub.textile @@ -16,6 +16,6 @@ For instance, consider a location tracking application. The subscriber will cont Pub/Sub in Ably -As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels/overview and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). +As seen in the illustration above, you can implement Pub/Sub easily by using Ably as the intermediary realtime messaging platform. Your publishers and subscribers can attach to named "channels":/realtime/channels and Ably is responsible for routing the right message to the right client in real time ("typically within 60ms globally":https://status.ably.com/status). Read our "Realtime Library":/realtime documentation to learn how you can implement Pub/Sub in your applications. You can also jump into our "Pub/Sub tutorial":https://www.ably.io/tutorials/publish-subscribe#lang-javascript or check out a "quick bit video":https://www.youtube.com/watch?v=_70uOFiBeo8&t=0s&list=PLv7MaB8onr7krKzzwswsLYFsB_KmgEu44&index=2 to see it in action. \ No newline at end of file diff --git a/content/general/events/ifttt.textile b/content/general/events/ifttt.textile index bd26a882f6..717f1fd2a5 100644 --- a/content/general/events/ifttt.textile +++ b/content/general/events/ifttt.textile @@ -46,7 +46,7 @@ In addition, if you are wanting data to be passed through and processed by IFTTT } ``` -In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels/overview to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. +In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. h2(#example). Example diff --git a/content/general/firehose.textile b/content/general/firehose.textile index bcffd22f88..0e8856871e 100644 --- a/content/general/firehose.textile +++ b/content/general/firehose.textile @@ -6,7 +6,7 @@ index: 26 Our Firehose can stream your realtime data published within the Ably platform directly to another streaming or queueing service. For example, all messages published by any device on a channel could be immediately streamed to Amazon Kinesis allowing you to process this data in realtime. Firehose is offered as part of our "Ably Reactor service":https://www.ably.io/reactor but is only available to "Enterprise customers":https://www.ably.io/pricing/enterprise. -Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. +Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. As each message is delivered once to your streaming or queueing server, this design is commonly used to process realtime data published by Ably asynchronously. For example, using workers consuming from your stream or queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. Find out why we think streams and message queues help solve many of the challenges associated with consuming pub/sub data server-side in our article: "Message queues — the right way to process and work with realtime data on your servers":https://blog.ably.io/message-queues-the-right-way-to-process-and-work-with-realtime-data-on-your-servers-2d15985301f8. diff --git a/content/general/queues.textile b/content/general/queues.textile index 6c4bcfd6cc..a799d630fd 100644 --- a/content/general/queues.textile +++ b/content/general/queues.textile @@ -46,7 +46,7 @@ All Ably accounts have access to Reactor Queue functionality, however to get sta h3(#provisioning). Provisioning Reactor Queues -Unlike "pub/sub channels":/realtime/channels/overview that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. +Unlike "pub/sub channels":/realtime/channels that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. Queues are setup "within your app dashboard":https://support.ably.io/support/solutions/articles/3000030053-how-do-i-access-my-app-dashboard and you will need to configure: @@ -404,7 +404,7 @@ When using Reactor Queues, please bear in mind that: * There is a default TTL (time-to-live) applied to all messages that is configured when you provision your queue. If a message has not been consumed from a queue within this period, it will be moved to the deadletter queue. If the TTL of the deadletter queue passes, the message is discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * There is a max message limit configured when you provision your queue. If the max message limit is reached for your queue, new messages will be moved to the deadletter queue. Once the deadletter queue reaches its max message limit, new messages will be discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * With the AMQP protocol, it is possible to consume multiple queues from a single connection, and also to consume more than one message at a time. You will need to refer to your client library's documentation to enable these capabilities. See "this StackOverFlow answer":http://stackoverflow.com/a/17011833/139607 as a good starting point. -* Unlike our Ably "pub/sub channels":/realtime/channels/overview which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. +* Unlike our Ably "pub/sub channels":/realtime/channels which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. * Each message published to the queue will count towards you monthly message quota. See "billing info for more details":#below. h3(#scalability-availability). Queue Scalability and High Availability diff --git a/content/general/versions/v0.8/queues.textile b/content/general/versions/v0.8/queues.textile index 80b50051a5..2a604c4af9 100644 --- a/content/general/versions/v0.8/queues.textile +++ b/content/general/versions/v0.8/queues.textile @@ -6,7 +6,7 @@ index: 19 Message queues provide a reliable mechanism for customers to process, store, augment or reroute realtime data efficiently and asynchronously by workers. -Using configurable rules, you can ensure that your messages, presence and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events are enqueued on an Ably message queue. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our "message queues":https://en.wikipedia.org/wiki/Message_queue operate on the basis that each messages is delivered to only one subscriber. +Using configurable rules, you can ensure that your messages, presence and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events are enqueued on an Ably message queue. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our "message queues":https://en.wikipedia.org/wiki/Message_queue operate on the basis that each messages is delivered to only one subscriber. As each message is delivered once to a single subscriber, queues are commonly used by one or more workers to process realtime data published by Ably asynchronously. For example, using workers subscribed to a queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. diff --git a/content/general/versions/v1.0/firehose.textile b/content/general/versions/v1.0/firehose.textile index e5451a7ceb..b526bc812e 100644 --- a/content/general/versions/v1.0/firehose.textile +++ b/content/general/versions/v1.0/firehose.textile @@ -6,7 +6,7 @@ index: 26 Our Firehose can stream your realtime data published within the Ably platform directly to another streaming or queueing service. For example, all messages published by any device on a channel could be immediately streamed to Amazon Kinesis allowing you to process this data in realtime. Firehose is offered as part of our "Ably Reactor service":https://www.ably.io/reactor but is only available to "Enterprise customers":https://www.ably.io/pricing/enterprise. -Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. +Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. As each message is delivered once to your streaming or queueing server, this design is commonly used to process realtime data published by Ably asynchronously. For example, using workers consuming from your stream or queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. Find out why we think streams and message queues help solve many of the challenges associated with consuming pub/sub data server-side in our article: "Message queues — the right way to process and work with realtime data on your servers":https://blog.ably.io/message-queues-the-right-way-to-process-and-work-with-realtime-data-on-your-servers-2d15985301f8. diff --git a/content/general/versions/v1.0/functions.textile b/content/general/versions/v1.0/functions.textile index 380388061d..dd54e80d32 100644 --- a/content/general/versions/v1.0/functions.textile +++ b/content/general/versions/v1.0/functions.textile @@ -44,7 +44,7 @@ _Please note that the @messages@ attribute is an @Array@ so that future envelope h3(#decoding-messages). Decoding messages -Each member of @messages@ is a 'raw' message, with the contents of your "@Message@":/rest/messages#properties within it. Messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into the "@Message@":/realtime/types#message object by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded on an individual member of that array. This will transform them into an array of "@Message@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). Using the Ably client library to decode messages has several advantages: +Each member of @messages@ is a 'raw' message, with the contents of your "@Message@":/rest/messages#properties within it. Messages sent "over the realtime service":/realtime/channels are automatically decoded into the "@Message@":/realtime/types#message object by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded on an individual member of that array. This will transform them into an array of "@Message@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). Using the Ably client library to decode messages has several advantages: * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) * If you are using "encryption":/realtime/encryption, you can pass your encryption key to the method and it will decrypt the @data@ for you @@ -79,7 +79,7 @@ _Please note that the @presence@ attribute is an @Array@ so that future envelope h3(#decoding-presence). Decoding presence events -Each member of @presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into "@PresenceMessage@":/realtime/types#presence-message objects by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded on an individual member of that array. This will transform them into an array of "@PresenceMessage@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). Using the Ably client library to decode @presence@ has several advantages: +Each member of @presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels are automatically decoded into "@PresenceMessage@":/realtime/types#presence-message objects by the Ably client library. With Reactor Functions you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded on an individual member of that array. This will transform them into an array of "@PresenceMessage@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). Using the Ably client library to decode @presence@ has several advantages: * It will decode the (numerical) action into a "@PresenceAction@":/realtime/presence#presence-action string (such as "@enter@", "@update@", or "@leave@") * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) diff --git a/content/general/versions/v1.0/queues.textile b/content/general/versions/v1.0/queues.textile index 67c7f944f5..d1dac78fc4 100644 --- a/content/general/versions/v1.0/queues.textile +++ b/content/general/versions/v1.0/queues.textile @@ -46,7 +46,7 @@ All Ably accounts have access to Reactor Queue functionality, however to get sta h3(#provisioning). Provisioning Reactor Queues -Unlike "pub/sub channels":/realtime/channels/overview that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. +Unlike "pub/sub channels":/realtime/channels that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. Queues are setup "within your app dashboard":https://support.ably.io/support/solutions/articles/3000030053-how-do-i-access-my-app-dashboard and you will need to configure: @@ -404,7 +404,7 @@ When using Reactor Queues, please bear in mind that: * There is a default TTL (time-to-live) applied to all messages that is configured when you provision your queue. If a message has not been consumed from a queue within this period, it will be moved to the deadletter queue. If the TTL of the deadletter queue passes, the message is discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * There is a max message limit configured when you provision your queue. If the max message limit is reached for your queue, new messages will be moved to the deadletter queue. Once the deadletter queue reaches its max message limit, new messages will be discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * With the AMQP protocol, it is possible to consume multiple queues from a single connection, and also to consume more than one message at a time. You will need to refer to your client library's documentation to enable these capabilities. See "this StackOverFlow answer":http://stackoverflow.com/a/17011833/139607 as a good starting point. -* Unlike our Ably "pub/sub channels":/realtime/channels/overview which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. +* Unlike our Ably "pub/sub channels":/realtime/channels which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. * Each message published to the queue will count towards you monthly message quota. See "billing info for more details":#below. h3(#scalability-availability). Queue Scalability and High Availability diff --git a/content/general/versions/v1.0/webhooks.textile b/content/general/versions/v1.0/webhooks.textile index 21fd308e9e..61c4a802a7 100644 --- a/content/general/versions/v1.0/webhooks.textile +++ b/content/general/versions/v1.0/webhooks.textile @@ -125,7 +125,7 @@ Each member of @data.presence@ has the following fields: h3(#decoding-presence). Decoding presence events -Each member of @data.presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into "@PresenceMessages@":/realtime/types#presence-message object by the Ably client library. With webhooks you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @data.presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded or an individual member of that array. This will transform them into an array of "@PresenceMessages@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). This has several advantages, e.g.: +Each member of @data.presence@ is a 'raw' presence event. Presence messages sent "over the realtime service":/realtime/channels are automatically decoded into "@PresenceMessages@":/realtime/types#presence-message object by the Ably client library. With webhooks you need to to do this explicitly, using "@PresenceMessage.fromEncodedArray@":/realtime/presence#presence-from-encoded-array on the @data.presence@ array, or "@PresenceMessage.fromEncoded@":/realtime/presence#presence-from-encoded or an individual member of that array. This will transform them into an array of "@PresenceMessages@":/realtime/types#presence-message (or in the case of @fromEncoded@, an individual "@PresenceMessage@":/realtime/types#presence-message). This has several advantages, e.g.: * It will decode the (numerical) action into a "@Presence action@":/realtime/presence#presence-action string (such as "@enter@", "@update@", or "@leave@") * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) @@ -259,7 +259,7 @@ Each member of @data.messages@ has the following fields: h3(#decoding-messages). Decoding messages -Each member of @data.messages@ is a 'raw' message. Messages sent "over the realtime service":/realtime/channels/overview are automatically decoded into "@Messages@":/realtime/types#message object by the Ably client library. With webhooks you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @data.messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded or an individual member of that array. This will transform them into an array of "@Messages@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). This has several advantages, e.g.: +Each member of @data.messages@ is a 'raw' message. Messages sent "over the realtime service":/realtime/channels are automatically decoded into "@Messages@":/realtime/types#message object by the Ably client library. With webhooks you need to to do this explicitly, using "@Message.fromEncodedArray@":/realtime/messages#message-from-encoded-array on the @data.messages@ array, or "@Message.fromEncoded@":/realtime/messages#message-from-encoded or an individual member of that array. This will transform them into an array of "@Messages@":/realtime/types#message (or in the case of @fromEncoded@, an individual "@Message@":/realtime/types#message). This has several advantages, e.g.: * It will fully decode any @data@ (using the @encoding@) back into the same datatype that it was sent in (or an equivalent in each client library's language) * If you are using "encryption":/realtime/encryption, you can pass your encryption key to the method and it will decrypt the @data@ for you diff --git a/content/general/versions/v1.1/events/ifttt.textile b/content/general/versions/v1.1/events/ifttt.textile index 9db4040953..b9478fa644 100644 --- a/content/general/versions/v1.1/events/ifttt.textile +++ b/content/general/versions/v1.1/events/ifttt.textile @@ -46,7 +46,7 @@ In addition, if you are wanting data to be passed through and processed by IFTTT } ``` -In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels/overview to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. +In the future we would like provide transformation capabilities, allowing for data sent on "channels":/realtime/channels to be re-structured prior to being sent to an endpoint. For IFTTT, this would allow for channel communication to not need to adhere to the IFTTT data structure expectations. If this would be of interest to you, please "get in touch":/contact. h2(#example). Example diff --git a/content/general/versions/v1.1/firehose.textile b/content/general/versions/v1.1/firehose.textile index bcffd22f88..0e8856871e 100644 --- a/content/general/versions/v1.1/firehose.textile +++ b/content/general/versions/v1.1/firehose.textile @@ -6,7 +6,7 @@ index: 26 Our Firehose can stream your realtime data published within the Ably platform directly to another streaming or queueing service. For example, all messages published by any device on a channel could be immediately streamed to Amazon Kinesis allowing you to process this data in realtime. Firehose is offered as part of our "Ably Reactor service":https://www.ably.io/reactor but is only available to "Enterprise customers":https://www.ably.io/pricing/enterprise. -Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels/overview which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. +Using configurable rules, you can stream any of messages, presence events, and "channel lifecycle events":/realtime/channel-metadata#lifecycle-events. Unlike our "channels":/realtime/channels which follow a "pub/sub pattern":https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern where each message is delivered to any number of subscribers, our Firehose operates on the basis that each message is delivered once to your streaming or queueing server. As each message is delivered once to your streaming or queueing server, this design is commonly used to process realtime data published by Ably asynchronously. For example, using workers consuming from your stream or queue, you could persist each message of a live chat to your own database, start publishing updates once a channel becomes active, or trigger an event if a device has submitted a location that indicates that it has reached its destination. Find out why we think streams and message queues help solve many of the challenges associated with consuming pub/sub data server-side in our article: "Message queues — the right way to process and work with realtime data on your servers":https://blog.ably.io/message-queues-the-right-way-to-process-and-work-with-realtime-data-on-your-servers-2d15985301f8. diff --git a/content/general/versions/v1.1/queues.textile b/content/general/versions/v1.1/queues.textile index 6c4bcfd6cc..a799d630fd 100644 --- a/content/general/versions/v1.1/queues.textile +++ b/content/general/versions/v1.1/queues.textile @@ -46,7 +46,7 @@ All Ably accounts have access to Reactor Queue functionality, however to get sta h3(#provisioning). Provisioning Reactor Queues -Unlike "pub/sub channels":/realtime/channels/overview that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. +Unlike "pub/sub channels":/realtime/channels that can exist in any datacenter and are provisioned on-demand by clients, queues need to be provisioned in advance and exist in one region. Queues are setup "within your app dashboard":https://support.ably.io/support/solutions/articles/3000030053-how-do-i-access-my-app-dashboard and you will need to configure: @@ -404,7 +404,7 @@ When using Reactor Queues, please bear in mind that: * There is a default TTL (time-to-live) applied to all messages that is configured when you provision your queue. If a message has not been consumed from a queue within this period, it will be moved to the deadletter queue. If the TTL of the deadletter queue passes, the message is discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * There is a max message limit configured when you provision your queue. If the max message limit is reached for your queue, new messages will be moved to the deadletter queue. Once the deadletter queue reaches its max message limit, new messages will be discarded. See "account limits":https://support.ably.io/solution/articles/3000053845-do-you-have-any-connection-message-rate-or-other-limits-on-accounts. * With the AMQP protocol, it is possible to consume multiple queues from a single connection, and also to consume more than one message at a time. You will need to refer to your client library's documentation to enable these capabilities. See "this StackOverFlow answer":http://stackoverflow.com/a/17011833/139607 as a good starting point. -* Unlike our Ably "pub/sub channels":/realtime/channels/overview which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. +* Unlike our Ably "pub/sub channels":/realtime/channels which are implicitly global and distributed, our message queues are provisioned in a single physical region. You can choose the region you want your queue to exist when provisioning your queue. Typically you will want to provision a queue closest to your servers to keep the latency as low as possible. * Each message published to the queue will count towards you monthly message quota. See "billing info for more details":#below. h3(#scalability-availability). Queue Scalability and High Availability diff --git a/content/mqtt/index.textile b/content/mqtt/index.textile index e94705fc93..4ff76badc7 100644 --- a/content/mqtt/index.textile +++ b/content/mqtt/index.textile @@ -46,7 +46,7 @@ This will connect using TLS through MQTT to Ably. h2(#pub-sub). Publishing and Subscribing with MQTT -"Ably's channels":/realtime/channels/overview correlate to topics in MQTT. An example of how to publish and subscribe with the NodeJS "MQTT package":https://www.npmjs.com/package/mqtt would be as follows: +"Ably's channels":/realtime/channels correlate to topics in MQTT. An example of how to publish and subscribe with the NodeJS "MQTT package":https://www.npmjs.com/package/mqtt would be as follows: bc[nodejs]. { const mqtt = require('mqtt'); diff --git a/content/partials/types/_channel_state_change.textile b/content/partials/types/_channel_state_change.textile index a8f57fa7bf..d3d50a88dc 100644 --- a/content/partials/types/_channel_state_change.textile +++ b/content/partials/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/partials/versions/v0.8/types/_channel_state_change.textile b/content/partials/versions/v0.8/types/_channel_state_change.textile index 035783cf03..ddb7444c5d 100644 --- a/content/partials/versions/v0.8/types/_channel_state_change.textile +++ b/content/partials/versions/v0.8/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/partials/versions/v1.0/types/_channel_state_change.textile b/content/partials/versions/v1.0/types/_channel_state_change.textile index 666d641852..878d6106c1 100644 --- a/content/partials/versions/v1.0/types/_channel_state_change.textile +++ b/content/partials/versions/v1.0/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/partials/versions/v1.1/types/_channel_state_change.textile b/content/partials/versions/v1.1/types/_channel_state_change.textile index a8f57fa7bf..d3d50a88dc 100644 --- a/content/partials/versions/v1.1/types/_channel_state_change.textile +++ b/content/partials/versions/v1.1/types/_channel_state_change.textile @@ -1,4 +1,4 @@ -A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels/overview object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. +A @Ably::Models::ChannelStateChange@ChannelStateChangeARTRealtimeChannelStateChange is a type encapsulating state change information emitted by the "@Channel@":/realtime/channels object. See "@Channel#on@":/realtime/channels#on to register a listener for one or more events. h4. Attributes diff --git a/content/realtime/channels/channel-metadata.textile b/content/realtime/channel-metadata.textile similarity index 100% rename from content/realtime/channels/channel-metadata.textile rename to content/realtime/channel-metadata.textile diff --git a/content/realtime/channel-params.textile b/content/realtime/channel-params.textile deleted file mode 100644 index d2e4d76e7f..0000000000 --- a/content/realtime/channel-params.textile +++ /dev/null @@ -1,247 +0,0 @@ ---- -title: Channel Parameters -section: realtime -index: 32 -jump_to: - Help with: - - Overview#overview - - Using params with v1.1 or earlier Ably libraries#using-params-with-lib-v11 - - Using params with non-Ably transports#using-params-with-other-transports - - Examples#examples - Parameters: - - rewind#rewind ---- - -h2(#overview). Overview - -Channel parameters are a general mechanism by which a client can express properties of a channel, or of its attachment to a channel. A set of channel parameters is simply a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines. - -The methods provided for specifying channel parameters, and the currently available features, are outlined below. - -h2(#supported-params). Currently supported channel params - -- rewind := Used to request that an attachment start from some number of messages or point in time in the past. See "rewind":#rewind for more information -- delta := **In an experimental state**. Used to request that data payloads should be sent as deltas to the previous payload. "Contact us":https://www.ably.io/contact for more information and supported values - -h2(#using-params-with-lib-v11). Using channel params with v1.1 or earlier Ably client libraries - -The current Ably libraries, at version 1.1, do not expose an API for expressing channel parameters. This means that it is necessary to specify parameters in a way that is opaque to the library. - -A set of params is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. - -For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. - -Using this syntax with the Ably library means that channel parameters are specified for the lifetime of the @Channel@ instance; in order to reference the same channel, but with different channel parameters, it is necessary to get a new @Channel@ instance, using a qualified name that includes the new channel parameters. - -h3. Example - -For example, to specify the @rewind@ channel param with the value @"1"@: - -```[javascript] - const realtime = new Ably.Realtime('{{API_KEY}}'); - const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); -``` - -h2(#using-params-with-other-transports). Using params with non-Ably transports - -It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. - -A set of params is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. - -For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. - -In an SSE connection, it is also possible to specify channel parameters as a query string in the connection URL, instead of as a qualifier on an individual channel name. In this case, the given channel parameters apply to all channel attachments associated with that connection. - -h3. SSE example - -For example, to specify the @rewind@ channel param with the value @"1"@ using a querystring parameter, where it will apply to all channels: - -```[javascript] -var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; -var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); -``` - -Or to specify the same parameter but only applying to one channel of two, using a qualified channel name: - -```[javascript] - var channelOne = encodeURIComponent('[?rewind=1]channel1'); - var channelTwo = 'channel2'; - var channels = channelOne + ',' + channelTwo; - var querystring = 'v=1.2&key={{API_KEY}}&channels=' + channels'; - var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); -``` - -h2(#rewind). Rewind parameter - -The @rewind@ channel parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). - -A @rewind@ parameter can express a channel position in terms of a number of messages, or a time interval. - -A @rewind@ value that is simply a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If that attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. - -If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. - -A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. - -If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel param. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. - -At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. - -By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. - -The channel position expressed by a @rewind@ parameter has an effect only on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). - -Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier represents an error, and any attachment request will fail with an error. - -h3(#rewind-example-ably). Rewind example with an Ably client library - -To subscribe to a channel, getting the most recent message if available: - -```[jsall] - // only with ably-js v1.2 or later - const realtime = new Ably.Realtime('{{API_KEY}}'); - realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { - rewind: '1' - }).subscribe(msg => console.log("Received message: ", msg)); -``` - -```[jsall] - // with ably-js v1.1 or below - const realtime = new Ably.Realtime('{{API_KEY}}'); - const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); - channel.subscribe(msg => console.log("Received message: ", msg)); -``` - -h3(#rewind-example-sse). Rewind example with SSE - -To subscribe to a channel, getting the most recent message if available: - -```[javascript] - var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; - var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); -``` - -h3(#rewind-examples-mqtt). Rewind example with MQTT - -```[nodejs] - var mqtt = require('mqtt'); - var options = { - keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', - port: 8883 - }; - var client = mqtt.connect('mqtts:mqtt.ably.io', options); - client.on('connect', () => { - client.subscribe('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); - }); - client.on('message', (topic, message) => { - ... - }); -``` - -h2(#delta). Delta parameter - -The @delta@ channel parameter allows subscribers to expresse their desire to receive deltas (diffs) between the previous and current message instead of the current message in full on a given channel. The effects of this parameter are invisible to message senders and only affect subscribers that specify it - i.e. the sender sends messages in full and Ably computes and sends the message deltas to any subscriber which subscribed using this parameter. - -Note that requesting deltas does not guarantee that every message received will be a delta, as the server may chose to send some messages in full depending on system load and other factors. Therefore a subscriber using the @delta@ parameter should be prepared to handle a random mix of delta and full messages. - -The @delta@ parameter can take only the value @vcdiff@. VCDIFF is the format of the deltas. It is an open format specified in "RFC 3284":https://tools.ietf.org/html/rfc3284. - -Ably provides a JavaScript "delta codec library":https://github.com/ably/delta-codec-js to help you avoid writing boilerplate VCDIFF handling code. Some examples follow. - -h3(#delta-example-sse). Delta example with enveloped SSE - -```[jsall] -const key = '{{API_KEY}}'; -const channel = 'sample-app-sse'; -const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.2&key=${key}&delta=vcdiff`; -const eventSource = new EventSource(url); -const channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); - -eventSource.onmessage = (event) => { - /* event.data is JSON-encoded Ably Message (see https://www.ably.io/documentation/realtime/types#message) */ - const message = JSON.parse(event.data); - const { id, extras } = message; - let { data } = message; - - try { - if (extras && extras.delta) { - data = channelDecoder.applyBase64Delta(data, id, extras.delta.from).asUtf8String(); - } else { - channelDecoder.setBase(data, id); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); -}; -``` - -h3(#delta-example-unenv-sse). Delta example with unenveloped SSE - -```[jsall] -const key = '{{API_KEY}}'; -const channel = 'sample-app-sse'; -const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.2&key=${key}&delta=vcdiff&enveloped=false`; -const eventSource = new EventSource(url); -const channelDecoder = new DeltaCodec.VcdiffDecoder(); - -eventSource.onmessage = (event) => { - let data = event.data; - - try { - if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { - data = channelDecoder.applyBase64Delta(data).asUtf8String(); - } else { - channelDecoder.setBase(data); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); -}; -``` - -h3(#delta-example-mqtt). Delta example with MQTT - -```[jsall] -const mqtt = require('mqtt'); -const { VcdiffDecoder } = require('./lib'); - -const options = { - keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', - port: 8883 -}; -const client = mqtt.connect('mqtts:mqtt.ably.io', options); -const channelName = 'sample-app-mqtt'; -const channelDecoder = new VcdiffDecoder(); - -client.on('message', (_, payload) => { - let data = payload; - - try { - if (VcdiffDecoder.isDelta(data)) { - data = channelDecoder.applyDelta(data).asUint8Array(); - } else { - channelDecoder.setBase(data); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); -}); - -client.subscribe(`[?delta=vcdiff]${channelName}`); -``` diff --git a/content/realtime/channels/overview.textile b/content/realtime/channels.textile similarity index 98% rename from content/realtime/channels/overview.textile rename to content/realtime/channels.textile index 7a075013f0..132b23c66c 100644 --- a/content/realtime/channels/overview.textile +++ b/content/realtime/channels.textile @@ -263,14 +263,14 @@ channel.subscribe { message in h4(#rewind). Subscribing to a channel with the rewind option enabled -It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-parameters#rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. +It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-params#rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. minimize. View details - "Rewind":/realtime/channel-parameters has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. + "Rewind":/realtime/channel-params has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. - In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel parameters directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-parameters with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-parameters documentation. + In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-params with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-params documentation. - *Note* that "rewind":/realtime/channel-parameters is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + *Note* that "rewind":/realtime/channel-params is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. In addition, rewind will only apply upon *attaching* to a channel, so any subsequent subscriptions post-attach will not fetch old messages. diff --git a/content/realtime/encryption.textile b/content/realtime/encryption.textile index 2160fa922d..3bb493d4d6 100644 --- a/content/realtime/encryption.textile +++ b/content/realtime/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/history.textile b/content/realtime/history.textile index d5d4a859dd..64bea8d240 100644 --- a/content/realtime/history.textile +++ b/content/realtime/history.textile @@ -130,7 +130,7 @@ If you would prefer to just dive into code and see some examples of how to use h h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history @@ -142,11 +142,11 @@ To enable history on a channel, it is necessary to add a channel rule in the set h3(#continuous-history). Continuous history -By using "rewind":/realtime/channel-parameters#rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. +By using "rewind":/realtime/channel-params#rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. h4(#rewind). Rewind -If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-parameters#rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-parameters#rewind for further details. +If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-params#rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-params#rewind for further details. In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if the channel were @[some_metadata]my_channel@, you would specify the use of rewind via @[some_metadata?rewind=1]my_channel@. You can specify either a number of messages up to 100 to rewind to (for example @10@), or a time specifier of either seconds (@10s@), or minutes (@2m@) up to 2 minutes. diff --git a/content/realtime/index.textile b/content/realtime/index.textile index a69921ee9b..c88fb8da68 100644 --- a/content/realtime/index.textile +++ b/content/realtime/index.textile @@ -27,7 +27,7 @@ These concepts are illustrated in the diagram below: An Ably Realtime client library is responsible for: - Connection state management := Actively managing the "WebSocket":/concepts/websockets connection by reconnecting "automatically to an available datacenter":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues when a connection drops and restoring the connection state. Find out more about "the connection object and its state":/realtime/connection and "connection state recovery which provides message continuity over changing network conditions":https://support.ably.io/solution/articles/3000044639-connection-state-recovery. -- Channel management := Providing "publish and subscribe":/realtime/channels/overview capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. +- Channel management := Providing "publish and subscribe":/realtime/channels capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. - Presence := Allowing a client to "register itself as present on a channel":/realtime/presence and actively ensuring all members present on a channel are kept in-sync locally. The library proactively restores presence state on suspended channels due to long periods of disconnectedness. - Data interoperabilty := Ensuring messages and their payloads (JSON, strings or binary data) are encoded and decoded in a uniform way to ensure interoperability between all supported platforms. - Encryption := "Encrypting payloads with the optional user-generated encryption key":/realtime/encryption ensuring payloads cannot be decrypted whilst in transit or by any party without the private key. diff --git a/content/realtime/messages.textile b/content/realtime/messages.textile index 1c2725ec3b..ed9613264c 100644 --- a/content/realtime/messages.textile +++ b/content/realtime/messages.textile @@ -34,7 +34,7 @@ The Ably Realtime service allows for clients to send information with @messages@ h2(#getting-started). Getting started -The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels/overview does not exist at the time the client is attached, a "channel":/realtime/channels/overview will be created in the Ably system immediately. +The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels does not exist at the time the client is attached, a "channel":/realtime/channels will be created in the Ably system immediately. ```[javascript](code-editor:realtime/channel-publish) var realtime = new Ably.Realtime('{{API_KEY}}'); diff --git a/content/realtime/presence.textile b/content/realtime/presence.textile index 57295f23f3..f44a674c29 100644 --- a/content/realtime/presence.textile +++ b/content/realtime/presence.textile @@ -41,7 +41,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/usage.textile b/content/realtime/usage.textile index 95b5ecffac..7043e01c58 100644 --- a/content/realtime/usage.textile +++ b/content/realtime/usage.textile @@ -262,7 +262,7 @@ h6(#channels). default: channels csharp: Channels -"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels/overview and "messages":/realtime/messages/ for more information. +"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels and "messages":/realtime/messages/ for more information. h6(#connection). default: connection diff --git a/content/realtime/versions/v0.8/encryption.textile b/content/realtime/versions/v0.8/encryption.textile index d521e7302d..74c88101bc 100644 --- a/content/realtime/versions/v0.8/encryption.textile +++ b/content/realtime/versions/v0.8/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/versions/v0.8/history.textile b/content/realtime/versions/v0.8/history.textile index 6ca5a98f9d..80b615b653 100644 --- a/content/realtime/versions/v0.8/history.textile +++ b/content/realtime/versions/v0.8/history.textile @@ -121,7 +121,7 @@ channel.publish("example", data: "message data") { error in h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history @@ -227,7 +227,7 @@ inline-toc. h2. Channel object -The "Realtime @Channel@ object":/realtime/channels/overview exposes the following public method to obtain "@Message@":#message history. +The "Realtime @Channel@ object":/realtime/channels exposes the following public method to obtain "@Message@":#message history. h3. Methods diff --git a/content/realtime/versions/v0.8/index.textile b/content/realtime/versions/v0.8/index.textile index c3eafd5390..a8b6cc004c 100644 --- a/content/realtime/versions/v0.8/index.textile +++ b/content/realtime/versions/v0.8/index.textile @@ -4,7 +4,7 @@ section: realtime index: 0 --- -The Ably Realtime client libraries establish and maintain a persistent connection to Ably enabling extremely low latency broadcasting of messages and presence state. All official client library APIs are consistent across every language, provide "pub/sub functionality":/realtime/channels/overview and "presence on channels":/realtime/presence, handle both "basic and token authentication":/realtime/authentication, "manage changing network conditions":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues, include optional "symmetric encryption":/realtime/encryption and provide access to "channel, presence and metrics history":/realtime/history. +The Ably Realtime client libraries establish and maintain a persistent connection to Ably enabling extremely low latency broadcasting of messages and presence state. All official client library APIs are consistent across every language, provide "pub/sub functionality":/realtime/channels and "presence on channels":/realtime/presence, handle both "basic and token authentication":/realtime/authentication, "manage changing network conditions":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues, include optional "symmetric encryption":/realtime/encryption and provide access to "channel, presence and metrics history":/realtime/history. The Ably Realtime client library is available in "most popular languages and platforms":https://www.ably.io/download including "Javascript browser library":https://github.com/ably/ably-js, "Java":https://github.com/ably/ably-java, ".NET":https://github.com/ably/ably-dotnet, "Node.js":https://github.com/ably/ably-js, "iOS":https://github.com/ably/ably-ios, "Ruby":https://github.com/ably/ably-ruby, "Go":https://github.com/ably/ably-go and "more...":https://www.ably.io/download diff --git a/content/realtime/versions/v0.8/presence.textile b/content/realtime/versions/v0.8/presence.textile index 8bcd2fc3ad..889e30aa22 100644 --- a/content/realtime/versions/v0.8/presence.textile +++ b/content/realtime/versions/v0.8/presence.textile @@ -38,7 +38,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/versions/v0.8/usage.textile b/content/realtime/versions/v0.8/usage.textile index 14815aa715..8db5d046f3 100644 --- a/content/realtime/versions/v0.8/usage.textile +++ b/content/realtime/versions/v0.8/usage.textile @@ -291,7 +291,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/realtime/channels/overview and "messages":/realtime/messages for more information. +A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/realtime/channels and "messages":/realtime/messages for more information. h6(#client-id). default: clientId diff --git a/content/realtime/versions/v1.0/encryption.textile b/content/realtime/versions/v1.0/encryption.textile index 20bc546d0c..e0679bd130 100644 --- a/content/realtime/versions/v1.0/encryption.textile +++ b/content/realtime/versions/v1.0/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/versions/v1.0/history.textile b/content/realtime/versions/v1.0/history.textile index a8ff464f99..2d0d69d9dd 100644 --- a/content/realtime/versions/v1.0/history.textile +++ b/content/realtime/versions/v1.0/history.textile @@ -130,7 +130,7 @@ If you would prefer to just dive into code and see some examples of how to use h h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history diff --git a/content/realtime/versions/v1.0/index.textile b/content/realtime/versions/v1.0/index.textile index b0e8d73af7..563d681832 100644 --- a/content/realtime/versions/v1.0/index.textile +++ b/content/realtime/versions/v1.0/index.textile @@ -27,7 +27,7 @@ These concepts are illustrated in the diagram below: An Ably Realtime client library is responsible for: - Connection state management := Actively managing the "WebSocket":/concepts/websockets connection by reconnecting "automatically to an available datacenter":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues when a connection drops and restoring the connection state. Find out more about "the connection object and its state":/realtime/connection and "connection state recovery which provides message continuity over changing network conditions":https://support.ably.io/solution/articles/3000044639-connection-state-recovery. -- Channel management := Providing "publish and subscribe":/realtime/channels/overview capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. +- Channel management := Providing "publish and subscribe":/realtime/channels capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. - Presence := Allowing a client to "register itself as present on a channel":/realtime/presence and actively ensuring all members present on a channel are kept in-sync locally. The library proactively restores presence state on suspended channels due to long periods of disconnectedness. - Data interoperabilty := Ensuring messages and their payloads (JSON, strings or binary data) are encoded and decoded in a uniform way to ensure interoperability between all supported platforms. - Encryption := "Encrypting payloads with the optional user-generated encryption key":/realtime/encryption ensuring payloads cannot be decrypted whilst in transit or by any party without the private key. diff --git a/content/realtime/versions/v1.0/messages.textile b/content/realtime/versions/v1.0/messages.textile index 3a84116ea4..23b7b5ba55 100644 --- a/content/realtime/versions/v1.0/messages.textile +++ b/content/realtime/versions/v1.0/messages.textile @@ -34,7 +34,7 @@ The Ably Realtime service allows for clients to send information with @messages@ h2(#getting-started). Getting started -The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels/overview does not exist at the time the client is attached, a "channel":/realtime/channels/overview will be created in the Ably system immediately. +The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels does not exist at the time the client is attached, a "channel":/realtime/channels will be created in the Ably system immediately. ```[javascript](code-editor:realtime/channel-publish) var realtime = new Ably.Realtime('{{API_KEY}}'); diff --git a/content/realtime/versions/v1.0/presence.textile b/content/realtime/versions/v1.0/presence.textile index f149817fec..0c91215230 100644 --- a/content/realtime/versions/v1.0/presence.textile +++ b/content/realtime/versions/v1.0/presence.textile @@ -41,7 +41,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/versions/v1.0/usage.textile b/content/realtime/versions/v1.0/usage.textile index 4dd7b42754..336bfc33b2 100644 --- a/content/realtime/versions/v1.0/usage.textile +++ b/content/realtime/versions/v1.0/usage.textile @@ -247,7 +247,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/realtime/channels/overview and "messages":/realtime/messages/ for more information. +A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/realtime/channels and "messages":/realtime/messages/ for more information. h6(#client-id). default: clientId diff --git a/content/realtime/versions/v1.1/encryption.textile b/content/realtime/versions/v1.1/encryption.textile index 2160fa922d..3bb493d4d6 100644 --- a/content/realtime/versions/v1.1/encryption.textile +++ b/content/realtime/versions/v1.1/encryption.textile @@ -27,7 +27,7 @@ Ably client libraries support built-in symmetric encryption of message content, h2(#getting-started). Getting started -"Channels":/realtime/channels/overview can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: +"Channels":/realtime/channels can be easily configured to automatically encrypt and decrypt all message payloads using the secret @key@ provided in the "channel options":/realtime/types#channel-options. Below is a simple example: ```[javascript](code-editor:realtime/channel-encrypted) Ably.Realtime.Crypto.generateRandomKey(function(err, key) { diff --git a/content/realtime/versions/v1.1/history.textile b/content/realtime/versions/v1.1/history.textile index 07e2a2e08b..64bea8d240 100644 --- a/content/realtime/versions/v1.1/history.textile +++ b/content/realtime/versions/v1.1/history.textile @@ -130,7 +130,7 @@ If you would prefer to just dive into code and see some examples of how to use h h2(#channel-and-presence). Channel & Presence history -Both the "@Channel@":/realtime/channels/overview and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels/overview object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. +Both the "@Channel@":/realtime/channels and "@Presence@":/realtime/presence objects provide history. The "@Channel@":/realtime/channels object provides the history of "@Message@":#message objects published on the channel, whereas the "@Presence@":/realtime/presence object provides presence event history of that channel i.e. members entering, updating or leaving the channel as "@PresenceMessage@":#presence-message objects. h3(#persisted-history). Enabling persistent history diff --git a/content/realtime/versions/v1.1/index.textile b/content/realtime/versions/v1.1/index.textile index a69921ee9b..c88fb8da68 100644 --- a/content/realtime/versions/v1.1/index.textile +++ b/content/realtime/versions/v1.1/index.textile @@ -27,7 +27,7 @@ These concepts are illustrated in the diagram below: An Ably Realtime client library is responsible for: - Connection state management := Actively managing the "WebSocket":/concepts/websockets connection by reconnecting "automatically to an available datacenter":https://support.ably.io/solution/articles/3000044636-routing-around-network-and-dns-issues when a connection drops and restoring the connection state. Find out more about "the connection object and its state":/realtime/connection and "connection state recovery which provides message continuity over changing network conditions":https://support.ably.io/solution/articles/3000044639-connection-state-recovery. -- Channel management := Providing "publish and subscribe":/realtime/channels/overview capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. +- Channel management := Providing "publish and subscribe":/realtime/channels capabilities over channels and actively managing them by queueing published messages when disconnected and "retrieving missed messages":https://support.ably.io/solution/articles/3000044639-connection-state-recovery once reconnected. The library proactively reattaches channels that become suspended due to long periods of disconnectedness. - Presence := Allowing a client to "register itself as present on a channel":/realtime/presence and actively ensuring all members present on a channel are kept in-sync locally. The library proactively restores presence state on suspended channels due to long periods of disconnectedness. - Data interoperabilty := Ensuring messages and their payloads (JSON, strings or binary data) are encoded and decoded in a uniform way to ensure interoperability between all supported platforms. - Encryption := "Encrypting payloads with the optional user-generated encryption key":/realtime/encryption ensuring payloads cannot be decrypted whilst in transit or by any party without the private key. diff --git a/content/realtime/versions/v1.1/messages.textile b/content/realtime/versions/v1.1/messages.textile index 1c2725ec3b..ed9613264c 100644 --- a/content/realtime/versions/v1.1/messages.textile +++ b/content/realtime/versions/v1.1/messages.textile @@ -34,7 +34,7 @@ The Ably Realtime service allows for clients to send information with @messages@ h2(#getting-started). Getting started -The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels/overview does not exist at the time the client is attached, a "channel":/realtime/channels/overview will be created in the Ably system immediately. +The Ably Realtime client library provides a straightforward API for "publishing":#message-publish and "subscribing":#message-subscription to messages on a "channel":/realtime/channels. If the "channel":/realtime/channels does not exist at the time the client is attached, a "channel":/realtime/channels will be created in the Ably system immediately. ```[javascript](code-editor:realtime/channel-publish) var realtime = new Ably.Realtime('{{API_KEY}}'); diff --git a/content/realtime/versions/v1.1/presence.textile b/content/realtime/versions/v1.1/presence.textile index 57295f23f3..f44a674c29 100644 --- a/content/realtime/versions/v1.1/presence.textile +++ b/content/realtime/versions/v1.1/presence.textile @@ -41,7 +41,7 @@ Presence enables clients to be aware of other clients that are currently "presen h2(#getting-started). Getting started -The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels/overview object to enter a channel and subscribe to presence events. +The @Presence@ object provides a straightforward API to subscribe to presence events such as members entering or leaving, retrieve a list of members present, or register the connected client as "present" on a channel. Here is a simple presence example using the "@presence@@Presence@":/realtime/channels#presence propertyfieldattribute of the "@Channel@":/realtime/channels object to enter a channel and subscribe to presence events. ```[javascript](code-editor:realtime/presence-simple) var realtime = new Ably.Realtime({ diff --git a/content/realtime/versions/v1.1/usage.textile b/content/realtime/versions/v1.1/usage.textile index e3b3fd73a4..c640dd5091 100644 --- a/content/realtime/versions/v1.1/usage.textile +++ b/content/realtime/versions/v1.1/usage.textile @@ -262,7 +262,7 @@ h6(#channels). default: channels csharp: Channels -"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels/overview and "messages":/realtime/messages/ for more information. +"@Channels@":/realtime/channels#channels-object is a reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. You can use the "@Get@":/realtime/channels#get method of this to get a @Channel@ instance. See "channels":/realtime/channels and "messages":/realtime/messages/ for more information. h6(#connection). default: connection diff --git a/content/rest/versions/v0.8/usage.textile b/content/rest/versions/v0.8/usage.textile index 1bdbae579d..fa8b6b3214 100644 --- a/content/rest/versions/v0.8/usage.textile +++ b/content/rest/versions/v0.8/usage.textile @@ -238,7 +238,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. +A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. h6(#client-id). default: clientId diff --git a/content/rest/versions/v1.0/usage.textile b/content/rest/versions/v1.0/usage.textile index 9942830a03..75c67a2edf 100644 --- a/content/rest/versions/v1.0/usage.textile +++ b/content/rest/versions/v1.0/usage.textile @@ -274,7 +274,7 @@ h6(#channels). default: channels csharp: Channels -A reference to the "@Channel@":/realtime/channels/overview collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. +A reference to the "@Channel@":/realtime/channels collection instance for this library indexed by the channel name. See "channels":/rest/channels and "messages":/rest/messages for more information. h6(#client-id). default: clientId diff --git a/content/root/best-practice-guide.textile b/content/root/best-practice-guide.textile index afe101c81c..4b3fadcae5 100644 --- a/content/root/best-practice-guide.textile +++ b/content/root/best-practice-guide.textile @@ -21,7 +21,7 @@ Ably Realtime is a cloud-based platform that allows you to easily integrate real h3(#pubsub). Publish and Subscribe (Pub/Sub) -You can publish data to named "channels":/realtime/channels/overview within Ably's platform and the platform will make sure that all clients subscribed to these channels will receive the data in realtime. +You can publish data to named "channels":/realtime/channels within Ably's platform and the platform will make sure that all clients subscribed to these channels will receive the data in realtime. h3(#notifications). Notifications diff --git a/content/tutorials/channel-enumeration-rest.textile b/content/tutorials/channel-enumeration-rest.textile index fa4ea862ed..e535f424b4 100644 --- a/content/tutorials/channel-enumeration-rest.textile +++ b/content/tutorials/channel-enumeration-rest.textile @@ -152,7 +152,7 @@ Make sure that you've enabled the channel metadata permission on your API key. h2(#next-steps). Next Steps -1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels/overview & "messages":https://www.ably.io/documentation/realtime/messages documentation. +1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels & "messages":https://www.ably.io/documentation/realtime/messages documentation. 2. If you would like to check out the other related tutorials to work with channel metadata, see the "Channel Lifecycle Events":/tutorials/channel-lifecycle-events and "Channel Occupancy Events":/tutorials/channel-occupancy-events tutorials. 3. Learn more about "Ably features":https://www.ably.io/features by going through our other "Ably tutorials":https://www.ably.io/tutorials 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/channel-lifecycle-events.textile b/content/tutorials/channel-lifecycle-events.textile index 2610561b4d..6b32e8d5c7 100644 --- a/content/tutorials/channel-lifecycle-events.textile +++ b/content/tutorials/channel-lifecycle-events.textile @@ -177,7 +177,7 @@ h2(#live-demo). Step - 5 Live Demo h2(#next-steps). Next Steps -1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels/overview & "messages":https://www.ably.io/documentation/realtime/messages documentation. +1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels & "messages":https://www.ably.io/documentation/realtime/messages documentation. 2. If you would like to check out the other related tutorials to work with channel metadata, see the "Channel Occupancy Events":/tutorials/channel-occupancy-events and "Channel Enumeration":/tutorials/channel-enumeration-rest tutorials . 3. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/channel-occupancy-events.textile b/content/tutorials/channel-occupancy-events.textile index d4f592a34b..9e6c74a191 100644 --- a/content/tutorials/channel-occupancy-events.textile +++ b/content/tutorials/channel-occupancy-events.textile @@ -223,7 +223,7 @@ Ably Channel Occupancy Events - Demo h2(#next-steps). Next Steps -1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels/overview & "messages":https://www.ably.io/documentation/realtime/messages documentation. +1. If you would like to find out more about how channels and publishing or subscribing to messages work, see the realtime "channels":https://www.ably.io/documentation/realtime/channels & "messages":https://www.ably.io/documentation/realtime/messages documentation. 2. If you would like to check out the other related tutorials to work with channel metadata, see the "Channel Lifecycle Events":/tutorials/channel-lifecycle-events and "Channel Enumeration":/tutorials/channel-enumeration-rest tutorials. 3. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/newsfeed-react.textile b/content/tutorials/newsfeed-react.textile index a900a6f389..543ec4de9b 100644 --- a/content/tutorials/newsfeed-react.textile +++ b/content/tutorials/newsfeed-react.textile @@ -570,7 +570,7 @@ To try this example yourself, @@ -792,7 +792,7 @@ blang[python]. h2(#next-steps). Next steps -1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels/overview & "messages":/realtime/messages documentation +1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels & "messages":/realtime/messages documentation 2. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 3. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works 4. "Get in touch if you need help":https://www.ably.io/contact diff --git a/content/tutorials/reactjs-realtime-commenting.textile b/content/tutorials/reactjs-realtime-commenting.textile index a2701d507e..23499ff368 100644 --- a/content/tutorials/reactjs-realtime-commenting.textile +++ b/content/tutorials/reactjs-realtime-commenting.textile @@ -474,7 +474,7 @@ to start the web server and open the browser. h2. Next steps -1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels/overview & "messages":/realtime/messages documentation +1. If you would like to find out more about how channels, publishing and subscribing works, see the Realtime "channels":/realtime/channels & "messages":/realtime/messages documentation 2. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 3. Learn more about Ably's "history feature":https://www.ably.io/tutorials/history#lang-javascript 4. Gain a good technical "overview of how the Ably realtime platform works":https://www.ably.io/documentation/how-ably-works diff --git a/content/tutorials/sse-and-http-streaming.textile b/content/tutorials/sse-and-http-streaming.textile index 3e015a5936..3be96f190c 100644 --- a/content/tutorials/sse-and-http-streaming.textile +++ b/content/tutorials/sse-and-http-streaming.textile @@ -192,7 +192,7 @@ blang[python]. print("Channel: %s - Message: %s - %s " % (message['channel'], message['name'], message['data'])) ``` - Here, we defined the @apiKey@ variable, which should be replaced with your Ably API key. We then defined our Ably "channels":/realtime/channels/overview with a variable named @channels@. We've added a simple check to see if the API key was in fact replaced. Next, we defined a variable called @url@, which is a template string, feeding in our @apiKey@ and @channels@. Notice that the route of this URL is @/sse@, which means we want to listen to the HTTP event streams from the server. + Here, we defined the @apiKey@ variable, which should be replaced with your Ably API key. We then defined our Ably "channels":/realtime/channels with a variable named @channels@. We've added a simple check to see if the API key was in fact replaced. Next, we defined a variable called @url@, which is a template string, feeding in our @apiKey@ and @channels@. Notice that the route of this URL is @/sse@, which means we want to listen to the HTTP event streams from the server. We then feed this URL to our @with_urllib3@ function, which attempts to fetch the stream, then passing the response to our @sseclient@, listening for the events. Once we get any of these events, we print the details to our console. To see this in action, run the python file with the @pythong subscriber.py@ command. You should get a log of new messages being published by the publisher we earlier set up. Note that in our subscriber, we've not included the Ably SDK but directly subscribed to the data stream. diff --git a/content/tutorials/trainapp-fitbit.textile b/content/tutorials/trainapp-fitbit.textile index 859c497ae4..2f7dc5f762 100644 --- a/content/tutorials/trainapp-fitbit.textile +++ b/content/tutorials/trainapp-fitbit.textile @@ -559,7 +559,7 @@ to start the web server and open the browser. h2. Next steps -1. If you would like to find out more about how channels and how publishing & subscribing works, see the realtime "channels":/realtime/channels/overview & "messages":/realtime/messages documentation +1. If you would like to find out more about how channels and how publishing & subscribing works, see the realtime "channels":/realtime/channels & "messages":/realtime/messages documentation 2. Learn more about "Channel Occupancy Events":https://www.ably.io/tutorials/channel-occupancy-events 3. Learn more about "Ably features":https://www.ably.io/features by stepping through our other "Ably tutorials":https://www.ably.io/tutorials 4. Learn more about "Fitbit":https://community.fitbit.com/t5/SDK-Development/bd-p/sdk diff --git a/content/tutorials/vue-tictactoe.textile b/content/tutorials/vue-tictactoe.textile index 4382449e0c..3c52b4e36c 100644 --- a/content/tutorials/vue-tictactoe.textile +++ b/content/tutorials/vue-tictactoe.textile @@ -1248,7 +1248,7 @@ And then run the demo locally by adding your "Ably API key":https://support.ably h2. Next steps -1. Find out more about Realtime "channels":/realtime/channels/overview & "messages":/realtime/messages +1. Find out more about Realtime "channels":/realtime/channels & "messages":/realtime/messages 2. "Find out more about Presence":/realtime/presence 3. "Find out more about History":/realtime/history 4. "Find out more about Authentication":/realtime/authentication diff --git a/data/jsbins.yaml b/data/jsbins.yaml index 3059eaa581..6aa55b613b 100644 --- a/data/jsbins.yaml +++ b/data/jsbins.yaml @@ -42,7 +42,7 @@ jsbin_hash: Sf9QPfpwxOvNcKy+KTQKXHq8dbc=: umikub 6voT8sjZ4GnNONoP3sW/Uaq2GkE=: aqalul 5SY9KnghzlKVnF/NlXih5jySnug=: utulow - L26ZVUkYlizKBpvX2MKx6qwqn50=: ufosih + heTWkNAvL1s99rFokByoTphFgV4=: itubin jsbin_id: adapters/pusher-pub-sub: eBxLJU1YqdX+JW9JQY70S4iQfmU= adapters/pubnub-pub-sub: pzHKfCW4/o2wDnCfbg1m0Pkl7v8= @@ -84,6 +84,6 @@ jsbin_id: sse/sse: 5SY9KnghzlKVnF/NlXih5jySnug= sse/eventstream: 6voT8sjZ4GnNONoP3sW/Uaq2GkE= rest/batch-presence: cHvxfaSCnHR6qzdutJZ/TZWK0FE= - realtime/rewind: L26ZVUkYlizKBpvX2MKx6qwqn50= + realtime/rewind: heTWkNAvL1s99rFokByoTphFgV4= authentication/jwt-token: Q0XIw74KKfK3Zv34fqKSck4ip5U= realtime/connection-recover: Sf9QPfpwxOvNcKy+KTQKXHq8dbc= From 5e6deafd7b0ab90666ea10d564fec180b15755f6 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Mon, 1 Jun 2020 18:08:07 +0100 Subject: [PATCH 10/47] Resolving a number of matt's comments --- content/realtime/channels.textile | 4 ++-- .../channels/channel-parameters/deltas.textile | 12 +++++++----- .../channels/channel-parameters/overview.textile | 2 +- .../channels/channel-parameters/rewind.textile | 7 ------- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/content/realtime/channels.textile b/content/realtime/channels.textile index 132b23c66c..df546bb974 100644 --- a/content/realtime/channels.textile +++ b/content/realtime/channels.textile @@ -151,8 +151,8 @@ h5(#setting-channel-parameters). Setting channel parameters Channel parameters allow a client to set the properties of a channel. The are two parameters that can be specified: -* "rewind":/realtime/channels/channel-parameters/rewind -* "delta":/realtime/channels/channel-parameters/deltas +- rewind := Used to request that an attachment start from a given number of messages or point in time in the past. See "rewind":/realtime/channels/channel-parameters/rewind for more information. +- delta := Used to request that data payloads should be sent as deltas to the previous payload. See "deltas":/realtime/channels/channel-parameters/deltas for more information. bc[jsall]. const realtime = new Ably.Realtime('{{API_KEY}}'); const channelOptions = { diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index dc59f42856..2f8b933e91 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -18,7 +18,7 @@ Delta mode is a way for a client to subscribe to a channel so that message paylo This is useful for channels that carry messages representing a series of updates to a particular object or document with a significant degree of similarily between successive messages. The client can apply the delta to the previous message to obtain the full payload. Using delta mode can signficantly reduce the encoded size of each message in the case that message payloads change by differences that are small relative to the size of the value. This reduction in size can reduce bandwidth costs, reduce transit latencies, and enable greater message throughput on a connection. -Currently the delta mode implementation supports a single representation of a delta, "VCDIFF":https://tools.ietf.org/html/rfc3284. However, the protocol and API are designed to allow other representations to be used in the future. +The delta mode implementation supports a single representation of a delta, "VCDIFF":https://tools.ietf.org/html/rfc3284. Subscribing in delta mode is enabled for a given channel by specifying a @delta@ "channel parameter":/realtime/channels/channel-parameters/overview with the value @vcdiff@. This will cause delta messages to be generated by the server and sent to the client, and the library reconstitutes the original message payload. Messages on the channel are delivered to the subscriber's listener in the same way as with a normal subscription. @@ -26,13 +26,13 @@ h2(#delta-processing). Delta processing Deltas apply to the principal payload of a @Message@ published via Ably, which is the @data@ member. Other elements of a message, such as @clientId@, @name@, or @extras@ are unchanged by use of deltas and are not compressed. -Deltas are supported for realtime subscriptions only. Messages retrieved via the history API, and messages delivered to Reactor endpoints, are not compressed. +Deltas are supported for realtime subscriptions only. Messages retrieved via "history":/realtime/history, and messages delivered to "Reactor integrations":https://www.ably.io/reactor, are not compressed. Delta compression via @vcdiff@ is supported for all payloads, whether string, binary, or JSON-encoded. The delta algorithm processes message payloads as opaque binaries and has no dependency on the stucture of the payload - it does not process line-oriented diffs, for example. In principle, @vcdiff@ deltas can be applied to encrypted message payloads, but in practice this provides no benefit because there is no similarity between successive encrypted payloads even on identical or near-identical plaintext message payloads. Delta compression is a subscriber-specified option only - the publisher has no control over whether or not deltas are generated for any given message; the processing is performed if there is at least one subscriber on a channel that has requested a delta-mode subscription. -There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question, for the region in question. When there are multiple publishers in multiple regions, publishing messages nearly simultaneously, the ordering of messages delievred to subscribers can be different in different regions, depending on actual region-to-region transit latencies; in this case, deltas are generated based on the actual message order in each region, and subscribers are delivered a sequence of delta messages that reflects that regional order. +There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question, for the region in question. When there are multiple publishers in multiple regions, publishing messages nearly simultaneously, the ordering of messages delivered to subscribers can be different in different regions, depending on actual region-to-region transit latencies; in this case, deltas are generated based on the actual message order in each region, and subscribers are delivered a sequence of delta messages that reflects that regional order. Delta mode, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. The effectiveness of delta mode - that is, whether or not there is a material saving in payload size - is dependent on the level of similarity between successive payloads. Therefore, if a channel carries messages from multiple sources or streams that are dissimilar, then delta processing might not result in a useful size reduction, even if the messages in each individual stream are similar; it depends on the specific sequence of messages that occurs in the channel, in the region in question. @@ -41,7 +41,7 @@ If a delta is generated and it results in a difference that is not appreciably s A channel subscriber can experience a discontinuity in the sequence of messages it receives on a given channel for the following reasons: * The connection can drop, and there will be a discontinuity of the client is unable to reconnect within the two-minute window it is allowed to preserve connection continuity. -* The outbound connection might have been rate-limited, which causes some messages to be dropped +* The outbound connection might have been rate-limited, which causes some messages to be dropped. * There might have been some internal error in the Ably system which leads to the server being unable to preserve continuity on the channel. In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. @@ -103,7 +103,7 @@ When subscribing without an Ably library, then the channel @delta@ parameter mus Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. -Examples of such transports are MQTT, and SSE in non-enveloped mode. In order to assist applications that use these transports, the @vcdiff@ decoder libraries can check for the @vcdiff@ magic number at the start of the message payload as an inexact method of determining whether or not the message is a regular message or a delta. Note that, in order to rely on that check, you need to know that that magic number will not be present in any valid (uncompressed) message in your app. No valid JSON value, for example, will match the @vcdiff@ header check, so it is safe to perform this sniffing on JSON message payloads. +Examples of such transports are MQTT, and SSE in non-enveloped mode. In order to assist applications that use these transports, the @vcdiff@ decoder libraries can check for the @vcdiff@ header at the start of the message payload as an inexact method of determining whether or not the message is a regular message or a delta. Note that, in order to rely on that check, you need to know that that header will not be present in any valid (uncompressed) message in your app. No valid JSON value, for example, will match the @vcdiff@ header check, so it is safe to perform this sniffing on JSON message payloads. h4(#delta-example-sse). Delta example with SSE @@ -142,6 +142,8 @@ You can subscribe to messages in delta mode, using the SSE transport, as follows h4(#delta-example-unenv-sse). Delta example with unenveloped SSE +For more information on enveloped and uneveloped SSE, please see the "SSE API":/sse#sse + ```(() => { const key = '{{API_KEY}}'; const channel = 'sample-app-sse'; diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 5d2d6ccf2e..234d2bc487 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -52,7 +52,7 @@ h2(#using-parameters-with-other-transports). Using parameters with non-Ably tran It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. -A set of params is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. +A set of parameters is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index a482ad1376..6e3881b9b8 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -51,13 +51,6 @@ To subscribe to a channel, getting the most recent message if available: }).subscribe(msg => console.log("Received message: ", msg)); ``` -```[jsall] - // with ably-js v1.1 or below - const realtime = new Ably.Realtime('{{API_KEY}}'); - const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); - channel.subscribe(msg => console.log("Received message: ", msg)); -``` - h3(#rewind-example-sse). Rewind example with SSE To subscribe to a channel, getting the most recent message if available: From e1644843b6c54626194238bf915b564393cb778c Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 10:50:30 +0100 Subject: [PATCH 11/47] Added delta JSBin code samples --- .../code/realtime/channel-deltas-size.code | 147 ++++++++++++++++++ content/code/realtime/channel-deltas.code | 74 +++++++++ data/jsbins.yaml | 4 + 3 files changed, 225 insertions(+) create mode 100644 content/code/realtime/channel-deltas-size.code create mode 100644 content/code/realtime/channel-deltas.code diff --git a/content/code/realtime/channel-deltas-size.code b/content/code/realtime/channel-deltas-size.code new file mode 100644 index 0000000000..63e6c9782a --- /dev/null +++ b/content/code/realtime/channel-deltas-size.code @@ -0,0 +1,147 @@ +[--- Javascript ---] +var clientOptions = { + key: '{{API_KEY}}', + plugins: { + vcdiff: { + decode: decodeAndCountSize + } + } + }; + +var deltaChannelOptions = { + params: { + delta: 'vcdiff', + rewind: 10 + } + }; + +var ably = new Ably.Realtime(clientOptions); + +var deltaChannel = ably.channels.get('[product:cttransit/gtfsr?rewind=10]vehicle:all', deltaChannelOptions); + +var channel = ably.channels.get('[product:cttransit/gtfsr?rewind=10]vehicle:all'); + +var receivedLogNotDeltas = document.getElementById('received-not-deltas'); +var receivedLogDeltas = document.getElementById('received-deltas'); +var totalWithoutDeltas = document.getElementById('no-delta'); +var totalWithDeltas = document.getElementById('delta'); + +/* Subscribe to a channel normally */ +channel.subscribe(function(message, err) { + var size = getMessageSize(message); + console.log(size); + totalWithoutDeltas.innerHTML = parseInt(totalWithoutDeltas.innerHTML, 10) + size; + receivedLogNotDeltas.insertAdjacentHTML('afterbegin', '
  • ' + JSON.stringify(message.data) + '
  • '); +}); + +/* Subscribe to a channel using deltas */ +deltaChannel.subscribe(function(message) { + receivedLogDeltas.insertAdjacentHTML('afterbegin', '
  • ' + JSON.stringify(message.data) + '
  • '); +}); + +/* Recursively work out the size of the message's elements */ +function getMessageSize(message) { + var bytes = 0; + if (typeof message === 'boolean') { + bytes += 4; + } else if (typeof message === 'string') { + bytes += message.length * 2; + } else if(typeof message === 'object') { + for (var i in message) { + /* Calculate the size of components of the object */ + bytes += getMessageSize(message[i]); + } + } + return bytes; +} + +/* Wrapper for the vcdiff decoder, allowing us to check the size of the original diff*/ +function decodeAndCountSize(delta, source) { + var result = decoder.decode(delta, source); + totalWithDeltas.innerHtml = parseInt(totalWithDeltas.innerHTML, 10) + message.getMessageSize(); + return result; +} +[--- /Javascript ---] + +[--- HTML ---] + + + + + + +

    Ably realtime deltas comparison

    +

    A simple example demonstrating how using deltas compares to not using deltas.

    +

    This example by default is subscribed to the CTtransit bus source, found on the Ably Hub. If you want to test this on one of your own channels, you can replace the API key with one of your own.

    + +

    Cumulative size of messages sent without deltas: 0 Bytes

    +

    Cumulative size of messages sent with deltas: 0 Bytes

    +
    +

    No deltas output

    +
      + +

      Deltas output

      +
        + +
        + + +[--- /HTML ---] + +[--- CSS ---] +body { + font-family: Arial, Sans Serif; + font-size: 13px; + min-width: 700px; +} + +h1 { + font-family: Arial, Sans Serif; + font-size: 18px; +} + +a, a:visited, a:active { + color: #ed760a; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +section { + padding: 10px 4px; + column-count: 2; + column-gap: 5px; +} + +h2 { + margin: 0 auto 4px; + text-align: center; +} + +ul { + display: block; + height: calc(100vh - 230px); + margin:0; + padding:0; + border: 1px solid #CCC; + overflow: scroll; + background-color: #EEE; + +} + +li { + padding: 2px 5px; + list-style: none; + line-height: 2em; +} + +li:nth-child(even) { + background:#ccc; +} + +section { + column-count: 2; +} +[--- /CSS ---] diff --git a/content/code/realtime/channel-deltas.code b/content/code/realtime/channel-deltas.code new file mode 100644 index 0000000000..0ef0572dc2 --- /dev/null +++ b/content/code/realtime/channel-deltas.code @@ -0,0 +1,74 @@ +[--- Javascript ---] +var apiKey = '{{API_KEY}}'; +var channelName = '{{RANDOM_CHANNEL_NAME}}'; +var realtimePublisher = new Ably.Realtime({ key: apiKey }); + +/* Initialize subscriber with delta plugin. Makes use of the vcdiff-decoder we've included in the HTML */ +var realtimeSubscriber = new Ably.Realtime({ key: apiKey, + plugins: { + vcdiff: vcdiffDecoder + } + }); +var deltaChannelOptions = { + params: { + delta: 'vcdiff' + } + }; + +var channelPublisher = realtimePublisher.channels.get(channelName); + +/* Specify in the channel options to use deltas for this channel */ +var channelSubscriber = realtimeSubscriber.channels.get(channelName, deltaChannelOptions); + +$('input#publish').on('click', function() { + show('Publishing message', 'orange'); + channelPublisher.publish('event', 'data', function(err) { + if (err) { + show('✗ Publish failed: ' + err.message, 'red'); + } else { + show('✓ Publish successful', 'green'); + } + }); +}); + +channelSubscriber.subscribe(function(message) { + show('⬅ Received message on subscription', 'green'); +}); + +function show(status, color) { + $('#channel-status').append($('
      • ').text(status).css('color', color)); +} +[--- /Javascript ---] + +[--- HTML ---] + + + +

        Ably Deltas Example

        + +

        In this example, we demonstrate the simplest way to subscribe to deltas on a channel. See our deltas documentation for more details. + +

        + +
        + +
          +[--- /HTML ---] + +[--- CSS ---] +body { + font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +h1 { + background: url('//jsbin-files.ably.io/images/logo.png') no-repeat; + font-size: 18px; + font-weight: bold; + padding: 8px 0 0 120px; + height: 42px; +} + +.row { + margin-bottom: 1em; +} +[--- /CSS ---] \ No newline at end of file diff --git a/data/jsbins.yaml b/data/jsbins.yaml index 6aa55b613b..dba2cab51a 100644 --- a/data/jsbins.yaml +++ b/data/jsbins.yaml @@ -43,6 +43,8 @@ jsbin_hash: 6voT8sjZ4GnNONoP3sW/Uaq2GkE=: aqalul 5SY9KnghzlKVnF/NlXih5jySnug=: utulow heTWkNAvL1s99rFokByoTphFgV4=: itubin + UjxZZTfXMcghYm5u6mmtFfDVdHc=: iyoqim + JtTGXp3eHSfA3TMvP5uLAjBOEmA=: ufopek jsbin_id: adapters/pusher-pub-sub: eBxLJU1YqdX+JW9JQY70S4iQfmU= adapters/pubnub-pub-sub: pzHKfCW4/o2wDnCfbg1m0Pkl7v8= @@ -87,3 +89,5 @@ jsbin_id: realtime/rewind: heTWkNAvL1s99rFokByoTphFgV4= authentication/jwt-token: Q0XIw74KKfK3Zv34fqKSck4ip5U= realtime/connection-recover: Sf9QPfpwxOvNcKy+KTQKXHq8dbc= + realtime/channel-deltas: UjxZZTfXMcghYm5u6mmtFfDVdHc= + realtime/channel-deltas-size: JtTGXp3eHSfA3TMvP5uLAjBOEmA= From 96128ca92b1c32df69ebcb3555ce59e95dbf9498 Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 10:58:07 +0100 Subject: [PATCH 12/47] Updated deltas code samples --- .../channel-parameters/deltas.textile | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 2f8b933e91..6ccbdf3280 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -12,7 +12,7 @@ jump_to: h2(#overview). Overview -The @delta@ parameter enables delta compression. It is applied on the channel you are subscribing to, enabling delta mode. +The @delta@ parameter enables delta compression. It is applied on the channel you are subscribing to, enabling delta mode. Delta mode is a way for a client to subscribe to a channel so that message payloads sent contain only the difference (ie the delta) between the present message and the previous message on the channel. @@ -42,9 +42,9 @@ A channel subscriber can experience a discontinuity in the sequence of messages * The connection can drop, and there will be a discontinuity of the client is unable to reconnect within the two-minute window it is allowed to preserve connection continuity. * The outbound connection might have been rate-limited, which causes some messages to be dropped. -* There might have been some internal error in the Ably system which leads to the server being unable to preserve continuity on the channel. +* There might have been some internal error in the Ably system which leads to the server being unable to preserve continuity on the channel. -In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. +In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. If a subscriber has a delta-mode subscription and the channel in question experiences a discontunity, then a non-delta message will be delivered to the client as the first message after the discontinuity. This ensures that lost messages do not prevent the client from reconstituting messages from deltas. @@ -57,8 +57,16 @@ The most common way to subscribe to Ably channels is via a realtime connection, For many libraries this requires no change on the part of the caller except to specify the @delta@ "channel parameter":/realtime/channels/channel-parameters/overview when subscribing to the channel. In some libraries, the @vcdiff@ delta decoding library is excluded from the default library distribution in order to avoid bloating the library. In these cases, it is also necessary to supply the delta decoder plugin when instancing the Ably library. -```[jsall] - const vcdiffPlugin = require('{{vcdiff-plugin}}') +```[js](code-editor:realtime/channel-deltas) + /* Make sure to include in your head */ + const realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); + realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { + delta: 'vcdiff' + }).subscribe(msg => console.log("Received message: ", msg)); +``` + +```[nodejs] + const vcdiffPlugin = require('@ably/vcdiff-decoder'); const realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { delta: 'vcdiff' @@ -101,7 +109,7 @@ In order to reconstruct the original message, the @vcdiff@ decoder algorithm nee When subscribing without an Ably library, then the channel @delta@ parameter must be specified using a "qualified channel name":/realtime/channels/channel-parameters/overview. In the case of SSE, it is also possible to specify channel parameters as regular query parameters on the connection URL. -Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. +Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. Examples of such transports are MQTT, and SSE in non-enveloped mode. In order to assist applications that use these transports, the @vcdiff@ decoder libraries can check for the @vcdiff@ header at the start of the message payload as an inexact method of determining whether or not the message is a regular message or a delta. Note that, in order to rely on that check, you need to know that that header will not be present in any valid (uncompressed) message in your app. No valid JSON value, for example, will match the @vcdiff@ header check, so it is safe to perform this sniffing on JSON message payloads. From 2940a0b383a18118b0bef987e7f5f268604fbe02 Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 11:22:43 +0100 Subject: [PATCH 13/47] Shorted deltas code sample --- content/realtime/channels/channel-parameters/deltas.textile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 6ccbdf3280..a9772741d7 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -126,7 +126,8 @@ You can subscribe to messages in delta mode, using the SSE transport, as follows const channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); eventSource.onmessage = (event) => { - /* event.data is JSON-encoded Ably Message (see https://www.ably.io/documentation/realtime/types#message) */ + /* event.data is JSON-encoded Ably Message + (see https://www.ably.io/documentation/realtime/types#message) */ const message = JSON.parse(event.data); const { id, extras } = message; let { data } = message; From bfd02c2a639ed6ee434eccb98229ac4400e9c1b7 Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 11:29:43 +0100 Subject: [PATCH 14/47] Const/let to var in channel parameter code snippets Also adds [js] to end of some code snippets missing it --- .../channel-parameters/deltas.textile | 56 ++++++++++--------- .../channel-parameters/overview.textile | 10 ++-- .../channel-parameters/rewind.textile | 6 +- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index a9772741d7..9b4222fcf9 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -59,15 +59,15 @@ For many libraries this requires no change on the part of the caller except to s ```[js](code-editor:realtime/channel-deltas) /* Make sure to include in your head */ - const realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); + var realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { delta: 'vcdiff' }).subscribe(msg => console.log("Received message: ", msg)); ``` ```[nodejs] - const vcdiffPlugin = require('@ably/vcdiff-decoder'); - const realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); + var vcdiffPlugin = require('@ably/vcdiff-decoder'); + var realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { delta: 'vcdiff' }).subscribe(msg => console.log("Received message: ", msg)); @@ -117,20 +117,20 @@ h4(#delta-example-sse). Delta example with SSE You can subscribe to messages in delta mode, using the SSE transport, as follows. -``` +```[js] (() => { - const key = '{{API_KEY}}'; - const channel = 'sample-app-sse'; - const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; - const eventSource = new EventSource(url); - const channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); + var key = '{{API_KEY}}'; + var channel = 'sample-app-sse'; + var url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; + var eventSource = new EventSource(url); + var channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); eventSource.onmessage = (event) => { /* event.data is JSON-encoded Ably Message (see https://www.ably.io/documentation/realtime/types#message) */ - const message = JSON.parse(event.data); - const { id, extras } = message; - let { data } = message; + var message = JSON.parse(event.data); + var { id, extras } = message; + var { data } = message; try { if (extras && extras.delta) { @@ -153,15 +153,16 @@ h4(#delta-example-unenv-sse). Delta example with unenveloped SSE For more information on enveloped and uneveloped SSE, please see the "SSE API":/sse#sse -```(() => { - const key = '{{API_KEY}}'; - const channel = 'sample-app-sse'; - const url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; - const eventSource = new EventSource(url); - const channelDecoder = new DeltaCodec.VcdiffDecoder(); +```[js] +(() => { + var key = '{{API_KEY}}'; + var channel = 'sample-app-sse'; + var url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; + var eventSource = new EventSource(url); + var channelDecoder = new DeltaCodec.VcdiffDecoder(); eventSource.onmessage = (event) => { - let data = event.data; + var data = event.data; try { if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { @@ -182,22 +183,22 @@ For more information on enveloped and uneveloped SSE, please see the "SSE API":/ h4(#delta-example-mqtt). Delta example with MQTT -``` -const mqtt = require('mqtt'); -const { VcdiffDecoder } = require('./lib'); +```[js] +var mqtt = require('mqtt'); +var { VcdiffDecoder } = require('./lib'); -const options = { +var options = { keepalive: 30, username: 'FIRST_HALF_OF_API_KEY', password: 'SECOND_HALF_OF_API_KEY', port: 8883 }; -const client = mqtt.connect('mqtts:mqtt.ably.io', options); -const channelName = 'sample-app-mqtt'; -const channelDecoder = new VcdiffDecoder(); +var client = mqtt.connect('mqtts:mqtt.ably.io', options); +var channelName = 'sample-app-mqtt'; +var channelDecoder = new VcdiffDecoder(); client.on('message', (_, payload) => { - let data = payload; + var data = payload; try { if (VcdiffDecoder.isDelta(data)) { @@ -216,3 +217,4 @@ client.on('message', (_, payload) => { client.subscribe(`[?delta=vcdiff]${channelName}`); ``` + diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 234d2bc487..11e854ad66 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -31,16 +31,16 @@ h3. Example For example, to specify the @rewind@ channel param with the value @"1"@: ```[javascript] - const realtime = new Ably.Realtime('{{API_KEY}}'); - const channelOpts = {params: {rewind: '1'}} - const channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); + var realtime = new Ably.Realtime('{{API_KEY}}'); + var channelOpts = {params: {rewind: '1'}} + var channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); ``` To modify the @rewind@ channel param with the value @"15s"@: ```[javascript] - const realtime = new Ably.Realtime('{{API_KEY}}'); - const channelOpts = {params: {rewind: '15s'}} + var realtime = new Ably.Realtime('{{API_KEY}}'); + var channelOpts = {params: {rewind: '15s'}} channel.setOptions(channelOpts, (err) => { if(!err) { console.log('channel params updated') diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 6e3881b9b8..23015cf959 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -10,9 +10,9 @@ jump_to: h2(#overview). Overview -The @rewind@ parameter allows you to specify, at the time of attaching to a channel, where to start the attachment from. +The @rewind@ parameter allows you to specify, at the time of attaching to a channel, where to start the attachment from. -You can specify either: +You can specify either: * A given number of messages. * A point in time in the past, as a time interval. @@ -45,7 +45,7 @@ To subscribe to a channel, getting the most recent message if available: ```[jsall] // only with ably-js v1.2 or later - const realtime = new Ably.Realtime('{{API_KEY}}'); + var realtime = new Ably.Realtime('{{API_KEY}}'); realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { rewind: '1' }).subscribe(msg => console.log("Received message: ", msg)); From 4a4bbf6616b2bb2060f81c6ee5bfdf4ed7c48f9a Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 11:56:03 +0100 Subject: [PATCH 15/47] Various code fixes and additions for channel-parameters - Add missing code snippets throughout channel parameters sections - Added a few TBD code snippet locations, to be filled once we have them - Fixed a stray " in java snippets - Added language specification in pages --- .../channel-parameters/deltas.textile | 12 ++++- .../channel-parameters/overview.textile | 51 ++++++++++++++++++- .../channel-parameters/rewind.textile | 34 ++++++++++++- 3 files changed, 93 insertions(+), 4 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 9b4222fcf9..2cdbfc508e 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -2,6 +2,12 @@ title: Delta compression section: realtime index: 3 +languages: + - javascript + - nodejs + - java + - objc + - dotnet jump_to: Help with: - Overview#overview @@ -74,7 +80,7 @@ For many libraries this requires no change on the part of the caller except to s ``` ```[java] - AblyRealtime ably = new AblyRealtime("{{API_KEY}}"") + AblyRealtime ably = new AblyRealtime("{{API_KEY}}") Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", new ChannelOptions{{params = Map.of("delta", "vcdiff")}}); channel.subscribe(new MessageListener() { @Override @@ -88,6 +94,10 @@ For many libraries this requires no change on the part of the caller except to s TBD ``` +```[swift] +TBD +``` + ```[dotnet] TBD ``` diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 11e854ad66..fe069dec4a 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -2,6 +2,12 @@ title: Channel Parameters section: realtime index: 1 +languages: + - javascript + - nodejs + - java + - objc + - dotnet jump_to: Help with: - Overview#overview @@ -30,15 +36,36 @@ h3. Example For example, to specify the @rewind@ channel param with the value @"1"@: -```[javascript] +```[jsall] var realtime = new Ably.Realtime('{{API_KEY}}'); var channelOpts = {params: {rewind: '1'}} var channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); ``` +```[java] + final Map params = new HashMap<>(); + params.put("rewind", "1"); + final ChannelOptions options = new ChannelOptions(); + options.params = params; + final Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", options); +``` + +```[objc] +TBD +``` + +```[swift] +TBD +``` + +```[dotnet] +TBD +``` + + To modify the @rewind@ channel param with the value @"15s"@: -```[javascript] +```[jsall] var realtime = new Ably.Realtime('{{API_KEY}}'); var channelOpts = {params: {rewind: '15s'}} channel.setOptions(channelOpts, (err) => { @@ -48,6 +75,26 @@ To modify the @rewind@ channel param with the value @"15s"@: }); ``` +```[java] + final Map params = new HashMap<>(); + params.put("rewind", "15s"); + final ChannelOptions options = new ChannelOptions(); + options.params = params; + final Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", options); +``` + +```[objc] +TBD +``` + +```[swift] +TBD +``` + +```[dotnet] +TBD +``` + h2(#using-parameters-with-other-transports). Using parameters with non-Ably transports It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 23015cf959..df3cf4b67d 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -2,6 +2,12 @@ title: Rewind section: realtime index: 2 +languages: + - javascript + - nodejs + - java + - objc + - dotnet jump_to: Help with: - Overview#overview @@ -44,13 +50,39 @@ h3(#rewind-example-ably). Rewind example with an Ably client library To subscribe to a channel, getting the most recent message if available: ```[jsall] - // only with ably-js v1.2 or later var realtime = new Ably.Realtime('{{API_KEY}}'); realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { rewind: '1' }).subscribe(msg => console.log("Received message: ", msg)); ``` +```[java] + final Map params = new HashMap<>(); + params.put("rewind", "15s"); + final ChannelOptions options = new ChannelOptions(); + options.params = params; + final Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", options); + + channel.subscribe(new MessageListener() { + @Override + public void onMessage(Message message) { + System.out.println("Received `" + message.name + "` message with data: " + message.data); + } + }); +``` + +```[objc] +TBD +``` + +```[swift] +TBD +``` + +```[dotnet] +TBD +``` + h3(#rewind-example-sse). Rewind example with SSE To subscribe to a channel, getting the most recent message if available: From 45e4d356f24ca293b15cb50a0e0ca7a19e07f3ad Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 11:56:45 +0100 Subject: [PATCH 16/47] Removed triple spaces in channel-parameters docs --- content/realtime/channels/channel-parameters/deltas.textile | 1 - content/realtime/channels/channel-parameters/overview.textile | 1 - 2 files changed, 2 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 2cdbfc508e..2f1654d446 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -62,7 +62,6 @@ The most common way to subscribe to Ably channels is via a realtime connection, For many libraries this requires no change on the part of the caller except to specify the @delta@ "channel parameter":/realtime/channels/channel-parameters/overview when subscribing to the channel. In some libraries, the @vcdiff@ delta decoding library is excluded from the default library distribution in order to avoid bloating the library. In these cases, it is also necessary to supply the delta decoder plugin when instancing the Ably library. - ```[js](code-editor:realtime/channel-deltas) /* Make sure to include in your head */ var realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index fe069dec4a..ffb7a90073 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -62,7 +62,6 @@ TBD TBD ``` - To modify the @rewind@ channel param with the value @"15s"@: ```[jsall] From 17afcc28049a55c3a6f93c1d2cc8a4822a5a9496 Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 11:57:29 +0100 Subject: [PATCH 17/47] Corrected MQTT code example from JS to nodejs --- content/realtime/channels/channel-parameters/deltas.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 2f1654d446..a43055a6c5 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -192,7 +192,7 @@ For more information on enveloped and uneveloped SSE, please see the "SSE API":/ h4(#delta-example-mqtt). Delta example with MQTT -```[js] +```[nodejs] var mqtt = require('mqtt'); var { VcdiffDecoder } = require('./lib'); From 5c5f7d6c79c08c4d63914ddab7cdfeb58080b32f Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 12:01:37 +0100 Subject: [PATCH 18/47] Added swift code samples to channel parameter pages --- .../channels/channel-parameters/deltas.textile | 9 ++++++++- .../channel-parameters/overview.textile | 18 ++++++++++++++++-- .../channels/channel-parameters/rewind.textile | 11 +++++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index a43055a6c5..e966a1e520 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -94,7 +94,14 @@ TBD ``` ```[swift] -TBD + let options = ARTClientOptions(key: key) + let client = ARTRealtime(options: options) + let channelOptions = ARTRealtimeChannelOptions() + channelOptions.params = [ + "delta": "vcdiff" + ] + + let channel = client.channels.get(channelName, options: channelOptions) ``` ```[dotnet] diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index ffb7a90073..427912b96b 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -55,7 +55,14 @@ TBD ``` ```[swift] -TBD + let options = ARTClientOptions(key: key) + let client = ARTRealtime(options: options) + let channelOptions = ARTRealtimeChannelOptions() + channelOptions.params = [ + "rewind": "1" + ] + + let channel = client.channels.get(channelName, options: channelOptions) ``` ```[dotnet] @@ -87,7 +94,14 @@ TBD ``` ```[swift] -TBD + let options = ARTClientOptions(key: key) + let client = ARTRealtime(options: options) + let channelOptions = ARTRealtimeChannelOptions() + channelOptions.params = [ + "rewind": "15s" + ] + + let channel = client.channels.get(channelName, options: channelOptions) ``` ```[dotnet] diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index df3cf4b67d..4b41e437bd 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -58,7 +58,7 @@ To subscribe to a channel, getting the most recent message if available: ```[java] final Map params = new HashMap<>(); - params.put("rewind", "15s"); + params.put("rewind", "1"); final ChannelOptions options = new ChannelOptions(); options.params = params; final Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", options); @@ -76,7 +76,14 @@ TBD ``` ```[swift] -TBD + let options = ARTClientOptions(key: key) + let client = ARTRealtime(options: options) + let channelOptions = ARTRealtimeChannelOptions() + channelOptions.params = [ + "rewind": "1" + ] + + let channel = client.channels.get(channelName, options: channelOptions) ``` ```[dotnet] From bf1ce6f1e8000334a9cb1ceface7b3221eeec9df Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 12:05:15 +0100 Subject: [PATCH 19/47] Updated MQTT code samples to use generated API key name/secret --- content/mqtt/index.textile | 8 ++++---- .../realtime/channels/channel-parameters/deltas.textile | 4 ++-- .../realtime/channels/channel-parameters/rewind.textile | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/content/mqtt/index.textile b/content/mqtt/index.textile index 4ff76badc7..8775ad4404 100644 --- a/content/mqtt/index.textile +++ b/content/mqtt/index.textile @@ -35,8 +35,8 @@ For example, in the NodeJS "MQTT package":https://www.npmjs.com/package/mqtt, yo bc[nodejs]. { var options = { keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', + username: '{{API_KEY_NAME}}', /* API key's name */ + password: '{{API_KEY_SECRET}}', /* API key's secret */ port: 8883 }; var client = mqtt.connect('mqtts:mqtt.ably.io', options); @@ -54,8 +54,8 @@ bc[nodejs]. { var decoder = new encoding.TextDecoder(); var options = { keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', + username: '{{API_KEY_NAME}}', /* API key's name */ + password: '{{API_KEY_SECRET}}', /* API key's secret */ port: 8883 }; var client = mqtt.connect('mqtts:mqtt.ably.io', options); diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index e966a1e520..85ef1a088c 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -205,8 +205,8 @@ var { VcdiffDecoder } = require('./lib'); var options = { keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', + username: '{{API_KEY_NAME}}', /* API key's name */ + password: '{{API_KEY_SECRET}}', /* API key's secret */ port: 8883 }; var client = mqtt.connect('mqtts:mqtt.ably.io', options); diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 4b41e437bd..2742c4131b 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -105,8 +105,8 @@ h3(#rewind-examples-mqtt). Rewind example with MQTT var mqtt = require('mqtt'); var options = { keepalive: 30, - username: 'FIRST_HALF_OF_API_KEY', - password: 'SECOND_HALF_OF_API_KEY', + username: '{{API_KEY_NAME}}', /* API key's name */ + password: '{{API_KEY_SECRET}}', /* API key's secret */ port: 8883 }; var client = mqtt.connect('mqtts:mqtt.ably.io', options); From 0bd0992df64790f3cc5e37c2cebdc00496cc56f0 Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 12:11:42 +0100 Subject: [PATCH 20/47] Fixed various javascript code snippets --- content/concepts/long-polling.textile | 2 +- .../channel-parameters/deltas.textile | 6 ++--- content/tutorials/reactor-event-aws.textile | 22 ++++++++--------- content/tutorials/reactor-event-azure.textile | 24 +++++++++---------- .../tutorials/reactor-event-google.textile | 24 +++++++++---------- 5 files changed, 39 insertions(+), 39 deletions(-) diff --git a/content/concepts/long-polling.textile b/content/concepts/long-polling.textile index 07c125cf01..1b4765cb71 100644 --- a/content/concepts/long-polling.textile +++ b/content/concepts/long-polling.textile @@ -112,7 +112,7 @@ From the readme, "Pollymer is a general-purpose AJAX library that provides conve Optional extras include support for JSON-P and logging. -```[js] +```[javascript] var req = new Pollymer.Request(); req.on('finished', function(code, result, headers) { ... }); req.on('error', function(reason) { ... }); diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 85ef1a088c..e0aa44f365 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -62,7 +62,7 @@ The most common way to subscribe to Ably channels is via a realtime connection, For many libraries this requires no change on the part of the caller except to specify the @delta@ "channel parameter":/realtime/channels/channel-parameters/overview when subscribing to the channel. In some libraries, the @vcdiff@ delta decoding library is excluded from the default library distribution in order to avoid bloating the library. In these cases, it is also necessary to supply the delta decoder plugin when instancing the Ably library. -```[js](code-editor:realtime/channel-deltas) +```[javascript](code-editor:realtime/channel-deltas) /* Make sure to include in your head */ var realtime = new Ably.Realtime({key: '{{API_KEY}}', plugins: {vcdiffDecoder: vcdiffDecoder}}); realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', { @@ -133,7 +133,7 @@ h4(#delta-example-sse). Delta example with SSE You can subscribe to messages in delta mode, using the SSE transport, as follows. -```[js] +```[javascript] (() => { var key = '{{API_KEY}}'; var channel = 'sample-app-sse'; @@ -169,7 +169,7 @@ h4(#delta-example-unenv-sse). Delta example with unenveloped SSE For more information on enveloped and uneveloped SSE, please see the "SSE API":/sse#sse -```[js] +```[javascript] (() => { var key = '{{API_KEY}}'; var channel = 'sample-app-sse'; diff --git a/content/tutorials/reactor-event-aws.textile b/content/tutorials/reactor-event-aws.textile index 44dccade04..67e213fb6f 100644 --- a/content/tutorials/reactor-event-aws.textile +++ b/content/tutorials/reactor-event-aws.textile @@ -198,7 +198,7 @@ Here we're going to enter some preliminary code just to test that everything is # Scroll down and edit @index.js@ in the _Function Code_ section. Enter the following code into the editor: -```[js] +```[javascript] const AWS = require('aws-sdk'); exports.handler = (event, context, callback) => { @@ -383,7 +383,7 @@ The application script has a few parts to it, but isn't too complex. The script The first thing to do is to instantiate the "Ably client library":https://www.ably.io/download (already linked for you in the above HTML) and verify that we can send and receive messages successfully. The following code will define a channel, subscribe to it, and use it to publish customer messages. If everything is working, the fact that we're subscribed to the same channel that we're publishing to means that our messages will simply be echoed back to us via the @receiveMessage@ handler function, which will then append them to the chat log in the HTML. -```[js] +```[javascript] // This Ably client library is available due to the script in the HTML header: const ably = Ably.Realtime('YOUR_API_KEY_GOES_HERE'); @@ -456,7 +456,7 @@ If two different customers are trying to order a pizza at the same time, we don' Here's some code to generate a random customer ID. This will be run when the page first loads, and you'll be able to then use the customerID in your channel names: -```[js] +```[javascript] // Generate a customer id, being sure to sandbox the setup code inside a closure const customerId = (function () { @@ -484,7 +484,7 @@ const customerId = (function () { Split your channel initialization code to generate two channels instead of one: -```[js] +```[javascript] // The customer's messages will be posted here const outboundChannel = ably.channels.get('pizza:customer:' + customerId); @@ -497,7 +497,7 @@ inboundChannel.subscribe(receiveMessage); Let's refactor the message publishing code into its own function. We'll also modify what we're sending so that it includes the customer ID in the message data. This will make it easy for the Lambda function to reply on the correct channel without having to extract the customer ID from the name of the inbound channel: -```[js] +```[javascript] function postMessage(message) { // Note the additional call to appendMessageElement, which previously was only // being used by the receiveMessage handler. Because we want to visually @@ -516,7 +516,7 @@ function postMessage(message) { Don't forget to also update your @processInput@ function to use @postMessage@ rather than publishing directly: -```[js] +```[javascript] function processInput(e) { if (e.which !== 13) { // Character code 13 is the ENTER key return; @@ -535,7 +535,7 @@ We could test the above now, and you certainly can do so if you want to be sure Go back and edit your Lambda function with the following code ("which you can find in the tutorial repository":https://github.com/ably/tutorials/tree/reactor-event-aws-javascript/lambda-function.js): -```[js] +```[javascript] // We'll need the Node.js HTTPS module to post a response back to Ably const https = require("https") @@ -663,7 +663,7 @@ Also, the UI is not very useful unless the text input box is focused at all time Modify the @appendMessage@ function to return a reference to the HTML element it has just appended to the DOM: -```[js] +```[javascript] function appendMessageElement(type, message) { const div = document.createElement('div'); div.classList.add(type, 'message'); @@ -679,7 +679,7 @@ function appendMessageElement(type, message) { Next, we'll define a special "waiting" message that we add when the user types a message, and remove when a reply is received: -```[js] +```[javascript] let waitingElement; // persist a reference to the HTML element function setWaiting(isWaiting) { // isWaiting should be true or false @@ -707,7 +707,7 @@ function setWaiting(isWaiting) { // isWaiting should be true or false Update the code to call the above function when sending and receiving messages: -```[js] +```[javascript] function receiveMessage(message) { setWaiting(false); // The bot has replied, so remove the waiting message appendMessageElement('bot', message.data); @@ -722,7 +722,7 @@ function postMessage(message) { Finally, at the end of the script where your text box event listener is defined, hook up a couple of extra event listeners to keep the user focused on the input text box: -```[js] +```[javascript] function focusInputField() { inputField.focus(); } diff --git a/content/tutorials/reactor-event-azure.textile b/content/tutorials/reactor-event-azure.textile index 825fe62ae4..102102e00d 100644 --- a/content/tutorials/reactor-event-azure.textile +++ b/content/tutorials/reactor-event-azure.textile @@ -126,7 +126,7 @@ In the interface displayed, you'll see a space to edit your function, and a tab In the code editor, update the code editor with the following script, **making sure to update the line containing "YOUR_API_KEY_HERE" with your actual API key:** -```[js] +```[javascript] const Ably = require('ably'); const processMessage = require('./pizza'); @@ -195,7 +195,7 @@ Next, click the "View files" tab to the far right of the Azure function code edi When the script files are uploaded, click the "Test" option right above the file list. In the "Request body" editor, enter the following JSON code: -```[js] +```[javascript] { "customerId": "abc123", "message": "I'd like a pepperoni pizza, please" @@ -311,7 +311,7 @@ The first thing to do is to instantiate the "Ably client library":https://www.ab *Don't forget to replace @YOUR_API_KEY_GOES_HERE@ with your actual API key!* -```[js] +```[javascript] // This Ably client library is available due to the script in the HTML header: const ably = Ably.Realtime('YOUR_API_KEY_GOES_HERE'); @@ -384,7 +384,7 @@ If two different customers are trying to order a pizza at the same time, we don' Here's some code to generate a random customer ID. This will be run when the page first loads, and you'll be able to then use the customerID in your channel names: -```[js] +```[javascript] // Generate a customer id, being sure to sandbox the setup code inside a closure const customerId = (function () { @@ -412,7 +412,7 @@ const customerId = (function () { Split your channel initialization code to generate two channels instead of one: -```[js] +```[javascript] // The customer's messages will be posted here const outboundChannel = ably.channels.get('pizza:customer:' + customerId); @@ -425,7 +425,7 @@ inboundChannel.subscribe(receiveMessage); We're not using any special server-side persistence features, so we'll need to keep track of the conversation context and order details ourselves, and pass them to the chat bot as the conversation progresses. Only the bot will be updating the context; we'll just keep track of it on the bot's behalf, so that it isn't lost from one message to the next. -```[js] +```[javascript] let context = null; // We start with an uninitialized conversation context function receiveMessage(message) { @@ -436,7 +436,7 @@ function receiveMessage(message) { Let's refactor the message publishing code into its own function. We'll also modify what we're sending so that it includes the customer ID in the message data. This will make it easy for the Azure function to reply on the correct channel without having to extract the customer ID from the name of the inbound channel: -```[js] +```[javascript] function postMessage(message) { // Note the additional call to appendMessageElement, which previously was only // being used by the receiveMessage handler. Because we want to visually @@ -455,7 +455,7 @@ function postMessage(message) { Don't forget to also update your @processInput@ function to use @postMessage@ rather than publishing directly: -```[js] +```[javascript] function processInput(e) { if (e.which !== 13) { // Character code 13 is the ENTER key return; @@ -480,7 +480,7 @@ Also, the UI is not very useful unless the text input box is focused at all time Modify the @appendMessage@ function to return a reference to the HTML element it has just appended to the DOM: -```[js] +```[javascript] function appendMessageElement(type, message) { const div = document.createElement('div'); div.classList.add(type, 'message'); @@ -496,7 +496,7 @@ function appendMessageElement(type, message) { Next, we'll define a special "waiting" message that we add when the user types a message, and remove when a reply is received: -```[js] +```[javascript] let waitingElement; // persist a reference to the HTML element function setWaiting(isWaiting) { // isWaiting should be true or false @@ -524,7 +524,7 @@ function setWaiting(isWaiting) { // isWaiting should be true or false Update the code to call the above function when sending and receiving messages: -```[js] +```[javascript] function receiveMessage(message) { setWaiting(false); // The bot has replied, so remove the waiting message context = message.data.context; @@ -540,7 +540,7 @@ function postMessage(message) { Finally, at the end of the script where your text box event listener is defined, hook up a couple of extra event listeners to keep the user focused on the input text box: -```[js] +```[javascript] function focusInputField() { inputField.focus(); } diff --git a/content/tutorials/reactor-event-google.textile b/content/tutorials/reactor-event-google.textile index 09e1b8889a..71f8193707 100644 --- a/content/tutorials/reactor-event-google.textile +++ b/content/tutorials/reactor-event-google.textile @@ -99,7 +99,7 @@ From the "tutorial repository":https://github.com/ably/tutorials/tree/reactor-ev Create a new file in your project folder, and name it @index.js@. Copy the following script into the file, **making sure to update the line containing "YOUR_API_KEY_HERE" with your actual API key:** -```[js] +```[javascript] const Ably = require('ably'); const processMessage = require('./pizza'); @@ -184,7 +184,7 @@ When your function has been deployed successfully, it's time to test it and make Back in the Google Cloud interface for your deployed function, you'll see a set of tabs, one of which is labelled "Testing". Enter the following JSON code into the field labelled "Triggering event", then click the blue "Test the function" button: -```[js] +```[javascript] { "customerId": "test", "message": "I'd like a pepperoni pizza, please" @@ -304,7 +304,7 @@ The code below should go in your @app.js@ file. *Don't forget to replace @YOUR_API_KEY_GOES_HERE@ with your actual API key!* -```[js] +```[javascript] // This Ably client library is available due to the script in the HTML header: const ably = Ably.Realtime('YOUR_API_KEY_GOES_HERE'); @@ -377,7 +377,7 @@ If two different customers are trying to order a pizza at the same time, we don' Here's some code to generate a random customer ID. This will be run when the page first loads, and you'll be able to then use the customerID in your channel names: -```[js] +```[javascript] // Generate a customer id, being sure to sandbox the setup code inside a closure const customerId = (function () { @@ -405,7 +405,7 @@ const customerId = (function () { Split your channel initialization code to generate two channels instead of one: -```[js] +```[javascript] // The customer's messages will be posted here const outboundChannel = ably.channels.get('pizza:customer:' + customerId); @@ -418,7 +418,7 @@ inboundChannel.subscribe(receiveMessage); We're not using any special server-side persistence features, so we'll need to keep track of the conversation context and order details ourselves, and pass them to the chat bot as the conversation progresses. Only the bot will be updating the context; we'll just keep track of it on the bot's behalf, so that it isn't lost from one message to the next. -```[js] +```[javascript] let context = null; // We start with an uninitialized conversation context function receiveMessage(message) { @@ -429,7 +429,7 @@ function receiveMessage(message) { Let's refactor the message publishing code into its own function. We'll also modify what we're sending so that it includes the customer ID in the message data. This will make it easy for the Google function to reply on the correct channel without having to extract the customer ID from the name of the inbound channel: -```[js] +```[javascript] function postMessage(message) { // Note the additional call to appendMessageElement, which previously was only // being used by the receiveMessage handler. Because we want to visually @@ -448,7 +448,7 @@ function postMessage(message) { Don't forget to also update your @processInput@ function to use @postMessage@ rather than publishing directly: -```[js] +```[javascript] function processInput(e) { if (e.which !== 13) { // Character code 13 is the ENTER key return; @@ -473,7 +473,7 @@ Also, the UI is not very useful unless the text input box is focused at all time Modify the @appendMessage@ function to return a reference to the HTML element it has just appended to the DOM: -```[js] +```[javascript] function appendMessageElement(type, message) { const div = document.createElement('div'); div.classList.add(type, 'message'); @@ -489,7 +489,7 @@ function appendMessageElement(type, message) { Next, we'll define a special "waiting" message that we add when the user types a message, and remove when a reply is received: -```[js] +```[javascript] let waitingElement; // persist a reference to the HTML element function setWaiting(isWaiting) { // isWaiting should be true or false @@ -517,7 +517,7 @@ function setWaiting(isWaiting) { // isWaiting should be true or false Update the code to call the above function when sending and receiving messages: -```[js] +```[javascript] function receiveMessage(message) { setWaiting(false); // The bot has replied, so remove the waiting message context = message.data.context; @@ -533,7 +533,7 @@ function postMessage(message) { Finally, at the end of the script where your text box event listener is defined, hook up a couple of extra event listeners to keep the user focused on the input text box: -```[js] +```[javascript] function focusInputField() { inputField.focus(); } From 4c0ecd203ef46b5e9ae837229ad58e4efa353064 Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 12:17:28 +0100 Subject: [PATCH 21/47] Updated references to channel-params pages --- content/realtime/channels.textile | 8 ++++---- .../realtime/channels/channel-parameters/overview.textile | 4 +++- content/realtime/history.textile | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/content/realtime/channels.textile b/content/realtime/channels.textile index df546bb974..db8b962753 100644 --- a/content/realtime/channels.textile +++ b/content/realtime/channels.textile @@ -263,14 +263,14 @@ channel.subscribe { message in h4(#rewind). Subscribing to a channel with the rewind option enabled -It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-params#rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. +It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-parameters/rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. minimize. View details - "Rewind":/realtime/channel-params has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. + "Rewind":/realtime/channel-parameters has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. - In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-params with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-params documentation. + In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-parameters/rewind with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-parameters documentation. - *Note* that "rewind":/realtime/channel-params is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + *Note* that "rewind":/realtime/channel-parameters/rewind is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. In addition, rewind will only apply upon *attaching* to a channel, so any subsequent subscriptions post-attach will not fetch old messages. diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 427912b96b..be6801a10b 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -136,7 +136,9 @@ Or to specify the same parameter but only applying to one channel of two, using var querystring = 'v=1.2&key={{API_KEY}}&channels=' + channels'; var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); ``` + h2(#next-steps). Next steps * Request that an attachment start from a given number of messages or point in time in the past using "rewind":/realtime/channels/channel-parameters/rewind. -* Request that data payloads should be sent as deltas to the previous payload using "deltas":/realtime/channels/channel-parameters/deltas. \ No newline at end of file +* Request that data payloads should be sent as deltas to the previous payload using "deltas":/realtime/channels/channel-parameters/deltas. + diff --git a/content/realtime/history.textile b/content/realtime/history.textile index 64bea8d240..9ad306da40 100644 --- a/content/realtime/history.textile +++ b/content/realtime/history.textile @@ -142,11 +142,11 @@ To enable history on a channel, it is necessary to add a channel rule in the set h3(#continuous-history). Continuous history -By using "rewind":/realtime/channel-params#rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. +By using "rewind":/realtime/channel-parameters/rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. h4(#rewind). Rewind -If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-params#rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-params#rewind for further details. +If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-parameters/rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-parameters/rewind for further details. In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if the channel were @[some_metadata]my_channel@, you would specify the use of rewind via @[some_metadata?rewind=1]my_channel@. You can specify either a number of messages up to 100 to rewind to (for example @10@), or a time specifier of either seconds (@10s@), or minutes (@2m@) up to 2 minutes. From c7918f6af2ef3fcf7bc982d5c7e91d0be2f46d4a Mon Sep 17 00:00:00 2001 From: tomC Date: Wed, 3 Jun 2020 14:02:30 +0100 Subject: [PATCH 22/47] Corrected various broken code samples and links in channel parameter pages --- content/code/realtime/rewind.code | 2 +- .../partials/types/_channel_options.textile | 3 +++ content/realtime/channels.textile | 8 +++---- .../channel-parameters/deltas.textile | 18 ++++++++++++-- .../channel-parameters/overview.textile | 24 +++++++++++++++---- .../channel-parameters/rewind.textile | 19 +++++++++++++-- content/realtime/history.textile | 4 ++-- data/jsbins.yaml | 4 ++-- 8 files changed, 64 insertions(+), 18 deletions(-) diff --git a/content/code/realtime/rewind.code b/content/code/realtime/rewind.code index aa2deb94df..6665bb5f93 100644 --- a/content/code/realtime/rewind.code +++ b/content/code/realtime/rewind.code @@ -58,7 +58,7 @@ function show(status, color, box) {

          Ably Rewind demo

          -

          In this example, we demonstrate the simplest way to subscribe to a message using rewind in libraries older than v1.2. See our Rewind documentation for more details. +

          In this example, we demonstrate the simplest way to subscribe to a message using rewind in libraries older than v1.2. See our Rewind documentation for more details.

          diff --git a/content/partials/types/_channel_options.textile b/content/partials/types/_channel_options.textile index 6b54f8b6e3..0275861b4a 100644 --- a/content/partials/types/_channel_options.textile +++ b/content/partials/types/_channel_options.textile @@ -20,6 +20,9 @@ h4. java: Members ruby: Attributes +blang[jsall,java,swift,objc,dotnet]. + - paramsParams := Optional "parameters":/realtime/channels/channel-parameters/overview which specify behaviour of the channel.
          __Type: @Map@@JSON Object@__ + - cipher:cipherCipherParams := Requests encryption for this channel when not null, and specifies encryption-related parameters (such as algorithm, chaining mode, key length and key). See "an example":/realtime/encryption#getting-started
          __Type: "@CipherParams@":/realtime/encryption#cipher-params or an options objecta @Param[]@ listan options hashan Associative Array containing at a minimum a @key@__ blang[java]. diff --git a/content/realtime/channels.textile b/content/realtime/channels.textile index db8b962753..7671e86b94 100644 --- a/content/realtime/channels.textile +++ b/content/realtime/channels.textile @@ -263,14 +263,14 @@ channel.subscribe { message in h4(#rewind). Subscribing to a channel with the rewind option enabled -It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channel-parameters/rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. +It is possible to subscribe to a channel and obtain messages from that channel's "history":/realtime/history with a single API request. To do so you would use the "rewind":/realtime/channels/channel-parameters/rewind feature. This will result in the specified number of messages from "history":/realtime/history being returned as part of the subscription process. minimize. View details - "Rewind":/realtime/channel-parameters has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. + "Rewind":/realtime/channels/channel-parameters has two methods of obtaining messages from history. You can retrieve a specified number of messages from history or messages from a set period of time into the past. - In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channel-parameters/rewind with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channel-parameters documentation. + In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if you have no metadata and wish to subscribe to channel @my_channel@ and fetch the most recent message from "history":/realtime/history, you would specify the channel as @[?rewind=1]my_channel@. If the channel had some metadata, @[some_metadata]my_channel@, you would apply "rewind":/realtime/channels/channel-parameters/rewind with @[some_metadata?rewind=1]my_channel@. For more details, look at our "channel parameter":/realtime/channels/channel-parameters documentation. - *Note* that "rewind":/realtime/channel-parameters/rewind is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + *Note* that "rewind":/realtime/channels/channel-parameters/rewind is limited to a maximum of @100 messages@, and can only get messages no older than 2 minutes by default. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. In addition, rewind will only apply upon *attaching* to a channel, so any subsequent subscriptions post-attach will not fetch old messages. diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index e0aa44f365..ef4e1011d4 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -7,7 +7,8 @@ languages: - nodejs - java - objc - - dotnet + - swift + - csharp jump_to: Help with: - Overview#overview @@ -104,7 +105,7 @@ TBD let channel = client.channels.get(channelName, options: channelOptions) ``` -```[dotnet] +```[csharp] TBD ``` @@ -234,3 +235,16 @@ client.on('message', (_, payload) => { client.subscribe(`[?delta=vcdiff]${channelName}`); ``` +h1. API Reference + +inline-toc. + ChannelsOptions Details: + - ChannelOptions#channel-options + +h3(#channel-options). + default: ChannelOptions Object + objc,swift: ARTChannelOptions + java: io.ably.lib.types.ChannelOptions + csharp: IO.Ably.Rest.ChannelOptions + +<%= partial partial_version('types/_channel_options') %> diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index be6801a10b..374b36feb4 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -7,7 +7,8 @@ languages: - nodejs - java - objc - - dotnet + - swift + - csharp jump_to: Help with: - Overview#overview @@ -38,7 +39,7 @@ For example, to specify the @rewind@ channel param with the value @"1"@: ```[jsall] var realtime = new Ably.Realtime('{{API_KEY}}'); - var channelOpts = {params: {rewind: '1'}} + var channelOpts = {params: {rewind: '1'}}; var channel = realtime.channels.get('{{RANDOM_CHANNEL_NAME}}', channelOpts); ``` @@ -65,7 +66,7 @@ TBD let channel = client.channels.get(channelName, options: channelOptions) ``` -```[dotnet] +```[csharp] TBD ``` @@ -76,7 +77,7 @@ To modify the @rewind@ channel param with the value @"15s"@: var channelOpts = {params: {rewind: '15s'}} channel.setOptions(channelOpts, (err) => { if(!err) { - console.log('channel params updated') + console.log('channel params updated'); } }); ``` @@ -104,7 +105,7 @@ TBD let channel = client.channels.get(channelName, options: channelOptions) ``` -```[dotnet] +```[csharp] TBD ``` @@ -142,3 +143,16 @@ h2(#next-steps). Next steps * Request that an attachment start from a given number of messages or point in time in the past using "rewind":/realtime/channels/channel-parameters/rewind. * Request that data payloads should be sent as deltas to the previous payload using "deltas":/realtime/channels/channel-parameters/deltas. +h1. API Reference + +inline-toc. + ChannelsOptions Details: + - ChannelOptions#channel-options + +h3(#channel-options). + default: ChannelOptions Object + objc,swift: ARTChannelOptions + java: io.ably.lib.types.ChannelOptions + csharp: IO.Ably.Rest.ChannelOptions + +<%= partial partial_version('types/_channel_options') %> diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 2742c4131b..aec832c014 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -7,7 +7,8 @@ languages: - nodejs - java - objc - - dotnet + - csharp + - swift jump_to: Help with: - Overview#overview @@ -86,7 +87,7 @@ TBD let channel = client.channels.get(channelName, options: channelOptions) ``` -```[dotnet] +```[csharp] TBD ``` @@ -117,3 +118,17 @@ h3(#rewind-examples-mqtt). Rewind example with MQTT ... }); ``` + +h1. API Reference + +inline-toc. + ChannelsOptions Details: + - ChannelOptions#channel-options + +h3(#channel-options). + default: ChannelOptions Object + objc,swift: ARTChannelOptions + java: io.ably.lib.types.ChannelOptions + csharp: IO.Ably.Rest.ChannelOptions + +<%= partial partial_version('types/_channel_options') %> diff --git a/content/realtime/history.textile b/content/realtime/history.textile index 9ad306da40..343a8c8b7e 100644 --- a/content/realtime/history.textile +++ b/content/realtime/history.textile @@ -142,11 +142,11 @@ To enable history on a channel, it is necessary to add a channel rule in the set h3(#continuous-history). Continuous history -By using "rewind":/realtime/channel-parameters/rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. +By using "rewind":/realtime/channels/channel-parameters/rewind or History's @untilAttach@, it is possible to obtain message history that is continuous with the realtime messages received on an attached channel. h4(#rewind). Rewind -If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channel-parameters/rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channel-parameters/rewind for further details. +If you wish to obtain history as part of attaching to a channel, you can use the "rewind channel parameter":/realtime/channels/channel-parameters/rewind. This will act as though you had attached to a channel from a certain message or time in the past, and play through all messages since that point. Check out the main "rewind documentation":/realtime/channels/channel-parameters/rewind for further details. In current Ably libraries, or when using the "service without a library":https://www.ably.io/adapters, this is done by qualifying the channel name. There is a future library release planned in which it will be possible to specify channel params directly via the API. As an example, if the channel were @[some_metadata]my_channel@, you would specify the use of rewind via @[some_metadata?rewind=1]my_channel@. You can specify either a number of messages up to 100 to rewind to (for example @10@), or a time specifier of either seconds (@10s@), or minutes (@2m@) up to 2 minutes. diff --git a/data/jsbins.yaml b/data/jsbins.yaml index dba2cab51a..ea0b69fd4c 100644 --- a/data/jsbins.yaml +++ b/data/jsbins.yaml @@ -42,9 +42,9 @@ jsbin_hash: Sf9QPfpwxOvNcKy+KTQKXHq8dbc=: umikub 6voT8sjZ4GnNONoP3sW/Uaq2GkE=: aqalul 5SY9KnghzlKVnF/NlXih5jySnug=: utulow - heTWkNAvL1s99rFokByoTphFgV4=: itubin UjxZZTfXMcghYm5u6mmtFfDVdHc=: iyoqim JtTGXp3eHSfA3TMvP5uLAjBOEmA=: ufopek + Mxz+xzHdWwWQBNl+Nkhr/yalpmg=: ajosuv jsbin_id: adapters/pusher-pub-sub: eBxLJU1YqdX+JW9JQY70S4iQfmU= adapters/pubnub-pub-sub: pzHKfCW4/o2wDnCfbg1m0Pkl7v8= @@ -86,7 +86,7 @@ jsbin_id: sse/sse: 5SY9KnghzlKVnF/NlXih5jySnug= sse/eventstream: 6voT8sjZ4GnNONoP3sW/Uaq2GkE= rest/batch-presence: cHvxfaSCnHR6qzdutJZ/TZWK0FE= - realtime/rewind: heTWkNAvL1s99rFokByoTphFgV4= + realtime/rewind: Mxz+xzHdWwWQBNl+Nkhr/yalpmg= authentication/jwt-token: Q0XIw74KKfK3Zv34fqKSck4ip5U= realtime/connection-recover: Sf9QPfpwxOvNcKy+KTQKXHq8dbc= realtime/channel-deltas: UjxZZTfXMcghYm5u6mmtFfDVdHc= From 6a143c2aea1c4db41c3852d32d67dfd29d24cc00 Mon Sep 17 00:00:00 2001 From: MarkWoulfeAbly <63646324+MarkWoulfeAbly@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:26:55 +0100 Subject: [PATCH 23/47] Update content/realtime/channels/channel-parameters/deltas.textile shortened description. --- content/realtime/channels/channel-parameters/deltas.textile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index ef4e1011d4..673ce895bc 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -41,7 +41,9 @@ Delta compression is a subscriber-specified option only - the publisher has no c There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question, for the region in question. When there are multiple publishers in multiple regions, publishing messages nearly simultaneously, the ordering of messages delivered to subscribers can be different in different regions, depending on actual region-to-region transit latencies; in this case, deltas are generated based on the actual message order in each region, and subscribers are delivered a sequence of delta messages that reflects that regional order. -Delta mode, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. The effectiveness of delta mode - that is, whether or not there is a material saving in payload size - is dependent on the level of similarity between successive payloads. Therefore, if a channel carries messages from multiple sources or streams that are dissimilar, then delta processing might not result in a useful size reduction, even if the messages in each individual stream are similar; it depends on the specific sequence of messages that occurs in the channel, in the region in question. +There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question. + +Delta mode, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. The effectiveness of delta mode is dependent on the level of similarity between successive payloads. If a delta is generated and it results in a difference that is not appreciably smaller than the original message, or is even larger than the original message (which can happen if successive messages are completely different), then the delta will not be sent and clients will receive the original, unprocessed message. Therefore, the sequence of messages that will be delivered to a client for any given channel will be a combination of regular messages and delta-compressed messages. From 076a5f20e491967e2aa4ff08c0dfc190f64b9515 Mon Sep 17 00:00:00 2001 From: MarkWoulfeAbly <63646324+MarkWoulfeAbly@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:43:37 +0100 Subject: [PATCH 24/47] Update content/realtime/channels/channel-parameters/deltas.textile --- content/realtime/channels/channel-parameters/deltas.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 673ce895bc..c7db0ec08b 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -113,7 +113,7 @@ TBD h3(#using-deltas-non-ably). Via a subscription that does not use an Ably library -If subscribing to a channel in delta mode using "SSE":/sse or one of the protocol adaptors such as "MQTT":/mqtt, then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the "download":https://www.ably.io/download section for details. If you need to decode @vcdiff@-formatted delta messages in languages for which there is no decoder available from Ably, then any compliant open-source implementation of the standard will work. +If subscribing to a channel in delta mode using "SSE":/sse or one of the protocol adaptors such as "MQTT":/mqtt, then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the "download":https://www.ably.io/download section for details. Messages that contain a @vcdiff@ delta have that delta payload in their @data@ attribute; in the case of @vcdiff@ deltas this will be a binary value, even if the @data@ in the original meessage was text. in addition, there is metadata in the message @extras@ attribute that indicate that the payload is a delta, and which message the delta is relative to. The format of the `extras` attribute is as follows: From 0b45978a89f8276d399c22758ed50aebeafae02e Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Fri, 5 Jun 2020 13:33:18 +0100 Subject: [PATCH 25/47] Improved channel parameter overview --- content/realtime/channels/channel-parameters/overview.textile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 374b36feb4..f30908d46e 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -20,12 +20,14 @@ jump_to: h2(#overview). Overview -Channel parameters allow a client to set the properties of a channel. A set of channel parameters is a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines. +Ably provides channel paramaters as a means of customizing channel functionality. For example, you can request that a channel attachment start from some time in the past by using the "rewind parameter":#supported-parameters. The methods provided for specifying channel parameters are outlined below. h2(#supported-parameters). Supported channel parameters +A set of channel parameters is a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines: + - rewind := Used to request that an attachment start from a given number of messages or point in time in the past. See "rewind":/realtime/channels/channel-parameters/rewind for more information. - delta := Used to request that data payloads should be sent as deltas to the previous payload. See "deltas":/realtime/channels/channel-parameters/deltas for more information. From e4d8e742cb59a25bf051aa188f85ceecf5267289 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Fri, 5 Jun 2020 13:49:00 +0100 Subject: [PATCH 26/47] Reformatted content in the rewind page --- .../channel-parameters/rewind.textile | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index aec832c014..3fae68c259 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -24,30 +24,18 @@ You can specify either: * A given number of messages. * A point in time in the past, as a time interval. -The @rewind@ parameter is specified using "channel parameters":/realtime/channels/channel-parameters/overview. - The parameter relates to the initial attachment of a connection to a channel, and expresses the intent to attach to the channel at a position, or a point in time, in the past (that is, effectively "rewinding" the channel for the purposes of the present attachment). -A @rewind@ value that is a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If the attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. - -If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. - -A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. - -If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel parameter. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. - -At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. - -By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. - -The channel position expressed by a @rewind@ parameter only has an effect on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). - -Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier will cause the attachment request to fail and return an error. +The @rewind@ parameter is specified using "channel parameters":/realtime/channels/channel-parameters/overview. h2(#examples). Examples h3(#rewind-example-ably). Rewind example with an Ably client library +A @rewind@ value that is a number @n@ (eg @rewind=1@) is a request to attach to the channel at a position @n@ messages before the present position. If the attachment is successful, and one or more messages exist on the channel prior to the present position, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. + +If fewer than the requested number of messages exists on the channel (including the case that there are no prior messages), then the available messages are sent; this does not constitute an error. + To subscribe to a channel, getting the most recent message if available: ```[jsall] @@ -91,6 +79,10 @@ TBD TBD ``` +A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. + +If you wish to use a time interval rewind but additionally specify a limit on the number of messages to be returned, you can use the @rewindLimit@ channel parameter. For example, to request up to 10 messages in a window 5m before the present time, specify a channel parameter string of @rewind=5m&rewindLimit=10@. If fewer than the requested number of messages exists on the channel in that interval (including the case that there are no messages), then the available messages are sent; this does not constitute an error. + h3(#rewind-example-sse). Rewind example with SSE To subscribe to a channel, getting the most recent message if available: @@ -119,6 +111,16 @@ h3(#rewind-examples-mqtt). Rewind example with MQTT }); ``` +h2(#additional-info). Additional information + +At most 100 messages will be sent in a rewind request. If the number of messages within the specified interval is greater than that limit, then only the most recent messages up to that limit are sent. The attachment succeeds, but truncation of the message backlog is indicated as a non-fatal error in the attachment response. + +By default, a maximum of two minutes of channel history is available when attaching. This means that a rewind time specifier of greater than two minutes will only be able to rewind by two minutes. If a channel has persistence enabled, then it is possible to rewind back in time by up to the persistence TTL on the channel. + +The channel position expressed by a @rewind@ parameter only has an effect on an initial channel attachment. Any subsequent reattachment of the same channel on the same connection, in order to resume the connection, will attempt to resume with continuity from the point at which the connection dropped. (There are a few exceptions to this: in particular, client libraries earlier than v1.2 that have been disconnected for over two minutes, and all clients when using "@recover@ mode":/realtime/connection#connection-state-recovery ; in both cases the previous attachment state is not preserved). + +Any @rewind@ parameter value that cannot be parsed either as a number or a time specifier will cause the attachment request to fail and return an error. + h1. API Reference inline-toc. From ca482258a999261fd758aa9a570db83dbafb4960 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Fri, 5 Jun 2020 16:50:11 +0100 Subject: [PATCH 27/47] Added delta image --- app/assets/images/realtime/delta-messages.png | Bin 0 -> 38214 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/assets/images/realtime/delta-messages.png diff --git a/app/assets/images/realtime/delta-messages.png b/app/assets/images/realtime/delta-messages.png new file mode 100644 index 0000000000000000000000000000000000000000..3069f3f53ec915829b467388cc938e5822620570 GIT binary patch literal 38214 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

          c*D2@`)BJGyc%fx`LA%bmj#m*EvuQn% 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 literal 0 HcmV?d00001 From c36345bcddf659b521ea9e87ef787790d68c3455 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Fri, 5 Jun 2020 16:52:06 +0100 Subject: [PATCH 28/47] fixed duplication issue --- content/realtime/channels/channel-parameters/deltas.textile | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index c7db0ec08b..b8237e4ce0 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -39,8 +39,6 @@ Delta compression via @vcdiff@ is supported for all payloads, whether string, bi Delta compression is a subscriber-specified option only - the publisher has no control over whether or not deltas are generated for any given message; the processing is performed if there is at least one subscriber on a channel that has requested a delta-mode subscription. -There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question, for the region in question. When there are multiple publishers in multiple regions, publishing messages nearly simultaneously, the ordering of messages delivered to subscribers can be different in different regions, depending on actual region-to-region transit latencies; in this case, deltas are generated based on the actual message order in each region, and subscribers are delivered a sequence of delta messages that reflects that regional order. - There is no constraint on how many publishers or subscribers there are. If there are multiple publishers, then deltas can still be generated, and they will be determined based on the order of messages in the channel in question. Delta mode, when activated on a channel, is performed for all messages on a channel, and deltas are calculated strictly based on the message ordering in that channel. The effectiveness of delta mode is dependent on the level of similarity between successive payloads. From 150d0115df73eedef83910b7fb99b57530d00d26 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Fri, 5 Jun 2020 17:05:14 +0100 Subject: [PATCH 29/47] updated channel param titles --- .../realtime/channels/channel-parameters/overview.textile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index f30908d46e..3073c8c3af 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -13,8 +13,8 @@ jump_to: Help with: - Overview#overview - Supported channel parameters#supported-parameters - - Using channel parameters#using-parameters - - Using channel parameters with non-Ably transports#using-parameters-with-other-transports + - Using channel parameters with Ably libraries#using-parameters-ably + - Using channel parameters without Ably libraries#using-parameters-non-ably - Next steps#next-steps --- @@ -31,7 +31,7 @@ A set of channel parameters is a set of key/value pairs, where both keys and val - rewind := Used to request that an attachment start from a given number of messages or point in time in the past. See "rewind":/realtime/channels/channel-parameters/rewind for more information. - delta := Used to request that data payloads should be sent as deltas to the previous payload. See "deltas":/realtime/channels/channel-parameters/deltas for more information. -h2(#using-parameters). Using channel parameters +h2(#using-parameters-ably). Using channel parameters with Ably libraries You can specify channel parameters in the @ChannelOptions@ when obtaining a @Channel@. A collection of channel parameters is expressed as a map of string key/value pairs. The @ChannelOptions@ associated with a channel may also be updated by calling "setOptions":/realtime/channels/overview#modifying-options. The parameters associated with a channel take effect when the channel is first attached; if the parameters are subsequently modified via a call to @setOptions@, then that call triggers an attach operation that applies the updated parameters, if successful. @@ -111,7 +111,7 @@ TBD TBD ``` -h2(#using-parameters-with-other-transports). Using parameters with non-Ably transports +h2(#using-parameters-non-ably). Using channel parameters without Ably libraries It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. From cafbff82efc1a46418c415deb5285ac8e5ba335b Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Fri, 5 Jun 2020 17:10:18 +0100 Subject: [PATCH 30/47] Linked to channel options --- content/realtime/channels/channel-parameters/overview.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 3073c8c3af..d0cfe0e22c 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -33,7 +33,7 @@ A set of channel parameters is a set of key/value pairs, where both keys and val h2(#using-parameters-ably). Using channel parameters with Ably libraries -You can specify channel parameters in the @ChannelOptions@ when obtaining a @Channel@. A collection of channel parameters is expressed as a map of string key/value pairs. The @ChannelOptions@ associated with a channel may also be updated by calling "setOptions":/realtime/channels/overview#modifying-options. The parameters associated with a channel take effect when the channel is first attached; if the parameters are subsequently modified via a call to @setOptions@, then that call triggers an attach operation that applies the updated parameters, if successful. +You can specify channel parameters in the "@ChannelOptions@":#channel-options when obtaining a @Channel@. A collection of channel parameters is expressed as a map of string key/value pairs. The @ChannelOptions@ associated with a channel may also be updated by calling "setOptions":/realtime/channels/overview#modifying-options. The parameters associated with a channel take effect when the channel is first attached; if the parameters are subsequently modified via a call to @setOptions@, then that call triggers an attach operation that applies the updated parameters, if successful. h3. Example From f1a507550aefec3eff1fce9c09f5689a32156bf9 Mon Sep 17 00:00:00 2001 From: tomC Date: Fri, 5 Jun 2020 17:22:27 +0100 Subject: [PATCH 31/47] Added deltas image to deltas documentation --- content/realtime/channels/channel-parameters/deltas.textile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index b8237e4ce0..b2dfa9f7e2 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -27,6 +27,10 @@ This is useful for channels that carry messages representing a series of updates The delta mode implementation supports a single representation of a delta, "VCDIFF":https://tools.ietf.org/html/rfc3284. + + Deltas explanation + + Subscribing in delta mode is enabled for a given channel by specifying a @delta@ "channel parameter":/realtime/channels/channel-parameters/overview with the value @vcdiff@. This will cause delta messages to be generated by the server and sent to the client, and the library reconstitutes the original message payload. Messages on the channel are delivered to the subscriber's listener in the same way as with a normal subscription. h2(#delta-processing). Delta processing From e82a6804ec69b6f985ca69d98d8a4979645392fa Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Mon, 8 Jun 2020 14:14:58 +0100 Subject: [PATCH 32/47] calrified non-supported libraries --- .../channel-parameters/overview.textile | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index d0cfe0e22c..c482141f6d 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -14,7 +14,7 @@ jump_to: - Overview#overview - Supported channel parameters#supported-parameters - Using channel parameters with Ably libraries#using-parameters-ably - - Using channel parameters without Ably libraries#using-parameters-non-ably + - Using channel parameters outside of supported Ably libraries#using-parameters-non-ably - Next steps#next-steps --- @@ -111,18 +111,29 @@ TBD TBD ``` -h2(#using-parameters-non-ably). Using channel parameters without Ably libraries +h2(#using-parameters-non-ably). Using channel parameters outside of supported Ably libraries -It is possible to interact with Ably channels using transports that do not involve using an Ably library; for example using SSE without any library, or using a supported non-Ably protocol such as MQTT. In these cases, it is also necessary to use a qualified channel name. +For the client libraries that do not currently expose the API, or transports that do not involve using an Ably library, a set of channel paramaters can be expressed by including a query string with standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. -A set of parameters is expressed by including a query string, using standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. +Examples of transports that do not use Ably libraries include using SSE without any library, or using a supported non-Ably protocol such as MQTT -For example, to specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. +To specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. -In an SSE connection, it is also possible to specify channel parameters as a query string in the connection URL, instead of as a qualifier on an individual channel name. In this case, the given channel parameters apply to all channel attachments associated with that connection. +h3. Non-supported Ably library example + +Using this syntax with a non-supported Ably library means that channel parameters are specified for the lifetime of the @Channel@ instance; in order to reference the same channel, but with different channel parameters, it is necessary to get a new @Channel@ instance, using a qualified name that includes the new channel parameters. + +For example, to specify the @rewind@ channel param with the value @"1"@: + +```[javascript] + const realtime = new Ably.Realtime('{{API_KEY}}'); + const channel = realtime.channels.get('[?rewind=1]{{RANDOM_CHANNEL_NAME}}'); +``` h3. SSE example +In an SSE connection, it is also possible to specify channel parameters as a query string in the connection URL, instead of as a qualifier on an individual channel name. In this case, the given channel parameters apply to all channel attachments associated with that connection. + For example, to specify the @rewind@ channel param with the value @"1"@ using a querystring parameter, where it will apply to all channels: ```[javascript] From b72bf94a8751325053e68f1bd6ee633a851f7e6b Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Mon, 8 Jun 2020 14:50:34 +0100 Subject: [PATCH 33/47] minor formatting changes --- content/realtime/channels/channel-parameters/deltas.textile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index b2dfa9f7e2..36a2a2a7e1 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -35,7 +35,7 @@ Subscribing in delta mode is enabled for a given channel by specifying a @delta@ h2(#delta-processing). Delta processing -Deltas apply to the principal payload of a @Message@ published via Ably, which is the @data@ member. Other elements of a message, such as @clientId@, @name@, or @extras@ are unchanged by use of deltas and are not compressed. +Deltas apply to the principal payload of a "@Message@":/realtime/messages#properties published via Ably, which is the @data@ member. Other elements of a message, such as @clientId@, @name@, or @extras@ are unchanged by use of deltas and are not compressed. Deltas are supported for realtime subscriptions only. Messages retrieved via "history":/realtime/history, and messages delivered to "Reactor integrations":https://www.ably.io/reactor, are not compressed. @@ -117,9 +117,9 @@ h3(#using-deltas-non-ably). Via a subscription that does not use an Ably library If subscribing to a channel in delta mode using "SSE":/sse or one of the protocol adaptors such as "MQTT":/mqtt, then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the "download":https://www.ably.io/download section for details. -Messages that contain a @vcdiff@ delta have that delta payload in their @data@ attribute; in the case of @vcdiff@ deltas this will be a binary value, even if the @data@ in the original meessage was text. in addition, there is metadata in the message @extras@ attribute that indicate that the payload is a delta, and which message the delta is relative to. The format of the `extras` attribute is as follows: +Messages that contain a @vcdiff@ delta have that delta payload in their @data@ attribute; in the case of @vcdiff@ deltas this will be a binary value, even if the @data@ in the original meessage was text. in addition, there is metadata in the message @extras@ attribute that indicate that the payload is a delta, and which message the delta is relative to. The format of the @extras@ attribute is as follows: -```[jsall] +```[javascript] extras: { format: 'vcdiff', from: '{{previous message id}}' From d5af127d947fabab7c429887f7ef2dd6417d47f4 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Mon, 8 Jun 2020 15:09:21 +0100 Subject: [PATCH 34/47] Updated rewind and delta descriptions --- content/realtime/channels/channel-parameters/overview.textile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index c482141f6d..144f3a774a 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -28,8 +28,8 @@ h2(#supported-parameters). Supported channel parameters A set of channel parameters is a set of key/value pairs, where both keys and values are strings; the keys correspond to specific features that Ably defines: -- rewind := Used to request that an attachment start from a given number of messages or point in time in the past. See "rewind":/realtime/channels/channel-parameters/rewind for more information. -- delta := Used to request that data payloads should be sent as deltas to the previous payload. See "deltas":/realtime/channels/channel-parameters/deltas for more information. +- rewind := Allows an attachment to a channel to start from a given number of messages or point in time in the past. See "rewind":/realtime/channels/channel-parameters/rewind for more information. +- delta := Enables delta compression, a way for a client to subscribe to a channel so that message payloads sent contain only the difference (ie the delta) between the present message and the previous message on the channel. See "deltas":/realtime/channels/channel-parameters/deltas for more information. h2(#using-parameters-ably). Using channel parameters with Ably libraries From 93a9b004ed80c95cc38718086a8bc5f869504133 Mon Sep 17 00:00:00 2001 From: tomC Date: Mon, 8 Jun 2020 15:09:24 +0100 Subject: [PATCH 35/47] Updated delta size demo to new js version - Also includes numbers as part of size calc for non-delta size - Rewind only used in params, no channel metadata --- .../code/realtime/channel-deltas-size.code | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/content/code/realtime/channel-deltas-size.code b/content/code/realtime/channel-deltas-size.code index 63e6c9782a..ec18328b5f 100644 --- a/content/code/realtime/channel-deltas-size.code +++ b/content/code/realtime/channel-deltas-size.code @@ -1,4 +1,9 @@ [--- Javascript ---] +var receivedLogNotDeltas = document.getElementById('received-not-deltas'); +var receivedLogDeltas = document.getElementById('received-deltas'); +var totalWithoutDeltas = document.getElementById('no-delta'); +var totalWithDeltas = document.getElementById('delta'); + var clientOptions = { key: '{{API_KEY}}', plugins: { @@ -17,19 +22,14 @@ var deltaChannelOptions = { var ably = new Ably.Realtime(clientOptions); -var deltaChannel = ably.channels.get('[product:cttransit/gtfsr?rewind=10]vehicle:all', deltaChannelOptions); +var deltaChannel = ably.channels.get('[product:cttransit/gtfsr]vehicle:all', deltaChannelOptions); -var channel = ably.channels.get('[product:cttransit/gtfsr?rewind=10]vehicle:all'); +var channel = ably.channels.get('[product:cttransit/gtfsr]vehicle:all'); -var receivedLogNotDeltas = document.getElementById('received-not-deltas'); -var receivedLogDeltas = document.getElementById('received-deltas'); -var totalWithoutDeltas = document.getElementById('no-delta'); -var totalWithDeltas = document.getElementById('delta'); /* Subscribe to a channel normally */ channel.subscribe(function(message, err) { var size = getMessageSize(message); - console.log(size); totalWithoutDeltas.innerHTML = parseInt(totalWithoutDeltas.innerHTML, 10) + size; receivedLogNotDeltas.insertAdjacentHTML('afterbegin', '

        • ' + JSON.stringify(message.data) + '
        • '); }); @@ -49,16 +49,21 @@ function getMessageSize(message) { } else if(typeof message === 'object') { for (var i in message) { /* Calculate the size of components of the object */ + bytes += i.length * 2; bytes += getMessageSize(message[i]); } + } else if (typeof message == 'number') { + bytes += 8; + } else if (message === undefined) { + bytes += 1; } return bytes; } -/* Wrapper for the vcdiff decoder, allowing us to check the size of the original diff*/ +/* Wrapper for the vcdiff decoder, allowing us to check the size of the original diff */ function decodeAndCountSize(delta, source) { + totalWithDeltas.innerHTML = parseInt(totalWithDeltas.innerHTML, 10) + delta.byteLength; var result = decoder.decode(delta, source); - totalWithDeltas.innerHtml = parseInt(totalWithDeltas.innerHTML, 10) + message.getMessageSize(); return result; } [--- /Javascript ---] @@ -66,7 +71,7 @@ function decodeAndCountSize(delta, source) { [--- HTML ---] - + From 55f23be67ebba5f35c7026c3432f5da1e30a8a2b Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Mon, 8 Jun 2020 16:17:57 +0100 Subject: [PATCH 36/47] updated overview based on feedback --- .../realtime/channels/channel-parameters/overview.textile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 144f3a774a..ab98a29ab5 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -111,15 +111,15 @@ TBD TBD ``` -h2(#using-parameters-non-ably). Using channel parameters outside of supported Ably libraries +h2(#using-parameters-non-ably). Using channel parameters without Ably library support -For the client libraries that do not currently expose the API, or transports that do not involve using an Ably library, a set of channel paramaters can be expressed by including a query string with standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. +For the client libraries that do not currently expose the API, or transports that do not involve using an Ably library, a set of channel parameters can be expressed by including a query string with standard URL query syntax and encoding, within the qualifier part of a channel name. The qualifier part is in square brackets at the start of the channel name. Examples of transports that do not use Ably libraries include using SSE without any library, or using a supported non-Ably protocol such as MQTT To specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. -h3. Non-supported Ably library example +h3. Example of Ably library without channel paramaters support Using this syntax with a non-supported Ably library means that channel parameters are specified for the lifetime of the @Channel@ instance; in order to reference the same channel, but with different channel parameters, it is necessary to get a new @Channel@ instance, using a qualified name that includes the new channel parameters. From 4df4584fe6bdf3b3de34ff40810321a2ae6153e1 Mon Sep 17 00:00:00 2001 From: tomC Date: Mon, 8 Jun 2020 17:03:10 +0100 Subject: [PATCH 37/47] Reduce length of delta examples --- .../realtime/channels/channel-parameters/deltas.textile | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 36a2a2a7e1..54fb3016df 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -142,7 +142,9 @@ You can subscribe to messages in delta mode, using the SSE transport, as follows (() => { var key = '{{API_KEY}}'; var channel = 'sample-app-sse'; - var url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; + var baseUrl = 'https://realtime.ably.io/event-stream'; + var urlParams = `?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; + var url = baseUrl + urlParams; var eventSource = new EventSource(url); var channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); @@ -178,7 +180,9 @@ For more information on enveloped and uneveloped SSE, please see the "SSE API":/ (() => { var key = '{{API_KEY}}'; var channel = 'sample-app-sse'; - var url = `https://realtime.ably.io/event-stream?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; + var baseUrl = 'https://realtime.ably.io/event-stream'; + var urlParams = `?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; + var url = baseUrl + urlParams; var eventSource = new EventSource(url); var channelDecoder = new DeltaCodec.VcdiffDecoder(); From 8aba69bf52f30de60c52ce70d1ac97870361b470 Mon Sep 17 00:00:00 2001 From: tomC Date: Mon, 8 Jun 2020 17:04:32 +0100 Subject: [PATCH 38/47] Fix sidebar ordering for realtime --- content/realtime/channel-metadata.textile | 2 +- content/realtime/channels.textile | 2 +- content/realtime/channels/channel-parameters/deltas.textile | 2 +- content/realtime/channels/channel-parameters/overview.textile | 2 +- content/realtime/channels/channel-parameters/rewind.textile | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/content/realtime/channel-metadata.textile b/content/realtime/channel-metadata.textile index 8af2ac9b14..724532d489 100644 --- a/content/realtime/channel-metadata.textile +++ b/content/realtime/channel-metadata.textile @@ -1,7 +1,7 @@ --- title: Channel Metadata API section: realtime -index: 31 +index: 3 jump_to: Help with: - Overview#overview diff --git a/content/realtime/channels.textile b/content/realtime/channels.textile index 7671e86b94..ceb83bb5d6 100644 --- a/content/realtime/channels.textile +++ b/content/realtime/channels.textile @@ -1,7 +1,7 @@ --- title: Channels section: realtime -index: 30 +index: 2 languages: - javascript - nodejs diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 54fb3016df..59eb36e25a 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -1,7 +1,7 @@ --- title: Delta compression section: realtime -index: 3 +index: 6 languages: - javascript - nodejs diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index ab98a29ab5..f8dbad212b 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -1,7 +1,7 @@ --- title: Channel Parameters section: realtime -index: 1 +index: 4 languages: - javascript - nodejs diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 3fae68c259..ceb859a4ff 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -1,7 +1,7 @@ --- title: Rewind section: realtime -index: 2 +index: 5 languages: - javascript - nodejs From 58a22639176f3b2a09206731bd70398cddc6c222 Mon Sep 17 00:00:00 2001 From: tomC Date: Mon, 8 Jun 2020 17:06:41 +0100 Subject: [PATCH 39/47] Correct api ref in channel parameters for csharp Incorrectly said REST rather than realtime --- content/realtime/channels/channel-parameters/deltas.textile | 2 +- content/realtime/channels/channel-parameters/overview.textile | 2 +- content/realtime/channels/channel-parameters/rewind.textile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 59eb36e25a..b22b4daf10 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -253,6 +253,6 @@ h3(#channel-options). default: ChannelOptions Object objc,swift: ARTChannelOptions java: io.ably.lib.types.ChannelOptions - csharp: IO.Ably.Rest.ChannelOptions + csharp: IO.Ably.Realtime.ChannelOptions <%= partial partial_version('types/_channel_options') %> diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index f8dbad212b..231820b9c3 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -166,6 +166,6 @@ h3(#channel-options). default: ChannelOptions Object objc,swift: ARTChannelOptions java: io.ably.lib.types.ChannelOptions - csharp: IO.Ably.Rest.ChannelOptions + csharp: IO.Ably.Realtime.ChannelOptions <%= partial partial_version('types/_channel_options') %> diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index ceb859a4ff..12355c01fc 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -131,6 +131,6 @@ h3(#channel-options). default: ChannelOptions Object objc,swift: ARTChannelOptions java: io.ably.lib.types.ChannelOptions - csharp: IO.Ably.Rest.ChannelOptions + csharp: IO.Ably.Realtime.ChannelOptions <%= partial partial_version('types/_channel_options') %> From ff006d444e8ac1bce463b5ac706a342e1d9febcc Mon Sep 17 00:00:00 2001 From: Kenneth Kalmer Date: Mon, 8 Jun 2020 17:55:38 +0100 Subject: [PATCH 40/47] fix: update jsbin pointers for realtime/channel-deltas-size --- data/jsbins.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/jsbins.yaml b/data/jsbins.yaml index ea0b69fd4c..0fd3784b7e 100644 --- a/data/jsbins.yaml +++ b/data/jsbins.yaml @@ -43,8 +43,8 @@ jsbin_hash: 6voT8sjZ4GnNONoP3sW/Uaq2GkE=: aqalul 5SY9KnghzlKVnF/NlXih5jySnug=: utulow UjxZZTfXMcghYm5u6mmtFfDVdHc=: iyoqim - JtTGXp3eHSfA3TMvP5uLAjBOEmA=: ufopek Mxz+xzHdWwWQBNl+Nkhr/yalpmg=: ajosuv + mZcTN8McM4HXm+nDeiZqLj9gq8w=: izopuj jsbin_id: adapters/pusher-pub-sub: eBxLJU1YqdX+JW9JQY70S4iQfmU= adapters/pubnub-pub-sub: pzHKfCW4/o2wDnCfbg1m0Pkl7v8= @@ -90,4 +90,4 @@ jsbin_id: authentication/jwt-token: Q0XIw74KKfK3Zv34fqKSck4ip5U= realtime/connection-recover: Sf9QPfpwxOvNcKy+KTQKXHq8dbc= realtime/channel-deltas: UjxZZTfXMcghYm5u6mmtFfDVdHc= - realtime/channel-deltas-size: JtTGXp3eHSfA3TMvP5uLAjBOEmA= + realtime/channel-deltas-size: mZcTN8McM4HXm+nDeiZqLj9gq8w= From b3d2a6611af47f5f04df12cdc905545768764226 Mon Sep 17 00:00:00 2001 From: tomC Date: Tue, 9 Jun 2020 09:44:50 +0100 Subject: [PATCH 41/47] Add new code samples for channel params --- .../channel-parameters/deltas.textile | 20 ++++++--- .../channel-parameters/overview.textile | 43 +++++++++++++------ .../channel-parameters/rewind.textile | 22 +++++++--- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index b22b4daf10..70191b1fef 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -6,7 +6,6 @@ languages: - javascript - nodejs - java - - objc - swift - csharp jump_to: @@ -94,10 +93,6 @@ For many libraries this requires no change on the part of the caller except to s }); ``` -```[obj-c] -TBD -``` - ```[swift] let options = ARTClientOptions(key: key) let client = ARTRealtime(options: options) @@ -110,7 +105,20 @@ TBD ``` ```[csharp] -TBD + var clientOptions = new ClientOptions(); + clientOptions.Key = "{{API_KEY}}"; + clientOptions.Environment = AblyEnvironment; + var ably = new AblyRealtime(clientOptions); + + var channelParams = new ChannelParams(); + channelParams.Add("delta", "vcdiff"); + var channelOptions = new ChannelOptions(); + channelOptions.Params = channelParams; + var channel = ably.Channels.Get("{{RANDOM_CHANNEL_NAME}}", channelOptions); + + channel.Subscribe(message => { + Console.WriteLine(message.Data.ToString()); + }); ``` h3(#using-deltas-non-ably). Via a subscription that does not use an Ably library diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index 231820b9c3..fd71b565a4 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -6,7 +6,6 @@ languages: - javascript - nodejs - java - - objc - swift - csharp jump_to: @@ -53,10 +52,6 @@ For example, to specify the @rewind@ channel param with the value @"1"@: final Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", options); ``` -```[objc] -TBD -``` - ```[swift] let options = ARTClientOptions(key: key) let client = ARTRealtime(options: options) @@ -69,7 +64,20 @@ TBD ``` ```[csharp] -TBD + var clientOptions = new ClientOptions(); + clientOptions.Key = "{{API_KEY}}"; + clientOptions.Environment = AblyEnvironment; + var ably = new AblyRealtime(clientOptions); + + var channelParams = new ChannelParams(); + channelParams.Add("rewind", "1"); + var channelOptions = new ChannelOptions(); + channelOptions.Params = channelParams; + var channel = ably.Channels.Get("{{RANDOM_CHANNEL_NAME}}", channelOptions); + + channel.Subscribe(message => { + Console.WriteLine(message.Data.ToString()); + }); ``` To modify the @rewind@ channel param with the value @"15s"@: @@ -92,10 +100,6 @@ To modify the @rewind@ channel param with the value @"15s"@: final Channel channel = ably.channels.get("{{RANDOM_CHANNEL_NAME}}", options); ``` -```[objc] -TBD -``` - ```[swift] let options = ARTClientOptions(key: key) let client = ARTRealtime(options: options) @@ -108,7 +112,20 @@ TBD ``` ```[csharp] -TBD + var clientOptions = new ClientOptions(); + clientOptions.Key = "{{API_KEY}}"; + clientOptions.Environment = AblyEnvironment; + var ably = new AblyRealtime(clientOptions); + + var channelParams = new ChannelParams(); + channelParams.Add("rewind", "15s"); + var channelOptions = new ChannelOptions(); + channelOptions.Params = channelParams; + var channel = ably.Channels.Get("{{RANDOM_CHANNEL_NAME}}", channelOptions); + + channel.Subscribe(message => { + Console.WriteLine(message.Data.ToString()); + }); ``` h2(#using-parameters-non-ably). Using channel parameters without Ably library support @@ -137,8 +154,8 @@ In an SSE connection, it is also possible to specify channel parameters as a que For example, to specify the @rewind@ channel param with the value @"1"@ using a querystring parameter, where it will apply to all channels: ```[javascript] -var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; -var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); + var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}'; + var eventSource = new EventSource('https://realtime.ably.io/event-stream?' + querystring); ``` Or to specify the same parameter but only applying to one channel of two, using a qualified channel name: diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index 12355c01fc..a7864f1f5a 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -6,7 +6,6 @@ languages: - javascript - nodejs - java - - objc - csharp - swift jump_to: @@ -60,12 +59,8 @@ To subscribe to a channel, getting the most recent message if available: }); ``` -```[objc] -TBD -``` - ```[swift] - let options = ARTClientOptions(key: key) + let options = ARTClientOptions(key: "{{API_KEY}}") let client = ARTRealtime(options: options) let channelOptions = ARTRealtimeChannelOptions() channelOptions.params = [ @@ -76,7 +71,20 @@ TBD ``` ```[csharp] -TBD + var clientOptions = new ClientOptions(); + clientOptions.Key = "{{API_KEY}}"; + clientOptions.Environment = AblyEnvironment; + var ably = new AblyRealtime(clientOptions); + + var channelParams = new ChannelParams(); + channelParams.Add("rewind", "1"); + var channelOptions = new ChannelOptions(); + channelOptions.Params = channelParams; + var channel = ably.Channels.Get("{{RANDOM_CHANNEL_NAME}}", channelOptions); + + channel.Subscribe(message => { + Console.WriteLine(message.Data.ToString()); + }); ``` A @rewind@ value can also be a string that is a time interval specifier. Supported specifier values express an integral number of seconds (eg @15s@) or minutes (eg @2m@). If that attachment is successful, and one or more messages exist on the channel in the given time interval prior to the present time, then those messages will be delivered to the subscriber immediately after the attachment has completed, and before any subsequent messages that arise in real time. From 0ecaa0046a68b7fb44eb317c6d1e0f64326d8e93 Mon Sep 17 00:00:00 2001 From: tomC Date: Tue, 9 Jun 2020 10:02:30 +0100 Subject: [PATCH 42/47] Remove ./lib from code example on deltas --- content/realtime/channels/channel-parameters/deltas.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 70191b1fef..17843353a5 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -218,7 +218,7 @@ h4(#delta-example-mqtt). Delta example with MQTT ```[nodejs] var mqtt = require('mqtt'); -var { VcdiffDecoder } = require('./lib'); +var { VcdiffDecoder } = require('@ably/vcdiff-decoder'); var options = { keepalive: 30, From 6c80cd5d3b6f20baae7c652597c53d2b7ea0db0d Mon Sep 17 00:00:00 2001 From: tomC Date: Tue, 9 Jun 2020 10:06:01 +0100 Subject: [PATCH 43/47] Fixed broken hrefs in channel parameter docs --- content/realtime/channels/channel-parameters/deltas.textile | 1 - content/realtime/channels/channel-parameters/rewind.textile | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 17843353a5..36bd414d3f 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -13,7 +13,6 @@ jump_to: - Overview#overview - Delta processing#delta-processing - Using deltas#using-deltas - - Examples#examples --- h2(#overview). Overview diff --git a/content/realtime/channels/channel-parameters/rewind.textile b/content/realtime/channels/channel-parameters/rewind.textile index a7864f1f5a..06aed44910 100644 --- a/content/realtime/channels/channel-parameters/rewind.textile +++ b/content/realtime/channels/channel-parameters/rewind.textile @@ -12,6 +12,7 @@ jump_to: Help with: - Overview#overview - Examples#examples + - Additional information#additional-info --- h2(#overview). Overview From 73a14122d04a3e395737806c282eea5abd9fa8a5 Mon Sep 17 00:00:00 2001 From: tomC Date: Tue, 9 Jun 2020 10:27:33 +0100 Subject: [PATCH 44/47] Updated delta see/mqtt code examples --- .../channel-parameters/deltas.textile | 169 +++++++++--------- 1 file changed, 84 insertions(+), 85 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index 36bd414d3f..c4c83bd080 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -146,37 +146,35 @@ h4(#delta-example-sse). Delta example with SSE You can subscribe to messages in delta mode, using the SSE transport, as follows. ```[javascript] -(() => { - var key = '{{API_KEY}}'; - var channel = 'sample-app-sse'; - var baseUrl = 'https://realtime.ably.io/event-stream'; - var urlParams = `?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; - var url = baseUrl + urlParams; - var eventSource = new EventSource(url); - var channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); - - eventSource.onmessage = (event) => { - /* event.data is JSON-encoded Ably Message - (see https://www.ably.io/documentation/realtime/types#message) */ - var message = JSON.parse(event.data); - var { id, extras } = message; - var { data } = message; - - try { - if (extras && extras.delta) { - data = channelDecoder.applyBase64Delta(data, id, extras.delta.from).asUtf8String(); - } else { - channelDecoder.setBase(data, id); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); +var key = '{{API_KEY}}'; +var channel = 'sample-app-sse'; +var baseUrl = 'https://realtime.ably.io/event-stream'; +var urlParams = `?channels=${channel}&v=1.1&key=${key}&delta=vcdiff`; +var url = baseUrl + urlParams; +var eventSource = new EventSource(url); +var channelDecoder = new DeltaCodec.CheckedVcdiffDecoder(); + +eventSource.onmessage = function(event) { + /* event.data is JSON-encoded Ably Message + (see https://www.ably.io/documentation/realtime/types#message) */ + var message = JSON.parse(event.data); + var { id, extras } = message; + var { data } = message; + + try { + if (extras && extras.delta) { + data = channelDecoder.applyBase64Delta(data, id, extras.delta.from).asUtf8String(); + } else { + channelDecoder.setBase(data, id); } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } - /* Process decoded data */ - console.log(data); - }; -})(); + /* Process decoded data */ + console.log(data); +}; ``` h4(#delta-example-unenv-sse). Delta example with unenveloped SSE @@ -184,70 +182,71 @@ h4(#delta-example-unenv-sse). Delta example with unenveloped SSE For more information on enveloped and uneveloped SSE, please see the "SSE API":/sse#sse ```[javascript] -(() => { - var key = '{{API_KEY}}'; - var channel = 'sample-app-sse'; - var baseUrl = 'https://realtime.ably.io/event-stream'; - var urlParams = `?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; - var url = baseUrl + urlParams; - var eventSource = new EventSource(url); - var channelDecoder = new DeltaCodec.VcdiffDecoder(); - - eventSource.onmessage = (event) => { - var data = event.data; - - try { - if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { - data = channelDecoder.applyBase64Delta(data).asUtf8String(); - } else { - channelDecoder.setBase(data); - } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - - /* Process decoded data */ - console.log(data); - }; -})(); + /* Make sure to include in your head */ + var DeltaCodec = require('@ably/delta-codec'); + + var key = '{{API_KEY}}'; + var channel = 'sample-app-sse'; + var baseUrl = 'https://realtime.ably.io/event-stream'; + var urlParams = `?channels=${channel}&v=1.1&key=${key}&delta=vcdiff&enveloped=false`; + var url = baseUrl + urlParams; + var eventSource = new EventSource(url); + var channelDecoder = new DeltaCodec.VcdiffDecoder(); + + eventSource.onmessage = function(event) { + var data = event.data; + + try { + if (DeltaCodec.VcdiffDecoder.isBase64Delta(data)) { + data = channelDecoder.applyBase64Delta(data).asUtf8String(); + } else { + channelDecoder.setBase(data); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); + } + + /* Process decoded data */ + console.log(data); + }; ``` h4(#delta-example-mqtt). Delta example with MQTT ```[nodejs] -var mqtt = require('mqtt'); -var { VcdiffDecoder } = require('@ably/vcdiff-decoder'); - -var options = { - keepalive: 30, - username: '{{API_KEY_NAME}}', /* API key's name */ - password: '{{API_KEY_SECRET}}', /* API key's secret */ - port: 8883 -}; -var client = mqtt.connect('mqtts:mqtt.ably.io', options); -var channelName = 'sample-app-mqtt'; -var channelDecoder = new VcdiffDecoder(); - -client.on('message', (_, payload) => { - var data = payload; - - try { - if (VcdiffDecoder.isDelta(data)) { - data = channelDecoder.applyDelta(data).asUint8Array(); - } else { - channelDecoder.setBase(data); + var mqtt = require('mqtt'); + var { VcdiffDecoder } = require('@ably/vcdiff-decoder'); + + var options = { + keepalive: 30, + username: '{{API_KEY_NAME}}', /* API key's name */ + password: '{{API_KEY_SECRET}}', /* API key's secret */ + port: 8883 + }; + var client = mqtt.connect('mqtts:mqtt.ably.io', options); + var channelName = 'sample-app-mqtt'; + var channelDecoder = new VcdiffDecoder(); + + client.on('message', (_, payload) => { + var data = payload; + + try { + if (VcdiffDecoder.isDelta(data)) { + data = channelDecoder.applyDelta(data).asUint8Array(); + } else { + channelDecoder.setBase(data); + } + } catch(e) { + /* Delta decoder error */ + console.log(e); } - } catch(e) { - /* Delta decoder error */ - console.log(e); - } - /* Process decoded data */ - console.log(data); -}); + /* Process decoded data */ + console.log(data); + }); -client.subscribe(`[?delta=vcdiff]${channelName}`); + client.subscribe(`[?delta=vcdiff]${channelName}`); ``` h1. API Reference From 8e6ead3d5f5ecdcfd3ad5112c4538ac21a2d4115 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Tue, 9 Jun 2020 11:34:35 +0100 Subject: [PATCH 45/47] shortened some information --- .../channels/channel-parameters/deltas.textile | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index c4c83bd080..d69e881933 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -124,18 +124,7 @@ h3(#using-deltas-non-ably). Via a subscription that does not use an Ably library If subscribing to a channel in delta mode using "SSE":/sse or one of the protocol adaptors such as "MQTT":/mqtt, then you will need to decode any received delta messages yourself. There are decoder libraries available to do this for several platforms; see the "download":https://www.ably.io/download section for details. -Messages that contain a @vcdiff@ delta have that delta payload in their @data@ attribute; in the case of @vcdiff@ deltas this will be a binary value, even if the @data@ in the original meessage was text. in addition, there is metadata in the message @extras@ attribute that indicate that the payload is a delta, and which message the delta is relative to. The format of the @extras@ attribute is as follows: - -```[javascript] -extras: { - format: 'vcdiff', - from: '{{previous message id}}' -} -``` - -In order to reconstruct the original message, the @vcdiff@ decoder algorithm needs to be applied to the given @data@ @vcdiff@ value, together with the @data@ for the previous message (on the assumption that that message had already been decoded if it itself was also a delta). If the original form of the present message was text, then this is indicated in the `encoding` attribute of the message, so the original text can be reconstructed by @utf-8@ decoding, once the @vcdiff@ decoding is complete. The decoder libraries that are available to download simplify this process, and more detailed information can be found in the @README@ of each of those libraries. - -When subscribing without an Ably library, then the channel @delta@ parameter must be specified using a "qualified channel name":/realtime/channels/channel-parameters/overview. In the case of SSE, it is also possible to specify channel parameters as regular query parameters on the connection URL. +When subscribing without an Ably library, the channel @delta@ parameter must be specified using a "qualified channel name":/realtime/channels/channel-parameters/overview. In the case of SSE, it is also possible to specify channel parameters as regular query parameters on the connection URL. Some transports provide raw message payloads - that is, the content of the @data@ attribute of a @Message@ - without the accompanying metadata. That means that the recipient of the message does not have access to the @extras@ or @encoding@ attributes of the message that would ordinarily be used to decode delta message payloads. From 7fd3e82f803a18b339570d7d1379e8f3f83019f2 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Tue, 9 Jun 2020 12:03:52 +0100 Subject: [PATCH 46/47] fixed broken url --- content/realtime/channels/channel-parameters/overview.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index fd71b565a4..be1148ceae 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -32,7 +32,7 @@ A set of channel parameters is a set of key/value pairs, where both keys and val h2(#using-parameters-ably). Using channel parameters with Ably libraries -You can specify channel parameters in the "@ChannelOptions@":#channel-options when obtaining a @Channel@. A collection of channel parameters is expressed as a map of string key/value pairs. The @ChannelOptions@ associated with a channel may also be updated by calling "setOptions":/realtime/channels/overview#modifying-options. The parameters associated with a channel take effect when the channel is first attached; if the parameters are subsequently modified via a call to @setOptions@, then that call triggers an attach operation that applies the updated parameters, if successful. +You can specify channel parameters in the "@ChannelOptions@":#channel-options when obtaining a @Channel@. A collection of channel parameters is expressed as a map of string key/value pairs. The @ChannelOptions@ associated with a channel may also be updated by calling "setOptions":/realtime/channels#modifying-options. The parameters associated with a channel take effect when the channel is first attached; if the parameters are subsequently modified via a call to @setOptions@, then that call triggers an attach operation that applies the updated parameters, if successful. h3. Example From 830ce567d0b56edd0a97ef00f0003cf501990763 Mon Sep 17 00:00:00 2001 From: Mark Woulfe Date: Tue, 9 Jun 2020 12:16:00 +0100 Subject: [PATCH 47/47] typos fixed --- .../channels/channel-parameters/deltas.textile | 6 +++--- .../channels/channel-parameters/overview.textile | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/content/realtime/channels/channel-parameters/deltas.textile b/content/realtime/channels/channel-parameters/deltas.textile index d69e881933..cbeaaabcae 100644 --- a/content/realtime/channels/channel-parameters/deltas.textile +++ b/content/realtime/channels/channel-parameters/deltas.textile @@ -21,7 +21,7 @@ The @delta@ parameter enables delta compression. It is applied on the channel yo Delta mode is a way for a client to subscribe to a channel so that message payloads sent contain only the difference (ie the delta) between the present message and the previous message on the channel. -This is useful for channels that carry messages representing a series of updates to a particular object or document with a significant degree of similarily between successive messages. The client can apply the delta to the previous message to obtain the full payload. Using delta mode can signficantly reduce the encoded size of each message in the case that message payloads change by differences that are small relative to the size of the value. This reduction in size can reduce bandwidth costs, reduce transit latencies, and enable greater message throughput on a connection. +This is useful for channels that carry messages representing a series of updates to a particular object or document with a significant degree of similarly between successive messages. The client can apply the delta to the previous message to obtain the full payload. Using delta mode can significantly reduce the encoded size of each message in the case that message payloads change by differences that are small relative to the size of the value. This reduction in size can reduce bandwidth costs, reduce transit latencies, and enable greater message throughput on a connection. The delta mode implementation supports a single representation of a delta, "VCDIFF":https://tools.ietf.org/html/rfc3284. @@ -37,7 +37,7 @@ Deltas apply to the principal payload of a "@Message@":/realtime/messages#proper Deltas are supported for realtime subscriptions only. Messages retrieved via "history":/realtime/history, and messages delivered to "Reactor integrations":https://www.ably.io/reactor, are not compressed. -Delta compression via @vcdiff@ is supported for all payloads, whether string, binary, or JSON-encoded. The delta algorithm processes message payloads as opaque binaries and has no dependency on the stucture of the payload - it does not process line-oriented diffs, for example. In principle, @vcdiff@ deltas can be applied to encrypted message payloads, but in practice this provides no benefit because there is no similarity between successive encrypted payloads even on identical or near-identical plaintext message payloads. +Delta compression via @vcdiff@ is supported for all payloads, whether string, binary, or JSON-encoded. The delta algorithm processes message payloads as opaque binaries and has no dependency on the structure of the payload - it does not process line-oriented diffs, for example. In principle, @vcdiff@ deltas can be applied to encrypted message payloads, but in practice this provides no benefit because there is no similarity between successive encrypted payloads even on identical or near-identical plaintext message payloads. Delta compression is a subscriber-specified option only - the publisher has no control over whether or not deltas are generated for any given message; the processing is performed if there is at least one subscriber on a channel that has requested a delta-mode subscription. @@ -55,7 +55,7 @@ A channel subscriber can experience a discontinuity in the sequence of messages In these cases, the service indicates the discontinuity to the client, together with the reason, and this is usually visible to the subscriber in a channel @UPDATE@ event. -If a subscriber has a delta-mode subscription and the channel in question experiences a discontunity, then a non-delta message will be delivered to the client as the first message after the discontinuity. This ensures that lost messages do not prevent the client from reconstituting messages from deltas. +If a subscriber has a delta-mode subscription and the channel in question experiences a discontinuity, then a non-delta message will be delivered to the client as the first message after the discontinuity. This ensures that lost messages do not prevent the client from reconstituting messages from deltas. h2(#using-deltas). Using deltas diff --git a/content/realtime/channels/channel-parameters/overview.textile b/content/realtime/channels/channel-parameters/overview.textile index be1148ceae..992afc076b 100644 --- a/content/realtime/channels/channel-parameters/overview.textile +++ b/content/realtime/channels/channel-parameters/overview.textile @@ -19,7 +19,7 @@ jump_to: h2(#overview). Overview -Ably provides channel paramaters as a means of customizing channel functionality. For example, you can request that a channel attachment start from some time in the past by using the "rewind parameter":#supported-parameters. +Ably provides channel parameters as a means of customizing channel functionality. For example, you can request that a channel attachment start from some time in the past by using the "rewind parameter":#supported-parameters. The methods provided for specifying channel parameters are outlined below. @@ -36,7 +36,7 @@ You can specify channel parameters in the "@ChannelOptions@":#channel-options wh h3. Example -For example, to specify the @rewind@ channel param with the value @"1"@: +For example, to specify the @rewind@ channel parameter with the value @"1"@: ```[jsall] var realtime = new Ably.Realtime('{{API_KEY}}'); @@ -80,7 +80,7 @@ For example, to specify the @rewind@ channel param with the value @"1"@: }); ``` -To modify the @rewind@ channel param with the value @"15s"@: +To modify the @rewind@ channel parameters with the value @"15s"@: ```[jsall] var realtime = new Ably.Realtime('{{API_KEY}}'); @@ -136,11 +136,11 @@ Examples of transports that do not use Ably libraries include using SSE without To specify the parameter @foo@ with value @bar@ on channel @baz@, the qualified channel name would be @[?foo=bar]baz@. If the channel name already has a qualifier, such as @[meta]log@, then the query string follows the existing qualifier, as in @[meta?foo=bar]log@. -h3. Example of Ably library without channel paramaters support +h3. Example of Ably library without channel parameters support Using this syntax with a non-supported Ably library means that channel parameters are specified for the lifetime of the @Channel@ instance; in order to reference the same channel, but with different channel parameters, it is necessary to get a new @Channel@ instance, using a qualified name that includes the new channel parameters. -For example, to specify the @rewind@ channel param with the value @"1"@: +For example, to specify the @rewind@ channel parameter with the value @"1"@: ```[javascript] const realtime = new Ably.Realtime('{{API_KEY}}'); @@ -151,7 +151,7 @@ h3. SSE example In an SSE connection, it is also possible to specify channel parameters as a query string in the connection URL, instead of as a qualifier on an individual channel name. In this case, the given channel parameters apply to all channel attachments associated with that connection. -For example, to specify the @rewind@ channel param with the value @"1"@ using a querystring parameter, where it will apply to all channels: +For example, to specify the @rewind@ channel parameter with the value @"1"@ using a querystring parameter, where it will apply to all channels: ```[javascript] var querystring = 'v=1.2&channels={{RANDOM_CHANNEL_NAME}}&rewind=1&key={{API_KEY}}';