Skip to content

Commit

Permalink
Merge pull request #1425 from ably/1375-msgpack-tree-shaking
Browse files Browse the repository at this point in the history
[SDK-3718] Create tree-shakable `MsgPack` module
  • Loading branch information
lawrence-forooghian authored Nov 9, 2023
2 parents 2fabf40 + f2e425a commit a9cc07d
Show file tree
Hide file tree
Showing 35 changed files with 258 additions and 69 deletions.
2 changes: 1 addition & 1 deletion scripts/moduleReport.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const esbuild = require('esbuild');

// List of all modules accepted in ModulesMap
const moduleNames = ['Rest', 'Crypto'];
const moduleNames = ['Rest', 'Crypto', 'MsgPack'];

// List of all free-standing functions exported by the library along with the
// ModulesMap entries that we expect them to transitively import
Expand Down
6 changes: 4 additions & 2 deletions src/common/lib/client/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ class Auth {

if (this.client.options.headers) Utils.mixin(headers, this.client.options.headers);

const requestBody = Utils.encodeBody(requestBodyDTO, format);
const requestBody = Utils.encodeBody(requestBodyDTO, this.client._MsgPack, format);
Resource.post(
this.client,
`/keys/${keyName}/revokeTokens`,
Expand All @@ -1092,7 +1092,9 @@ class Auth {
return;
}

const batchResult = (unpacked ? body : Utils.decodeBody(body, format)) as TokenRevocationResult;
const batchResult = (
unpacked ? body : Utils.decodeBody(body, this.client._MsgPack, format)
) as TokenRevocationResult;

callback(null, batchResult);
}
Expand Down
5 changes: 4 additions & 1 deletion src/common/lib/client/baseclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { ModulesMap } from './modulesmap';
import { Rest } from './rest';
import { IUntypedCryptoStatic } from 'common/types/ICryptoStatic';
import { throwMissingModuleError } from '../util/utils';
import { MsgPack } from 'common/types/msgpack';

type BatchResult<T> = API.Types.BatchResult<T>;
type BatchPublishSpec = API.Types.BatchPublishSpec;
Expand All @@ -40,6 +41,7 @@ class BaseClient {

private readonly _rest: Rest | null;
readonly _Crypto: IUntypedCryptoStatic | null;
readonly _MsgPack: MsgPack | null;

constructor(options: ClientOptions | string, modules: ModulesMap) {
if (!options) {
Expand All @@ -56,7 +58,8 @@ class BaseClient {
'initialized with clientOptions ' + Platform.Config.inspect(options)
);

const normalOptions = (this.options = Defaults.normaliseOptions(optionsObj));
this._MsgPack = modules.MsgPack ?? null;
const normalOptions = (this.options = Defaults.normaliseOptions(optionsObj, this._MsgPack));

/* process options */
if (normalOptions.key) {
Expand Down
4 changes: 2 additions & 2 deletions src/common/lib/client/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Channel extends EventEmitter {
headers: Record<string, string>,
unpacked?: boolean
) {
return await Message.fromResponseBody(body, options, unpacked ? undefined : format);
return await Message.fromResponseBody(body, options, client._MsgPack, unpacked ? undefined : format);
}).get(params as Record<string, unknown>, callback);
}

Expand Down Expand Up @@ -177,7 +177,7 @@ class Channel extends EventEmitter {
return;
}

this._publish(Message.serialize(messages, format), headers, params, callback);
this._publish(Message.serialize(messages, client._MsgPack, format), headers, params, callback);
});
}

Expand Down
10 changes: 9 additions & 1 deletion src/common/lib/client/defaultrealtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@ import ConnectionManager from '../transport/connectionmanager';
import ProtocolMessage from '../types/protocolmessage';
import Platform from 'common/platform';
import { DefaultMessage } from '../types/defaultmessage';
import { MsgPack } from 'common/types/msgpack';

