| export default class Serializer { |
| constructor(allowedMetadataKeys) { |
| this.HEADER_LENGTH = 1; |
| this.USER_BROADCAST_PUSH_META_LENGTH = 6; |
| this.KINDS = { userBroadcastPush: 3, userBroadcast: 4 }; |
| this.BINARY_ENCODING = 0; |
| this.JSON_ENCODING = 1; |
| this.BROADCAST_EVENT = 'broadcast'; |
| this.allowedMetadataKeys = []; |
| this.allowedMetadataKeys = allowedMetadataKeys !== null && allowedMetadataKeys !== void 0 ? allowedMetadataKeys : []; |
| } |
| encode(msg, callback) { |
| if (msg.event === this.BROADCAST_EVENT && |
| !(msg.payload instanceof ArrayBuffer) && |
| typeof msg.payload.event === 'string') { |
| return callback(this._binaryEncodeUserBroadcastPush(msg)); |
| } |
| let payload = [msg.join_ref, msg.ref, msg.topic, msg.event, msg.payload]; |
| return callback(JSON.stringify(payload)); |
| } |
| _binaryEncodeUserBroadcastPush(message) { |
| var _a; |
| if (this._isArrayBuffer((_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload)) { |
| return this._encodeBinaryUserBroadcastPush(message); |
| } |
| else { |
| return this._encodeJsonUserBroadcastPush(message); |
| } |
| } |
| _encodeBinaryUserBroadcastPush(message) { |
| var _a, _b; |
| const userPayload = (_b = (_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload) !== null && _b !== void 0 ? _b : new ArrayBuffer(0); |
| return this._encodeUserBroadcastPush(message, this.BINARY_ENCODING, userPayload); |
| } |
| _encodeJsonUserBroadcastPush(message) { |
| var _a, _b; |
| const userPayload = (_b = (_a = message.payload) === null || _a === void 0 ? void 0 : _a.payload) !== null && _b !== void 0 ? _b : {}; |
| const encoder = new TextEncoder(); |
| const encodedUserPayload = encoder.encode(JSON.stringify(userPayload)).buffer; |
| return this._encodeUserBroadcastPush(message, this.JSON_ENCODING, encodedUserPayload); |
| } |
| _encodeUserBroadcastPush(message, encodingType, encodedPayload) { |
| var _a, _b; |
| |
| |
| |
| |
| const encoder = new TextEncoder(); |
| const topic = encoder.encode(message.topic); |
| const ref = encoder.encode((_a = message.ref) !== null && _a !== void 0 ? _a : ''); |
| const joinRef = encoder.encode((_b = message.join_ref) !== null && _b !== void 0 ? _b : ''); |
| const userEvent = encoder.encode(message.payload.event); |
| |
| const rest = this.allowedMetadataKeys |
| ? this._pick(message.payload, this.allowedMetadataKeys) |
| : {}; |
| const metadata = encoder.encode(Object.keys(rest).length === 0 ? '' : JSON.stringify(rest)); |
| |
| if (joinRef.length > 255) { |
| throw new Error(`joinRef length ${joinRef.length} exceeds maximum of 255`); |
| } |
| if (ref.length > 255) { |
| throw new Error(`ref length ${ref.length} exceeds maximum of 255`); |
| } |
| if (topic.length > 255) { |
| throw new Error(`topic length ${topic.length} exceeds maximum of 255`); |
| } |
| if (userEvent.length > 255) { |
| throw new Error(`userEvent length ${userEvent.length} exceeds maximum of 255`); |
| } |
| if (metadata.length > 255) { |
| throw new Error(`metadata length ${metadata.length} exceeds maximum of 255`); |
| } |
| const metaLength = this.USER_BROADCAST_PUSH_META_LENGTH + |
| joinRef.length + |
| ref.length + |
| topic.length + |
| userEvent.length + |
| metadata.length; |
| const header = new ArrayBuffer(this.HEADER_LENGTH + metaLength); |
| const view = new DataView(header); |
| const bytes = new Uint8Array(header); |
| let offset = 0; |
| view.setUint8(offset++, this.KINDS.userBroadcastPush); |
| view.setUint8(offset++, joinRef.length); |
| view.setUint8(offset++, ref.length); |
| view.setUint8(offset++, topic.length); |
| view.setUint8(offset++, userEvent.length); |
| view.setUint8(offset++, metadata.length); |
| view.setUint8(offset++, encodingType); |
| bytes.set(joinRef, offset); |
| offset += joinRef.length; |
| bytes.set(ref, offset); |
| offset += ref.length; |
| bytes.set(topic, offset); |
| offset += topic.length; |
| bytes.set(userEvent, offset); |
| offset += userEvent.length; |
| bytes.set(metadata, offset); |
| offset += metadata.length; |
| var combined = new Uint8Array(header.byteLength + encodedPayload.byteLength); |
| combined.set(new Uint8Array(header), 0); |
| combined.set(new Uint8Array(encodedPayload), header.byteLength); |
| return combined.buffer; |
| } |
| decode(rawPayload, callback) { |
| if (this._isArrayBuffer(rawPayload)) { |
| let result = this._binaryDecode(rawPayload); |
| return callback(result); |
| } |
| if (typeof rawPayload === 'string') { |
| const jsonPayload = JSON.parse(rawPayload); |
| const [join_ref, ref, topic, event, payload] = jsonPayload; |
| return callback({ join_ref, ref, topic, event, payload }); |
| } |
| return callback({}); |
| } |
| _binaryDecode(buffer) { |
| const view = new DataView(buffer); |
| const kind = view.getUint8(0); |
| const decoder = new TextDecoder(); |
| switch (kind) { |
| case this.KINDS.userBroadcast: |
| return this._decodeUserBroadcast(buffer, view, decoder); |
| } |
| } |
| _decodeUserBroadcast(buffer, view, decoder) { |
| const topicSize = view.getUint8(1); |
| const userEventSize = view.getUint8(2); |
| const metadataSize = view.getUint8(3); |
| const payloadEncoding = view.getUint8(4); |
| let offset = this.HEADER_LENGTH + 4; |
| const topic = decoder.decode(buffer.slice(offset, offset + topicSize)); |
| offset = offset + topicSize; |
| const userEvent = decoder.decode(buffer.slice(offset, offset + userEventSize)); |
| offset = offset + userEventSize; |
| const metadata = decoder.decode(buffer.slice(offset, offset + metadataSize)); |
| offset = offset + metadataSize; |
| const payload = buffer.slice(offset, buffer.byteLength); |
| const parsedPayload = payloadEncoding === this.JSON_ENCODING ? JSON.parse(decoder.decode(payload)) : payload; |
| const data = { |
| type: this.BROADCAST_EVENT, |
| event: userEvent, |
| payload: parsedPayload, |
| }; |
| |
| if (metadataSize > 0) { |
| data['meta'] = JSON.parse(metadata); |
| } |
| return { join_ref: null, ref: null, topic: topic, event: this.BROADCAST_EVENT, payload: data }; |
| } |
| _isArrayBuffer(buffer) { |
| var _a; |
| return buffer instanceof ArrayBuffer || ((_a = buffer === null || buffer === void 0 ? void 0 : buffer.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'ArrayBuffer'; |
| } |
| _pick(obj, keys) { |
| if (!obj || typeof obj !== 'object') { |
| return {}; |
| } |
| return Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key))); |
| } |
| } |
| |