From 7bf76a7704132c4fe34527d91211d9e66f4ab59d Mon Sep 17 00:00:00 2001 From: Tsviatko Yovtchev Date: Mon, 9 Mar 2020 18:44:05 +0200 Subject: [PATCH 1/4] Documenting the delta channel param --- content/realtime/channel-params.textile | 108 ++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/content/realtime/channel-params.textile b/content/realtime/channel-params.textile index 75cf596cc1..c44b4c3aba 100644 --- a/content/realtime/channel-params.textile +++ b/content/realtime/channel-params.textile @@ -139,3 +139,111 @@ h3(#rewind-examples-mqtt). Rewind example with MQTT ... }); ``` +h2(#delta). Delta parameter + +The @delta@ channel parameter expresses the intent to receive the delta (diff) between the previous and current message instead of the current message in full on a given channel. This parameter is oblivious to the sender and only affects the subscriber using it. I.e. the sender sends messages in full and Ably Realtime would compute and send the message deltas to any subscriber using this parameter. + +It should also be noted that Ably Realtime does not guarantee every message to be a delta once the @delta@ parameter is specified. Ably Realtime might chose to send some messages in full depending on system load, etc. So 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@. VCFIFF is the format of the delta itself (VCFIFF is an open format specified "here":https://tools.ietf.org/html/rfc3284) + +One could use the "delta codec library":https://github.com/ably/delta-codec-js provided by Ably to avoid writing boilerplate VCDIFF handling code. Some examples follow. + +h3(#delta-example-sse). Delta example with enveloped 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`; + 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 + +```(() => { + 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); + }; +})(); +``` + +h3(#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}`); +``` \ No newline at end of file From 22e911f64c3c12166671527456a50dd26d35b5d4 Mon Sep 17 00:00:00 2001 From: Quintin Willison Date: Mon, 23 Mar 2020 10:38:57 +0000 Subject: [PATCH 2/4] Fix markup. --- content/realtime/channel-params.textile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/content/realtime/channel-params.textile b/content/realtime/channel-params.textile index c44b4c3aba..3095e2b5e4 100644 --- a/content/realtime/channel-params.textile +++ b/content/realtime/channel-params.textile @@ -139,6 +139,7 @@ h3(#rewind-examples-mqtt). Rewind example with MQTT ... }); ``` + h2(#delta). Delta parameter The @delta@ channel parameter expresses the intent to receive the delta (diff) between the previous and current message instead of the current message in full on a given channel. This parameter is oblivious to the sender and only affects the subscriber using it. I.e. the sender sends messages in full and Ably Realtime would compute and send the message deltas to any subscriber using this parameter. @@ -151,7 +152,7 @@ One could use the "delta codec library":https://github.com/ably/delta-codec-js p h3(#delta-example-sse). Delta example with enveloped SSE -``` +```[jsall] (() => { const key = '{{API_KEY}}'; const channel = 'sample-app-sse'; @@ -184,7 +185,8 @@ h3(#delta-example-sse). Delta example with enveloped SSE 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.1&key=${key}&delta=vcdiff&enveloped=false`; @@ -213,7 +215,7 @@ h3(#delta-example-unenv-sse). Delta example with unenveloped SSE h3(#delta-example-mqtt). Delta example with MQTT -``` +```[jsall] const mqtt = require('mqtt'); const { VcdiffDecoder } = require('./lib'); @@ -246,4 +248,4 @@ client.on('message', (_, payload) => { }); client.subscribe(`[?delta=vcdiff]${channelName}`); -``` \ No newline at end of file +``` From fbf72fad00d4566f60fe7fa495c886a7bf296123 Mon Sep 17 00:00:00 2001 From: Quintin Willison Date: Mon, 23 Mar 2020 10:58:06 +0000 Subject: [PATCH 3/4] Make changes suggested by Simon in PR #835, plus some other language/tone tweaks. --- content/realtime/channel-params.textile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/realtime/channel-params.textile b/content/realtime/channel-params.textile index 3095e2b5e4..097f7ceeeb 100644 --- a/content/realtime/channel-params.textile +++ b/content/realtime/channel-params.textile @@ -142,13 +142,13 @@ h3(#rewind-examples-mqtt). Rewind example with MQTT h2(#delta). Delta parameter -The @delta@ channel parameter expresses the intent to receive the delta (diff) between the previous and current message instead of the current message in full on a given channel. This parameter is oblivious to the sender and only affects the subscriber using it. I.e. the sender sends messages in full and Ably Realtime would compute and send the message deltas to any subscriber using this 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. -It should also be noted that Ably Realtime does not guarantee every message to be a delta once the @delta@ parameter is specified. Ably Realtime might chose to send some messages in full depending on system load, etc. So a subscriber using the @delta@ parameter should be prepared to handle a random mix of delta and full messages. +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@. VCFIFF is the format of the delta itself (VCFIFF is an open format specified "here":https://tools.ietf.org/html/rfc3284) +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. -One could use the "delta codec library":https://github.com/ably/delta-codec-js provided by Ably to avoid writing boilerplate VCDIFF handling code. Some examples follow. +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 From b4b8b045d92c16ba1e219bd44f2901d98e7ea8f2 Mon Sep 17 00:00:00 2001 From: Quintin Willison Date: Mon, 23 Mar 2020 11:01:33 +0000 Subject: [PATCH 4/4] Fix code indentation, including converting tabs to spaces, plus removal of unnecessary wrapper. --- content/realtime/channel-params.textile | 140 ++++++++++++------------ 1 file changed, 68 insertions(+), 72 deletions(-) diff --git a/content/realtime/channel-params.textile b/content/realtime/channel-params.textile index 097f7ceeeb..2105699fba 100644 --- a/content/realtime/channel-params.textile +++ b/content/realtime/channel-params.textile @@ -153,64 +153,60 @@ Ably provides a JavaScript "delta codec library":https://github.com/ably/delta-c 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.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); - }; -})(); +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); +}; ``` 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.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); - }; -})(); +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); +}; ``` h3(#delta-example-mqtt). Delta example with MQTT @@ -220,31 +216,31 @@ 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 + 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); + 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}`);