/**
`DefaultRealtime` is the class that the non tree-shakable version of the SDK exports as `Realtime`. It ensures that this version of the SDK includes all of the functionality which is optionally available in the tree-shakable version.
*/
export class DefaultRealtime extends BaseRealtime {
constructor(options: ClientOptions) {
super(options, { ...allCommonModules, Crypto: DefaultRealtime.Crypto ?? undefined });
const MsgPack = DefaultRealtime._MsgPack;
if (!MsgPack) {
throw new Error('Expected DefaultRealtime._MsgPack to have been set');
}

super(options, { ...allCommonModules, Crypto: DefaultRealtime.Crypto ?? undefined, MsgPack });
}

static Utils = Utils;
Expand All @@ -32,4 +38,6 @@ export class DefaultRealtime extends BaseRealtime {
}

static Message = DefaultMessage;

static _MsgPack: MsgPack | null = null;
}
14 changes: 13 additions & 1 deletion src/common/lib/client/defaultrest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@ import ClientOptions from '../../types/ClientOptions';
import { allCommonModules } from './modulesmap';
import Platform from 'common/platform';
import { DefaultMessage } from '../types/defaultmessage';
import { MsgPack } from 'common/types/msgpack';

/**
`DefaultRest` is the class that the non tree-shakable version of the SDK exports as `Rest`. It ensures that this version of the SDK includes all of the functionality which is optionally available in the tree-shakable version.
*/
export class DefaultRest extends BaseRest {
constructor(options: ClientOptions | string) {
super(options, { ...allCommonModules, Crypto: DefaultRest.Crypto ?? undefined });
const MsgPack = DefaultRest._MsgPack;
if (!MsgPack) {
throw new Error('Expected DefaultRest._MsgPack to have been set');
}

super(options, {
...allCommonModules,
Crypto: DefaultRest.Crypto ?? undefined,
MsgPack: DefaultRest._MsgPack ?? undefined,
});
}

private static _Crypto: typeof Platform.Crypto = null;
Expand All @@ -25,4 +35,6 @@ export class DefaultRest extends BaseRest {
}

static Message = DefaultMessage;

static _MsgPack: MsgPack | null = null;
}
2 changes: 2 additions & 0 deletions src/common/lib/client/modulesmap.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Rest } from './rest';
import { IUntypedCryptoStatic } from '../../types/ICryptoStatic';
import { MsgPack } from 'common/types/msgpack';

export interface ModulesMap {
Rest?: typeof Rest;
Crypto?: IUntypedCryptoStatic;
MsgPack?: MsgPack;
}

export const allCommonModules: ModulesMap = { Rest };
14 changes: 12 additions & 2 deletions src/common/lib/client/presence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ class Presence extends EventEmitter {
headers: Record<string, string>,
unpacked?: boolean
) {
return await PresenceMessage.fromResponseBody(body, options as CipherOptions, unpacked ? undefined : format);
return await PresenceMessage.fromResponseBody(
body,
options as CipherOptions,
client._MsgPack,
unpacked ? undefined : format
);
}).get(params, callback);
}

