Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SDK-3938] Remove the existing plugins mechanism #1512

Merged
merged 8 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
* @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 Expand Up @@ -2314,8 +2304,8 @@
*/
get(name: string, channelOptions?: ChannelOptions): T;
/**
* @experimental This is a preview feature and may change in a future non-major release.

Check warning on line 2307 in ably.d.ts

View workflow job for this annotation

GitHub Actions / lint

Invalid JSDoc tag name "experimental"
* This experimental method allows you to create custom realtime data feeds by selectively subscribing

Check warning on line 2308 in ably.d.ts

View workflow job for this annotation

GitHub Actions / lint

Expected no lines between tags
* to receive only part of the data from the channel.
* See the [announcement post](https://pages.ably.com/subscription-filters-preview) for more information.
*
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
Loading