Skip to content

Commit

Permalink
Merge pull request #1512 from ably/1492-remove-plugins-mechanism
Browse files Browse the repository at this point in the history
[SDK-3938] Remove the existing plugins mechanism
  • Loading branch information
lawrence-forooghian authored Nov 29, 2023
2 parents 6f9d7f7 + c1f70b0 commit 0d1f6cb
Show file tree
Hide file tree
Showing 25 changed files with 1,000 additions and 866 deletions.
41 changes: 33 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,39 @@ channel.subscribe('myEvent', function (message) {

Subscribing to a channel in delta mode enables [delta compression](https://www.ably.com/docs/realtime/channels/channel-parameters/deltas). This 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.

Configuring a channel for deltas is detailed in the [@ably-forks/vcdiff-decoder documentation](https://github.com/ably-forks/vcdiff-decoder#usage).
To subscribe to a channel in delta mode, you must:

1. Create a client that supports deltas (this only applies when running in a browser);
2. Configure the channel to operate in delta mode.

#### Creating a client that supports deltas

This section only applies when running in a browser. The Realtime client on all other platforms includes delta support.

To use delta functionality in the browser, you must use the [modular variant of the library](#modular-tree-shakable-variant) and create a client that includes the `Vcdiff` module:

```javascript
import { BaseRealtime, WebSocketTransport, FetchRequest, Vcdiff } from 'ably/modules';

const options = { key: 'YOUR_ABLY_KEY' };
const client = new BaseRealtime(options, {
WebSocketTransport,
FetchRequest,
Vcdiff
});
```

#### Configuring a channel to operate in delta mode

To configure a channel to operate in delta mode, specify channel parameters of `{ delta: 'vcdiff' }` when fetching the channel:

```javascript
const channel = realtime.channels.get('your-ably-channel', {
params: {
delta: 'vcdiff'
}
});
```

Beyond specifying channel options, the rest is transparent and requires no further changes to your application. The `message.data` instances that are delivered to your listening function continue to contain the values that were originally published.

Expand Down Expand Up @@ -466,13 +498,6 @@ const nextPage = await statsPage.next(); // retrieves the next page as Pa
const time = await client.time(); // time is in ms since epoch
```
## Delta Plugin
From version 1.2 this client library supports subscription to a stream of Vcdiff formatted delta messages from the Ably service. For certain applications this can bring significant data efficiency savings.
This is an optional feature so our
See the [@ably-forks/vcdiff-decoder documentation](https://github.com/ably-forks/vcdiff-decoder#usage) for setup and usage examples.
## Support, feedback and troubleshooting
Please visit http://support.ably.com/ for access to our knowledgebase and to ask for any assistance.
Expand Down
10 changes: 0 additions & 10 deletions ably.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,16 +565,6 @@ declare namespace Types {
* @defaultValue 10s
*/
realtimeRequestTimeout?: number;

/**
* A map between a plugin type and a plugin object.
*/
plugins?: {
/**
* A plugin capable of decoding `vcdiff`-encoded messages. For more information on how to configure a channel to use delta encoding, see the [documentation for the `@ably-forks/vcdiff-decoder` package](https://github.com/ably-forks/vcdiff-decoder#usage).
*/
vcdiff?: any;
};
}

/**
Expand Down
19 changes: 19 additions & 0 deletions modules.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,20 @@ export declare const FetchRequest: unknown;
*/
export declare const MessageInteractions: unknown;

/**
* Provides a {@link BaseRealtime} instance with the ability to use [delta compression](https://www.ably.com/docs/realtime/channels/channel-parameters/deltas).
*
* To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
*
* ```javascript
* import { BaseRealtime, WebSocketTransport, FetchRequest, Vcdiff } from 'ably/modules';
* const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest, Vcdiff });
* ```
*
* For information on how to configure a channel to use delta encoding, see [the documentation in the `README`](https://github.com/ably/ably-js/blob/main/README.md#configuring-a-channel-to-operate-in-delta-mode).
*/
export declare const Vcdiff: unknown;

/**
* Pass a `ModulesMap` to { @link BaseRest.constructor | the constructor of BaseRest } or {@link BaseRealtime.constructor | that of BaseRealtime} to specify which functionality should be made available to that client.
*/
Expand Down Expand Up @@ -216,6 +230,11 @@ export interface ModulesMap {
* See {@link MessageInteractions | documentation for the `MessageInteractions` module}.
*/
MessageInteractions?: typeof MessageInteractions;

/**
* See {@link Vcdiff | documentation for the `Vcdiff` module}.
*/
Vcdiff?: typeof Vcdiff;
}

/**
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
}
},
"devDependencies": {
"@ably/vcdiff-decoder": "1.0.4",
"@ably/vcdiff-decoder": "1.0.6",
"@testing-library/react": "^13.3.0",
"@types/node": "^18.0.0",
"@types/request": "^2.48.7",
Expand Down
1 change: 1 addition & 0 deletions scripts/moduleReport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const moduleNames = [
'XHRRequest',
'FetchRequest',
'MessageInteractions',
'Vcdiff',
];

// List of all free-standing functions exported by the library along with the
Expand Down
5 changes: 4 additions & 1 deletion src/common/lib/client/baserealtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import ClientOptions from '../../types/ClientOptions';
import * as API from '../../../../ably';
import { ModulesMap, RealtimePresenceModule } from './modulesmap';
import { TransportNames } from 'common/constants/TransportName';
import { TransportImplementations } from 'common/platform';
import Platform, { TransportImplementations } from 'common/platform';
import { VcdiffDecoder } from '../types/message';

/**
`BaseRealtime` is an export of the tree-shakable version of the SDK, and acts as the base class for the `DefaultRealtime` class exported by the non tree-shakable version.
*/
class BaseRealtime extends BaseClient {
readonly _RealtimePresence: RealtimePresenceModule | null;
readonly _decodeVcdiff: VcdiffDecoder | null;
// Extra transport implementations available to this client, in addition to those in Platform.Transports.bundledImplementations
readonly _additionalTransportImplementations: TransportImplementations;
_channels: any;
Expand All @@ -28,6 +30,7 @@ class BaseRealtime extends BaseClient {
Logger.logAction(Logger.LOG_MINOR, 'Realtime()', '');
this._additionalTransportImplementations = BaseRealtime.transportImplementationsFromModules(modules);
this._RealtimePresence = modules.RealtimePresence ?? null;
this._decodeVcdiff = (modules.Vcdiff ?? (Platform.Vcdiff.supported && Platform.Vcdiff.bundledDecode)) || null;
this.connection = new Connection(this, this.options);
this._channels = new Channels(this);
if (options.autoConnect !== false) this.connect();
Expand Down
2 changes: 2 additions & 0 deletions src/common/lib/client/modulesmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
fromValues as presenceMessageFromValues,
fromValuesArray as presenceMessagesFromValuesArray,
} from '../types/presencemessage';
import { VcdiffDecoder } from '../types/message';

export interface PresenceMessageModule {
presenceMessageFromValues: typeof presenceMessageFromValues;
Expand All @@ -31,6 +32,7 @@ export interface ModulesMap {
XHRRequest?: typeof XHRRequest;
FetchRequest?: typeof fetchRequest;
MessageInteractions?: typeof FilteredSubscriptions;
Vcdiff?: VcdiffDecoder;
}

export const allCommonModules: ModulesMap = { Rest };
5 changes: 3 additions & 2 deletions src/common/lib/client/realtimechannel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Message, {
decode as decodeMessage,
getMessagesSize,
CipherOptions,
EncodingDecodingContext,
} from '../types/message';
import ChannelStateChange from './channelstatechange';
import ErrorInfo, { IPartialErrorInfo, PartialErrorInfo } from '../types/errorinfo';
Expand Down Expand Up @@ -86,7 +87,7 @@ class RealtimeChannel extends EventEmitter {
_requestedFlags: Array<API.Types.ChannelMode> | null;
_mode?: null | number;
_attachResume: boolean;
_decodingContext: { channelOptions: API.Types.ChannelOptions; plugins: any; baseEncodedPreviousPayload: undefined };
_decodingContext: EncodingDecodingContext;
_lastPayload: {
messageId?: string | null;
protocolMessageChannelSerial?: string | null;
Expand Down Expand Up @@ -121,7 +122,7 @@ class RealtimeChannel extends EventEmitter {
this._attachResume = false;
this._decodingContext = {
channelOptions: this.channelOptions,
plugins: client.options.plugins || {},
decodeVcdiff: client._decodeVcdiff ?? undefined,
baseEncodedPreviousPayload: undefined,
};
this._lastPayload = {
Expand Down
22 changes: 11 additions & 11 deletions src/common/lib/types/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,18 @@ export type CipherOptions = {
};
};

export type VcdiffDecoder = (delta: Uint8Array, source: Uint8Array) => Uint8Array;

export type EncodingDecodingContext = {
channelOptions: ChannelOptions;
plugins: {
vcdiff?: {
encrypt: Function;
decode: Function;
};
};
decodeVcdiff?: VcdiffDecoder;
baseEncodedPreviousPayload?: Buffer | BrowserBufferlike;
};

function normaliseContext(context: CipherOptions | EncodingDecodingContext | ChannelOptions): EncodingDecodingContext {
if (!context || !(context as EncodingDecodingContext).channelOptions) {
return {
channelOptions: context as ChannelOptions,
plugins: {},
baseEncodedPreviousPayload: undefined,
};
}
Expand Down Expand Up @@ -217,8 +213,12 @@ export async function decode(
throw new Error('Unable to decrypt message; not an encrypted channel');
}
case 'vcdiff':
if (!context.plugins || !context.plugins.vcdiff) {
throw new ErrorInfo('Missing Vcdiff decoder (https://github.com/ably-forks/vcdiff-decoder)', 40019, 400);
if (!context.decodeVcdiff) {
if (Platform.Vcdiff.supported) {
Utils.throwMissingModuleError('Vcdiff');
} else {
throw new ErrorInfo(Platform.Vcdiff.errorMessage, 40019, 400);
}
}
if (typeof Uint8Array === 'undefined') {
throw new ErrorInfo(
Expand All @@ -234,10 +234,10 @@ export async function decode(
}

// vcdiff expects Uint8Arrays, can't copy with ArrayBuffers.
deltaBase = Platform.BufferUtils.toBuffer(deltaBase as Buffer);
const deltaBaseBuffer = Platform.BufferUtils.toBuffer(deltaBase as Buffer);
data = Platform.BufferUtils.toBuffer(data);

data = Platform.BufferUtils.arrayBufferViewToBuffer(context.plugins.vcdiff.decode(data, deltaBase));
data = Platform.BufferUtils.arrayBufferViewToBuffer(context.decodeVcdiff(data, deltaBaseBuffer));
lastPayload = data;
} catch (e) {
throw new ErrorInfo('Vcdiff delta decode failed with ' + e, 40018, 400);
Expand Down
2 changes: 1 addition & 1 deletion src/common/lib/util/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -569,5 +569,5 @@ export function arrEquals(a: any[], b: any[]) {
}

export function throwMissingModuleError(moduleName: keyof ModulesMap): never {
throw new ErrorInfo(`${moduleName} module not provided`, 400, 40000);
throw new ErrorInfo(`${moduleName} module not provided`, 40019, 400);
}
7 changes: 7 additions & 0 deletions src/common/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as WebBufferUtils from '../platform/web/lib/util/bufferutils';
import * as NodeBufferUtils from '../platform/nodejs/lib/util/bufferutils';
import { IUntypedCryptoStatic } from '../common/types/ICryptoStatic';
import TransportName from './constants/TransportName';
import { VcdiffDecoder } from './lib/types/message';

type Bufferlike = WebBufferUtils.Bufferlike | NodeBufferUtils.Bufferlike;
type BufferUtilsOutput = WebBufferUtils.Output | NodeBufferUtils.Output;
Expand Down Expand Up @@ -39,4 +40,10 @@ export default class Platform {
};
static Defaults: IDefaults;
static WebStorage: IWebStorage | null;
static Vcdiff:
| { supported: false; errorMessage: string /* explains why this platform does not support vcdiff */ }
| {
supported: true;
bundledDecode: VcdiffDecoder | null /* { supported: true, bundledDecode: null } means that the decode implementation can be provided via ModulesMap */;
};
}
2 changes: 2 additions & 0 deletions src/platform/nativescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DefaultRealtime } from '../../common/lib/client/defaultrealtime';
import Platform from '../../common/platform';
import ErrorInfo from '../../common/lib/types/errorinfo';
import { fromDeserializedIncludingDependencies as protocolMessageFromDeserialized } from '../../common/lib/types/protocolmessage';
import { decode as decodeVcdiff } from '@ably/vcdiff-decoder';

// Platform Specific
import BufferUtils from '../web/lib/util/bufferutils';
Expand All @@ -30,6 +31,7 @@ Platform.Http = Http;
Platform.Config = Config;
Platform.Transports = Transports;
Platform.WebStorage = WebStorage;
Platform.Vcdiff = { supported: true, bundledDecode: decodeVcdiff };

for (const clientClass of [DefaultRest, DefaultRealtime]) {
clientClass.Crypto = Crypto;
Expand Down
2 changes: 2 additions & 0 deletions src/platform/nodejs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DefaultRealtime } from '../../common/lib/client/defaultrealtime';
import Platform from '../../common/platform';
import ErrorInfo from '../../common/lib/types/errorinfo';
import { fromDeserializedIncludingDependencies as protocolMessageFromDeserialized } from '../../common/lib/types/protocolmessage';
import { decode as decodeVcdiff } from '@ably/vcdiff-decoder';

// Platform Specific
import BufferUtils from './lib/util/bufferutils';
Expand All @@ -26,6 +27,7 @@ Platform.Http = Http;
Platform.Config = Config;
Platform.Transports = Transports;
Platform.WebStorage = null;
Platform.Vcdiff = { supported: true, bundledDecode: decodeVcdiff };

for (const clientClass of [DefaultRest, DefaultRealtime]) {
clientClass.Crypto = Crypto;
Expand Down
2 changes: 2 additions & 0 deletions src/platform/react-native/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DefaultRealtime } from '../../common/lib/client/defaultrealtime';
import Platform from '../../common/platform';
import ErrorInfo from '../../common/lib/types/errorinfo';
import { fromDeserializedIncludingDependencies as protocolMessageFromDeserialized } from '../../common/lib/types/protocolmessage';
import { decode as decodeVcdiff } from '@ably/vcdiff-decoder';

// Platform Specific
import BufferUtils from '../web/lib/util/bufferutils';
Expand All @@ -30,6 +31,7 @@ Platform.Http = Http;
Platform.Config = Config;
Platform.Transports = Transports;
Platform.WebStorage = WebStorage;
Platform.Vcdiff = { supported: true, bundledDecode: decodeVcdiff };

for (const clientClass of [DefaultRest, DefaultRealtime]) {
clientClass.Crypto = Crypto;
Expand Down
5 changes: 5 additions & 0 deletions src/platform/web/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ Platform.Http = Http;
Platform.Config = Config;
Platform.Transports = Transports;
Platform.WebStorage = WebStorage;
// To use vcdiff on web you must use the modular variant of the library
Platform.Vcdiff = {
supported: false,
errorMessage: 'For vcdiff functionality in the browser, you must use the modular variant of ably-js',
};

for (const clientClass of [DefaultRest, DefaultRealtime]) {
clientClass.Crypto = Crypto;
Expand Down
2 changes: 2 additions & 0 deletions src/platform/web/modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Platform.Http = Http;
Platform.Config = Config;
Platform.Transports = ModulesTransports;
Platform.WebStorage = WebStorage;
Platform.Vcdiff = { supported: true, bundledDecode: null };

Http.bundledRequestImplementations = modulesBundledRequestImplementations;

Expand Down Expand Up @@ -49,6 +50,7 @@ export * from './modules/msgpack';
export * from './modules/realtimepresence';
export * from './modules/transports';
export * from './modules/http';
export * from './modules/vcdiff';
export { Rest } from '../../common/lib/client/rest';
export { FilteredSubscriptions as MessageInteractions } from '../../common/lib/client/filteredsubscriptions';
export { BaseRest, BaseRealtime, ErrorInfo };
1 change: 1 addition & 0 deletions src/platform/web/modules/vcdiff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { decode as Vcdiff } from '@ably/vcdiff-decoder';
Loading

0 comments on commit 0d1f6cb

Please sign in to comment.