Expand Down Expand Up @@ -82,7 +87,12 @@ class Presence extends EventEmitter {
headers: Record<string, string>,
unpacked?: boolean
) {
return await PresenceMessage.fromResponseBody(body, options as CipherOptions, unpacked ? undefined : format);
return await PresenceMessage.fromResponseBody(
body,
options as CipherOptions,
client._MsgPack,
unpacked ? undefined : format
);
}).get(params, callback);
}
}
Expand Down
23 changes: 16 additions & 7 deletions src/common/lib/client/push.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Admin {

if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

const requestBody = Utils.encodeBody(body, format);
const requestBody = Utils.encodeBody(body, client._MsgPack, format);
Resource.post(client, '/push/publish', requestBody, headers, params, null, (err) => callback(err));
}
}
Expand All @@ -71,7 +71,7 @@ class DeviceRegistrations {

if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

const requestBody = Utils.encodeBody(body, format);
const requestBody = Utils.encodeBody(body, client._MsgPack, format);
Resource.put(
client,
'/push/deviceRegistrations/' + encodeURIComponent(device.id),
Expand All @@ -85,6 +85,7 @@ class DeviceRegistrations {
!err
? (DeviceDetails.fromResponseBody(
body as Record<string, unknown>,
client._MsgPack,
unpacked ? undefined : format
) as DeviceDetails)
: undefined
Expand Down Expand Up @@ -128,6 +129,7 @@ class DeviceRegistrations {
!err
? (DeviceDetails.fromResponseBody(
body as Record<string, unknown>,
client._MsgPack,
unpacked ? undefined : format
) as DeviceDetails)
: undefined
Expand All @@ -153,7 +155,7 @@ class DeviceRegistrations {
headers: Record<string, string>,
unpacked?: boolean
) {
return DeviceDetails.fromResponseBody(body, unpacked ? undefined : format);
return DeviceDetails.fromResponseBody(body, client._MsgPack, unpacked ? undefined : format);
}).get(params, callback);
}

Expand Down Expand Up @@ -232,7 +234,7 @@ class ChannelSubscriptions {

if (client.options.pushFullWait) Utils.mixin(params, { fullWait: 'true' });

const requestBody = Utils.encodeBody(body, format);
const requestBody = Utils.encodeBody(body, client._MsgPack, format);
Resource.post(
client,
'/push/channelSubscriptions',
Expand All @@ -243,7 +245,12 @@ class ChannelSubscriptions {
function (err, body, headers, unpacked) {
callback(
err,
!err && PushChannelSubscription.fromResponseBody(body as Record<string, any>, unpacked ? undefined : format)
!err &&
PushChannelSubscription.fromResponseBody(
body as Record<string, any>,
client._MsgPack,
unpacked ? undefined : format
)
);
}
);
Expand All @@ -266,7 +273,7 @@ class ChannelSubscriptions {
headers: Record<string, string>,
unpacked?: boolean
) {
return PushChannelSubscription.fromResponseBody(body, unpacked ? undefined : format);
return PushChannelSubscription.fromResponseBody(body, client._MsgPack, unpacked ? undefined : format);
}).get(params, callback);
}

Expand Down Expand Up @@ -308,7 +315,9 @@ class ChannelSubscriptions {
headers: Record<string, string>,
unpacked?: boolean
) {
const parsedBody = (!unpacked && format ? Utils.decodeBody(body, format) : body) as Array<string>;
const parsedBody = (
!unpacked && format ? Utils.decodeBody(body, client._MsgPack, format) : body
) as Array<string>;

for (let i = 0; i < parsedBody.length; i++) {
parsedBody[i] = String(parsedBody[i]);
Expand Down
16 changes: 12 additions & 4 deletions src/common/lib/client/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import HttpMethods from '../../constants/HttpMethods';
import ErrorInfo, { IPartialErrorInfo, PartialErrorInfo } from '../types/errorinfo';
import BaseClient from './baseclient';
import { ErrnoException } from '../../types/http';
import { MsgPack } from 'common/types/msgpack';

function withAuthDetails(
client: BaseClient,
Expand All @@ -27,7 +28,11 @@ function withAuthDetails(
}
}

function unenvelope<T>(callback: ResourceCallback<T>, format: Utils.Format | null): ResourceCallback<T> {
function unenvelope<T>(
callback: ResourceCallback<T>,
MsgPack: MsgPack | null,
format: Utils.Format | null
): ResourceCallback<T> {
return (err, body, outerHeaders, unpacked, outerStatusCode) => {
if (err && !body) {
callback(err);
Expand All @@ -36,7 +41,7 @@ function unenvelope<T>(callback: ResourceCallback<T>, format: Utils.Format | nul

if (!unpacked) {
try {
body = Utils.decodeBody(body, format);
body = Utils.decodeBody(body, MsgPack, format);
} catch (e) {
if (Utils.isErrorInfoOrPartialErrorInfo(e)) {
callback(e);
Expand Down Expand Up @@ -204,7 +209,7 @@ class Resource {
}

if (envelope) {
callback = callback && unenvelope(callback, envelope);
callback = callback && unenvelope(callback, client._MsgPack, envelope);
(params = params || {})['envelope'] = envelope;
}

Expand All @@ -221,7 +226,10 @@ class Resource {
let decodedBody = body;
if (headers['content-type']?.indexOf('msgpack') > 0) {
try {
decodedBody = Platform.Config.msgpack.decode(body as Buffer);
if (!client._MsgPack) {
Utils.throwMissingModuleError('MsgPack');
}
decodedBody = client._MsgPack.decode(body as Buffer);
} catch (decodeErr) {
Logger.logAction(
Logger.LOG_MICRO,
Expand Down
26 changes: 18 additions & 8 deletions src/common/lib/client/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,17 @@ export class Rest {
customHeaders: Record<string, string>,
callback: StandardCallback<HttpPaginatedResponse<unknown>>
): Promise<HttpPaginatedResponse<unknown>> | void {
const useBinary = this.client.options.useBinaryProtocol,
encoder = useBinary ? Platform.Config.msgpack.encode : JSON.stringify,
decoder = useBinary ? Platform.Config.msgpack.decode : JSON.parse,
format = useBinary ? Utils.Format.msgpack : Utils.Format.json,
envelope = this.client.http.supportsLinkHeaders ? undefined : format;
const [encoder, decoder, format] = (() => {
if (this.client.options.useBinaryProtocol) {
if (!this.client._MsgPack) {
Utils.throwMissingModuleError('MsgPack');
}
return [this.client._MsgPack.encode, this.client._MsgPack.decode, Utils.Format.msgpack];
} else {
return [JSON.stringify, JSON.parse, Utils.Format.json];
}
})();
const envelope = this.client.http.supportsLinkHeaders ? undefined : format;
params = params || {};
const _method = method.toLowerCase() as HttpMethods;
const headers =
Expand Down Expand Up @@ -200,7 +206,7 @@ export class Rest {

if (this.client.options.headers) Utils.mixin(headers, this.client.options.headers);

const requestBody = Utils.encodeBody(requestBodyDTO, format);
const requestBody = Utils.encodeBody(requestBodyDTO, this.client._MsgPack, format);
Resource.post(
this.client,
'/messages',
Expand All @@ -214,7 +220,9 @@ export class Rest {
return;
}

const batchResults = (unpacked ? body : Utils.decodeBody(body, format)) as BatchPublishResult[];
const batchResults = (
unpacked ? body : Utils.decodeBody(body, this.client._MsgPack, format)
) as BatchPublishResult[];

// I don't love the below type assertions for `callback` but not sure how to avoid them
if (singleSpecMode) {
Expand Down Expand Up @@ -254,7 +262,9 @@ export class Rest {
return;
}

const batchResult = (unpacked ? body : Utils.decodeBody(body, format)) as BatchPresenceResult;
const batchResult = (
unpacked ? body : Utils.decodeBody(body, this.client._MsgPack, format)
) as BatchPresenceResult;

callback(null, batchResult);
}
Expand Down
6 changes: 4 additions & 2 deletions src/common/lib/transport/websockettransport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ class WebSocketTransport extends Transport {
return;
}
try {
(wsConnection as NodeWebSocket).send(ProtocolMessage.serialize(message, this.params.format));
(wsConnection as NodeWebSocket).send(
ProtocolMessage.serialize(message, this.connectionManager.realtime._MsgPack, this.params.format)
);
} catch (e) {
const msg = 'Exception from ws connection when trying to send: ' + Utils.inspectError(e);
Logger.logAction(Logger.LOG_ERROR, 'WebSocketTransport.send()', msg);
Expand All @@ -119,7 +121,7 @@ class WebSocketTransport extends Transport {
'data received; length = ' + data.length + '; type = ' + typeof data
);
try {
this.onProtocolMessage(ProtocolMessage.deserialize(data, this.format));
this.onProtocolMessage(ProtocolMessage.deserialize(data, this.connectionManager.realtime._MsgPack, this.format));
} catch (e) {
Logger.logAction(
Logger.LOG_ERROR,
Expand Down
Loading

0 comments on commit a9cc07d

Please sign in to comment.