mastercache
Version:
Multi-tier cache module for Node.js. Redis, Upstash, CloudfareKV, File, in-memory and others drivers
1 lines • 6.63 kB
Source Map (JSON)
{"version":3,"sources":["../../../../src/bus/encoders/binary-encoder.ts"],"sourcesContent":["import type { TransportEncoder } from '@boringnode/bus/types/main';\n\nimport { CacheBusMessageType } from '../../types/bus';\nimport type { CacheBusMessage } from '../../types/bus';\n\n/**\n * A Binary Encoder that encodes and decodes CacheBusMessage\n *\n * The encoding is as follows:\n * - The bus ID is encoded as a UTF8 string and directly appended to the resulting buffer.\n * Note that the length of the bus ID should be specified in the constructor.\n *\n * - The message type is encoded as a single byte, with 0x01 for 'Set' message, and 0x02 for a 'Delete' message\n *\n * - The keys are encoded as follows:\n * - A 4-byte big-endian integer representing the length of the key in bytes\n * - The key itself\n *\n * - These components are concatenated together in the order busId -> type -> keys\n *\n */\nexport class BinaryEncoder implements TransportEncoder {\n #busIdLength: number;\n\n /**\n * We assume the bus ID is a string of length 24 by default.\n * Because this is the default length of a cuid\n */\n constructor(busIdLength = 24) {\n this.#busIdLength = busIdLength;\n }\n\n protected busMessageTypeToNum(type: CacheBusMessageType): number {\n if (type === CacheBusMessageType.Set) return 0x01;\n if (type === CacheBusMessageType.Clear) return 0x02;\n return 0x03;\n }\n\n protected numToBusMessageType(num: number): CacheBusMessageType {\n if (num === 0x01) return CacheBusMessageType.Set;\n if (num === 0x02) return CacheBusMessageType.Clear;\n return CacheBusMessageType.Delete;\n }\n\n /**\n * Encode the given message into a Buffer\n */\n encode(message: any): string | Buffer {\n const payload = message.payload as Omit<CacheBusMessage, 'busId'>;\n\n /**\n * Compute the total size needed for storing the keys\n */\n const totalKeysLength = payload.keys.reduce(\n (sum, key) => sum + 4 + Buffer.byteLength(key, 'utf8'),\n 0,\n );\n\n const namespaceKeyLength = payload.namespace ? Buffer.byteLength(payload.namespace, 'utf8') : 0;\n\n const totalLength = this.#busIdLength + 1 + 4 + namespaceKeyLength + totalKeysLength;\n\n /**\n * Allocate a single buffer for the entire message\n */\n const buffer = Buffer.alloc(totalLength);\n\n /**\n * 1. write the bus ID\n */\n buffer.write(message.busId, 0, this.#busIdLength, 'utf8');\n\n /**\n * 2. write the message type. 0x01 for 'Set' message, and 0x02 for a 'Delete' message\n */\n buffer.writeUInt8(this.busMessageTypeToNum(payload.type), this.#busIdLength);\n\n /**\n * 3. Write the namespace\n */\n let offset = this.#busIdLength + 1;\n /**\n * Write the length of the namespace key\n */\n buffer.writeUInt32BE(namespaceKeyLength, offset);\n offset += 4;\n\n /**\n * Write the namespace itself, if not empty\n */\n if (payload.namespace) {\n buffer.write(payload.namespace, offset, namespaceKeyLength, 'utf8');\n offset += namespaceKeyLength;\n }\n\n /**\n * 4. Write the keys\n */\n for (const key of payload.keys) {\n /**\n * Compute the length of the key in bytes and write it as a 4-byte big-endian integer\n */\n const keyLength = Buffer.byteLength(key, 'utf8');\n buffer.writeUInt32BE(keyLength, offset);\n offset += 4;\n\n /**\n * Write the key itself\n */\n buffer.write(key, offset, keyLength, 'utf8');\n offset += keyLength;\n }\n\n return buffer;\n }\n\n /**\n * Decode the given Buffer into a CacheBusMessage\n */\n decode(data: string | Buffer): any {\n let offset = 0;\n const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data, 'binary');\n\n /**\n * First #busIdLength bytes are the bus ID\n */\n const busId = buffer.toString('utf8', offset, this.#busIdLength);\n offset += this.#busIdLength;\n\n /**\n * Then comes the message type as a single byte\n */\n const typeValue = buffer.readUInt8(offset++);\n const type = this.numToBusMessageType(typeValue);\n\n /**\n * Then the namespace\n */\n const namespaceKeyLength = buffer.readUInt32BE(offset);\n offset += 4;\n\n const namespace = namespaceKeyLength\n ? buffer.toString('utf8', offset, offset + namespaceKeyLength)\n : '';\n offset += namespaceKeyLength;\n\n /**\n * Finally, the keys\n */\n const keys = [];\n while (offset < buffer.length) {\n /**\n * First 4 bytes are the length of the key in bytes\n */\n const keyLength = buffer.readUInt32BE(offset);\n offset += 4;\n\n /**\n * Then comes the key itself\n */\n const key = buffer.toString('utf8', offset, offset + keyLength);\n offset += keyLength;\n\n keys.push(key);\n }\n\n return { busId, payload: { keys, type, namespace } };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBO,IAAM,gBAAN,MAAgD;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,cAAc,IAAI;AAC5B,SAAK,eAAe;AAAA,EACtB;AAAA,EAEU,oBAAoB,MAAmC;AAC/D,QAAI,yBAAkC,QAAO;AAC7C,QAAI,6BAAoC,QAAO;AAC/C,WAAO;AAAA,EACT;AAAA,EAEU,oBAAoB,KAAkC;AAC9D,QAAI,QAAQ,EAAM;AAClB,QAAI,QAAQ,EAAM;AAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,SAA+B;AACpC,UAAM,UAAU,QAAQ;AAKxB,UAAM,kBAAkB,QAAQ,KAAK;AAAA,MACnC,CAAC,KAAK,QAAQ,MAAM,IAAI,OAAO,WAAW,KAAK,MAAM;AAAA,MACrD;AAAA,IACF;AAEA,UAAM,qBAAqB,QAAQ,YAAY,OAAO,WAAW,QAAQ,WAAW,MAAM,IAAI;AAE9F,UAAM,cAAc,KAAK,eAAe,IAAI,IAAI,qBAAqB;AAKrE,UAAM,SAAS,OAAO,MAAM,WAAW;AAKvC,WAAO,MAAM,QAAQ,OAAO,GAAG,KAAK,cAAc,MAAM;AAKxD,WAAO,WAAW,KAAK,oBAAoB,QAAQ,IAAI,GAAG,KAAK,YAAY;AAK3E,QAAI,SAAS,KAAK,eAAe;AAIjC,WAAO,cAAc,oBAAoB,MAAM;AAC/C,cAAU;AAKV,QAAI,QAAQ,WAAW;AACrB,aAAO,MAAM,QAAQ,WAAW,QAAQ,oBAAoB,MAAM;AAClE,gBAAU;AAAA,IACZ;AAKA,eAAW,OAAO,QAAQ,MAAM;AAI9B,YAAM,YAAY,OAAO,WAAW,KAAK,MAAM;AAC/C,aAAO,cAAc,WAAW,MAAM;AACtC,gBAAU;AAKV,aAAO,MAAM,KAAK,QAAQ,WAAW,MAAM;AAC3C,gBAAU;AAAA,IACZ;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,MAA4B;AACjC,QAAI,SAAS;AACb,UAAM,SAAS,OAAO,SAAS,IAAI,IAAI,OAAO,OAAO,KAAK,MAAM,QAAQ;AAKxE,UAAM,QAAQ,OAAO,SAAS,QAAQ,QAAQ,KAAK,YAAY;AAC/D,cAAU,KAAK;AAKf,UAAM,YAAY,OAAO,UAAU,QAAQ;AAC3C,UAAM,OAAO,KAAK,oBAAoB,SAAS;AAK/C,UAAM,qBAAqB,OAAO,aAAa,MAAM;AACrD,cAAU;AAEV,UAAM,YAAY,qBACd,OAAO,SAAS,QAAQ,QAAQ,SAAS,kBAAkB,IAC3D;AACJ,cAAU;AAKV,UAAM,OAAO,CAAC;AACd,WAAO,SAAS,OAAO,QAAQ;AAI7B,YAAM,YAAY,OAAO,aAAa,MAAM;AAC5C,gBAAU;AAKV,YAAM,MAAM,OAAO,SAAS,QAAQ,QAAQ,SAAS,SAAS;AAC9D,gBAAU;AAEV,WAAK,KAAK,GAAG;AAAA,IACf;AAEA,WAAO,EAAE,OAAO,SAAS,EAAE,MAAM,MAAM,UAAU,EAAE;AAAA,EACrD;AACF;","names":[]}