From 52b651b53b6e24e6f19c51838fbceb2a3915e1bd Mon Sep 17 00:00:00 2001 From: menduz Date: Sat, 5 Feb 2022 13:49:03 -0300 Subject: [PATCH 01/11] add codegen and benchmark --- Makefile | 8 +- package-lock.json | 147 ++++++++++++++----- package.json | 6 +- scripts/generate-proto-file.ts | 3 +- scripts/print-proto-dsl.ts | 131 ++++++++++++++++- src/protocol/wire-protocol.ts | 254 +++++++++++++++++++++++++++++++++ test/bench.ts | 113 +++++++++++++++ test/helpers.ts | 12 +- 8 files changed, 631 insertions(+), 43 deletions(-) create mode 100644 src/protocol/wire-protocol.ts create mode 100644 test/bench.ts diff --git a/Makefile b/Makefile index 6ecb574..aa10d54 100644 --- a/Makefile +++ b/Makefile @@ -59,4 +59,10 @@ build: rm -rf node_modules/@microsoft/api-extractor/node_modules/typescript || true ./node_modules/.bin/api-extractor run $(LOCAL_ARG) --typescript-compiler-folder ./node_modules/typescript -.PHONY: build test +cheap-perf: + @time node_modules/.bin/ts-node test/bench.ts + @time node_modules/.bin/ts-node test/bench.ts + @time node_modules/.bin/ts-node test/bench.ts + @time node_modules/.bin/ts-node test/bench.ts + +.PHONY: build test cheap-perf diff --git a/package-lock.json b/package-lock.json index 5cd3fd4..84bc23d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,13 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { + "@types/bytebuffer": "^5.0.43", "@types/google-protobuf": "^3.15.5", + "bytebuffer": "^5.0.1", + "camelcase": "^6.3.0", "google-protobuf": "^3.19.1", - "mitt": "^3.0.0" + "mitt": "^3.0.0", + "pascalcase": "^2.0.0" }, "devDependencies": { "@microsoft/api-extractor": "^7.17.0", @@ -638,6 +642,15 @@ "node": ">=8" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -1089,6 +1102,15 @@ "@babel/types": "^7.3.0" } }, + "node_modules/@types/bytebuffer": { + "version": "5.0.43", + "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.43.tgz", + "integrity": "sha512-vQnTYvy4LpSojHjKdmg4nXFI1BAiYPvZ/k3ouczZAQnbDprk1xqxJiFmFHyy8y6MuUq3slz5erNMtn6n87uVKw==", + "dependencies": { + "@types/long": "*", + "@types/node": "*" + } + }, "node_modules/@types/google-protobuf": { "version": "3.15.5", "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", @@ -1137,11 +1159,15 @@ "pretty-format": "^27.0.0" } }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "node_modules/@types/node": { "version": "12.20.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", - "dev": true + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==" }, "node_modules/@types/prettier": { "version": "2.4.2", @@ -1515,6 +1541,17 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "dependencies": { + "long": "~3" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1525,12 +1562,14 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/caniuse-lite": { @@ -3025,18 +3064,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-watcher": { "version": "27.4.2", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", @@ -3264,6 +3291,14 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "node_modules/long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", + "engines": { + "node": ">=0.6" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3521,6 +3556,17 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, + "node_modules/pascalcase": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-2.0.0.tgz", + "integrity": "sha512-DHpENy5Qm/FaX+x3iBLoMLG/XHNCTgL+yErm1TwuVaj6u4fiOSkYkf60vGtITk7hrKHOO4uCl9vRrD4hqjNKjg==", + "dependencies": { + "camelcase": "^6.2.1" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4977,6 +5023,14 @@ "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } } }, "@istanbuljs/schema": { @@ -5371,6 +5425,15 @@ "@babel/types": "^7.3.0" } }, + "@types/bytebuffer": { + "version": "5.0.43", + "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.43.tgz", + "integrity": "sha512-vQnTYvy4LpSojHjKdmg4nXFI1BAiYPvZ/k3ouczZAQnbDprk1xqxJiFmFHyy8y6MuUq3slz5erNMtn6n87uVKw==", + "requires": { + "@types/long": "*", + "@types/node": "*" + } + }, "@types/google-protobuf": { "version": "3.15.5", "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", @@ -5419,11 +5482,15 @@ "pretty-format": "^27.0.0" } }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "@types/node": { "version": "12.20.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", - "dev": true + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==" }, "@types/prettier": { "version": "2.4.2", @@ -5718,6 +5785,14 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "~3" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5725,10 +5800,9 @@ "dev": true }, "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" }, "caniuse-lite": { "version": "1.0.30001292", @@ -6876,14 +6950,6 @@ "jest-get-type": "^27.4.0", "leven": "^3.1.0", "pretty-format": "^27.4.2" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } } }, "jest-watcher": { @@ -7065,6 +7131,11 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7270,6 +7341,14 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, + "pascalcase": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-2.0.0.tgz", + "integrity": "sha512-DHpENy5Qm/FaX+x3iBLoMLG/XHNCTgL+yErm1TwuVaj6u4fiOSkYkf60vGtITk7hrKHOO4uCl9vRrD4hqjNKjg==", + "requires": { + "camelcase": "^6.2.1" + } + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", diff --git a/package.json b/package.json index a5657f1..462fcbf 100644 --- a/package.json +++ b/package.json @@ -36,8 +36,12 @@ "dist" ], "dependencies": { + "@types/bytebuffer": "^5.0.43", "@types/google-protobuf": "^3.15.5", + "bytebuffer": "^5.0.1", + "camelcase": "^6.3.0", "google-protobuf": "^3.19.1", - "mitt": "^3.0.0" + "mitt": "^3.0.0", + "pascalcase": "^2.0.0" } } diff --git a/scripts/generate-proto-file.ts b/scripts/generate-proto-file.ts index 1088b63..45599f5 100644 --- a/scripts/generate-proto-file.ts +++ b/scripts/generate-proto-file.ts @@ -1,4 +1,4 @@ -import { generateProtoFile } from "./print-proto-dsl" +import { generateProtoFile, generateTsProtocol } from "./print-proto-dsl" import { field, protoDsl } from "./proto-dsl" import { writeFileSync } from "fs" @@ -157,3 +157,4 @@ proto.addMessage( ) writeFileSync("src/protocol/index.proto", generateProtoFile(proto.validate())) +writeFileSync("src/protocol/wire-protocol.ts", generateTsProtocol(proto.validate())) diff --git a/scripts/print-proto-dsl.ts b/scripts/print-proto-dsl.ts index fc917f9..c52b7cd 100644 --- a/scripts/print-proto-dsl.ts +++ b/scripts/print-proto-dsl.ts @@ -1,20 +1,21 @@ -import { isProtoEnum, isProtoMessage, ProtoEnum, ProtoMessage } from "./proto-dsl" +import { isProtoEnum, isProtoMessage, ProtoEnum, ProtoField, ProtoMessage } from "./proto-dsl" +import camelCase from "camelcase" export function generateProtoFile(names: Map): string { - const parts: string[] = [`// THIS FILE IS AUTOGENERATED`,`syntax = "proto3";`] + const parts: string[] = [`// THIS FILE IS AUTOGENERATED`, `syntax = "proto3";`] for (const [name, value] of names) { if (isProtoMessage(value)) { parts.push(`message ${name} {`) - value.fields.sort((a,b) => a.number > b.number ? 1 : -1) + value.fields.sort((a, b) => (a.number > b.number ? 1 : -1)) for (const field of value.fields) { parts.push(` ${field.repeated ? "repeated " : ""}${field.type}\t${field.name} = ${field.number};`) } parts.push(`}\n`) - } else if (isProtoEnum(value)) { + } else if (isProtoEnum(value)) { parts.push(`enum ${name} {`) for (const key in value.values) { parts.push(` ${name}_${key} = ${value.values[key]};`) @@ -25,3 +26,125 @@ export function generateProtoFile(names: Map): return parts.join("\n") } + +function mapTypescriptType(incomingType: string): string { + switch (incomingType) { + case "bytes": + return "Uint8Array" + case "bool": + return "boolean" + } + return incomingType +} + +function unaryReader(type: ProtoField): string { + switch (type.type) { + case "fixed32": + return "bb.readInt32()" + case "string": + return "_readString(bb)" + case "bytes": + return "_readBytes(bb)" + case "bool": + return "bb.readByte() != 0" + } + return `read${type.type}(bb)` +} + +function getReader(type: ProtoField): string { + if (type.repeated) { + return `_readArray(bb, (bb) => ${unaryReader(type)})` + } + return unaryReader(type) +} + +function unaryWriter(type: ProtoField, valueName: string): string { + const accessor = valueName + switch (type.type) { + case `fixed32`: + return `bb.writeInt32(${accessor})` + case `string`: + return `_writeString(bb, ${accessor})` + case `bytes`: + return `_writeBytes(bb, ${accessor})` + case `bool`: + return `bb.writeByte(${accessor} ? 1 : 0)` + } + return `write${type.type}(bb, ${accessor})` +} + +function getWriter(type: ProtoField, accessorName: string): string { + if (type.repeated) { + return `_writeArray(bb, (bb, elem) => ${unaryWriter(type, "elem")}, ${accessorName})` + } + return unaryWriter(type, accessorName) +} + +export function generateTsProtocol(names: Map): string { + const parts: string[] = [ + `// THIS FILE IS AUTOGENERATED`, + `import ByteBuffer from 'bytebuffer'`, + `export type fixed32 = number\n`, + `function _readArray(bb: ByteBuffer, reader: (bb: ByteBuffer) => T): Array {`, + ` const len = bb.readUint32(); const ret: T[] = [];`, + ` for(let i = 0; i < len; i++) ret.push(reader(bb));`, + ` return ret;`, + `}`, + `function _readString(bb: ByteBuffer) {`, + ` const len=bb.readUint32();`, + ` return bb.readString(len);`, + `}`, + `function _readBytes(bb: ByteBuffer): Uint8Array {`, + ` const len=bb.readUint32();`, + ` return bb.readBytes(len).buffer;`, + `}`, + + `function _writeArray(bb: ByteBuffer, writer: (bb: ByteBuffer, value: T) => void, array: T[]) {`, + ` bb.writeUint32(array.length);`, + ` for(let element of array) writer(bb, element);`, + `}`, + `function _writeString(bb: ByteBuffer, value: string) { // TODO: check encoding and WTF-16`, + ` bb.writeUint32(value.length);`, + ` bb.writeString(value);`, + `}`, + `function _writeBytes(bb: ByteBuffer, value: Uint8Array) {`, + ` bb.writeUint32(value.byteLength);`, + ` bb.writeBytes(value);`, + `}`, + ] + + for (const [name, value] of names) { + if (isProtoMessage(value)) { + const fields = value.fields.sort((a, b) => (a.number > b.number ? 1 : -1)) + + parts.push(`export type ${name} = {`) + for (const field of fields) { + const tsType = mapTypescriptType(field.type) + parts.push(` ${camelCase(field.name)}: ${field.repeated ? "Array<" + tsType + ">" : tsType}`) + } + parts.push(`}\n`) + + parts.push(`export function write${name}(bb: ByteBuffer, value: ${name}) {`) + for (const field of fields) { + parts.push(` ${getWriter(field, `value[${JSON.stringify(camelCase(field.name))}]`)};`) + } + parts.push(`}\n`) + + parts.push(`export function read${name}(bb: ByteBuffer): ${name} {`) + parts.push(` return {`) + for (const field of fields) { + parts.push(` ${camelCase(field.name)}: ${getReader(field)},`) + } + parts.push(` }`) + parts.push(`}\n`) + } else if (isProtoEnum(value)) { + parts.push(`export const enum ${name} {`) + for (const key in value.values) { + parts.push(` ${key} = ${value.values[key]},`) + } + parts.push(`}\n`) + } + } + + return parts.join("\n") +} diff --git a/src/protocol/wire-protocol.ts b/src/protocol/wire-protocol.ts new file mode 100644 index 0000000..a4f13ea --- /dev/null +++ b/src/protocol/wire-protocol.ts @@ -0,0 +1,254 @@ +// THIS FILE IS AUTOGENERATED +import ByteBuffer from 'bytebuffer' +export type fixed32 = number + +function _readArray(bb: ByteBuffer, reader: (bb: ByteBuffer) => T): Array { + const len = bb.readUint32(); const ret: T[] = []; + for(let i = 0; i < len; i++) ret.push(reader(bb)); + return ret; +} +function _readString(bb: ByteBuffer) { + const len=bb.readUint32(); + return bb.readString(len); +} +function _readBytes(bb: ByteBuffer): Uint8Array { + const len=bb.readUint32(); + return bb.readBytes(len).buffer; +} +function _writeArray(bb: ByteBuffer, writer: (bb: ByteBuffer, value: T) => void, array: T[]) { + bb.writeUint32(array.length); + for(let element of array) writer(bb, element); +} +function _writeString(bb: ByteBuffer, value: string) { // TODO: check encoding and WTF-16 + bb.writeUint32(value.length); + bb.writeString(value); +} +function _writeBytes(bb: ByteBuffer, value: Uint8Array) { + bb.writeUint32(value.byteLength); + bb.writeBytes(value); +} +export type RpcMessageHeader = { + messageIdentifier: fixed32 +} + +export function writeRpcMessageHeader(bb: ByteBuffer, value: RpcMessageHeader) { + bb.writeInt32(value["messageIdentifier"]); +} + +export function readRpcMessageHeader(bb: ByteBuffer): RpcMessageHeader { + return { + messageIdentifier: bb.readInt32(), + } +} + +export const enum RpcMessageTypes { + EMPTY = 0, + REQUEST = 1, + RESPONSE = 2, + STREAM_MESSAGE = 3, + STREAM_ACK = 4, + CREATE_PORT = 5, + CREATE_PORT_RESPONSE = 6, + REQUEST_MODULE = 7, + REQUEST_MODULE_RESPONSE = 8, + REMOTE_ERROR_RESPONSE = 9, + DESTROY_PORT = 10, + SERVER_READY = 11, +} + +export type CreatePort = { + messageIdentifier: fixed32 + portName: string +} + +export function writeCreatePort(bb: ByteBuffer, value: CreatePort) { + bb.writeInt32(value["messageIdentifier"]); + _writeString(bb, value["portName"]); +} + +export function readCreatePort(bb: ByteBuffer): CreatePort { + return { + messageIdentifier: bb.readInt32(), + portName: _readString(bb), + } +} + +export type CreatePortResponse = { + messageIdentifier: fixed32 + portId: fixed32 +} + +export function writeCreatePortResponse(bb: ByteBuffer, value: CreatePortResponse) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["portId"]); +} + +export function readCreatePortResponse(bb: ByteBuffer): CreatePortResponse { + return { + messageIdentifier: bb.readInt32(), + portId: bb.readInt32(), + } +} + +export type RequestModule = { + messageIdentifier: fixed32 + portId: fixed32 + moduleName: string +} + +export function writeRequestModule(bb: ByteBuffer, value: RequestModule) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["portId"]); + _writeString(bb, value["moduleName"]); +} + +export function readRequestModule(bb: ByteBuffer): RequestModule { + return { + messageIdentifier: bb.readInt32(), + portId: bb.readInt32(), + moduleName: _readString(bb), + } +} + +export type RequestModuleResponse = { + messageIdentifier: fixed32 + portId: fixed32 + procedures: Array +} + +export function writeRequestModuleResponse(bb: ByteBuffer, value: RequestModuleResponse) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["portId"]); + _writeArray(bb, (bb, elem) => writeModuleProcedure(bb, elem), value["procedures"]); +} + +export function readRequestModuleResponse(bb: ByteBuffer): RequestModuleResponse { + return { + messageIdentifier: bb.readInt32(), + portId: bb.readInt32(), + procedures: _readArray(bb, (bb) => readModuleProcedure(bb)), + } +} + +export type DestroyPort = { + messageIdentifier: fixed32 + portId: fixed32 +} + +export function writeDestroyPort(bb: ByteBuffer, value: DestroyPort) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["portId"]); +} + +export function readDestroyPort(bb: ByteBuffer): DestroyPort { + return { + messageIdentifier: bb.readInt32(), + portId: bb.readInt32(), + } +} + +export type ModuleProcedure = { + procedureId: fixed32 + procedureName: string +} + +export function writeModuleProcedure(bb: ByteBuffer, value: ModuleProcedure) { + bb.writeInt32(value["procedureId"]); + _writeString(bb, value["procedureName"]); +} + +export function readModuleProcedure(bb: ByteBuffer): ModuleProcedure { + return { + procedureId: bb.readInt32(), + procedureName: _readString(bb), + } +} + +export type Request = { + messageIdentifier: fixed32 + portId: fixed32 + procedureId: fixed32 + payload: Uint8Array +} + +export function writeRequest(bb: ByteBuffer, value: Request) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["portId"]); + bb.writeInt32(value["procedureId"]); + _writeBytes(bb, value["payload"]); +} + +export function readRequest(bb: ByteBuffer): Request { + return { + messageIdentifier: bb.readInt32(), + portId: bb.readInt32(), + procedureId: bb.readInt32(), + payload: _readBytes(bb), + } +} + +export type RemoteError = { + messageIdentifier: fixed32 + errorCode: fixed32 + errorMessage: string +} + +export function writeRemoteError(bb: ByteBuffer, value: RemoteError) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["errorCode"]); + _writeString(bb, value["errorMessage"]); +} + +export function readRemoteError(bb: ByteBuffer): RemoteError { + return { + messageIdentifier: bb.readInt32(), + errorCode: bb.readInt32(), + errorMessage: _readString(bb), + } +} + +export type Response = { + messageIdentifier: fixed32 + payload: Uint8Array +} + +export function writeResponse(bb: ByteBuffer, value: Response) { + bb.writeInt32(value["messageIdentifier"]); + _writeBytes(bb, value["payload"]); +} + +export function readResponse(bb: ByteBuffer): Response { + return { + messageIdentifier: bb.readInt32(), + payload: _readBytes(bb), + } +} + +export type StreamMessage = { + messageIdentifier: fixed32 + portId: fixed32 + sequenceId: fixed32 + payload: Uint8Array + closed: boolean + ack: boolean +} + +export function writeStreamMessage(bb: ByteBuffer, value: StreamMessage) { + bb.writeInt32(value["messageIdentifier"]); + bb.writeInt32(value["portId"]); + bb.writeInt32(value["sequenceId"]); + _writeBytes(bb, value["payload"]); + bb.writeByte(value["closed"] ? 1 : 0); + bb.writeByte(value["ack"] ? 1 : 0); +} + +export function readStreamMessage(bb: ByteBuffer): StreamMessage { + return { + messageIdentifier: bb.readInt32(), + portId: bb.readInt32(), + sequenceId: bb.readInt32(), + payload: _readBytes(bb), + closed: bb.readByte() != 0, + ack: bb.readByte() != 0, + } +} diff --git a/test/bench.ts b/test/bench.ts new file mode 100644 index 0000000..0be9546 --- /dev/null +++ b/test/bench.ts @@ -0,0 +1,113 @@ +import * as helpers from "./helpers" +import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client_pb" +import { RpcClientPort, RpcServerPort } from "../src" +import { + clientProcedureStream, + clientProcedureUnary, + serverProcedureStream, + serverProcedureUnary, +} from "../src/codegen" + +/// service BookService { +export type BookService = { + /// rpc GetBook(GetBookRequest) returns (Book) {} + GetBook(arg: GetBookRequest): Promise + /// rpc QueryBooks(QueryBooksRequest) returns (stream Book) {} + QueryBooks(arg: QueryBooksRequest): AsyncGenerator +} +/// } + +const FAIL_WITH_EXCEPTION_ISBN = 1 + +export type BookServiceModuleInitializator = (port: RpcServerPort) => Promise + +export function registerBookService(port: RpcServerPort, moduleInitializator: BookServiceModuleInitializator): void { + port.registerModule("BookService", async (port) => { + const mod = await moduleInitializator(port) + return { + GetBook: serverProcedureUnary(mod["GetBook"].bind(mod), "GetBook", GetBookRequest, Book), + QueryBooks: serverProcedureStream(mod["QueryBooks"].bind(mod), "QueryBooks", QueryBooksRequest, Book), + } + }) +} + +export function loadBookService(port: RpcClientPort): BookService { + const mod = port.loadModule("BookService") + return { + GetBook: clientProcedureUnary(mod, "GetBook", GetBookRequest, Book), + QueryBooks: clientProcedureStream(mod, "QueryBooks", QueryBooksRequest, Book), + } +} + +async function test() { + const testEnv = helpers.createSimpleTestEnvironment({ + async initializePort(port) { + registerBookService(port, async () => ({ + async GetBook(req) { + if (req.getIsbn() == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") + + const book = new Book() + book.setAuthor("menduz") + book.setIsbn(req.getIsbn()) + book.setTitle("Rpc onion layers") + return book + }, + async *QueryBooks(req) { + if (req.getAuthorPrefix() == "fail_before_yield") throw new Error("fail_before_yield") + + const books = [ + { author: "mr menduz", isbn: 1234, title: "1001 reasons to write your own OS" }, + { author: "mr cazala", isbn: 1111, title: "Advanced CSS" }, + { author: "mr mannakia", isbn: 7666, title: "Advanced binary packing" }, + { author: "mr kuruk", isbn: 7668, title: "Advanced bots AI" }, + ] + + for (const book of books) { + if (book.author.includes(req.getAuthorPrefix())) { + const protoBook = new Book() + protoBook.setAuthor(book.author) + protoBook.setIsbn(book.isbn) + protoBook.setTitle(book.title) + yield protoBook + } + } + + if (req.getAuthorPrefix() == "fail_before_end") throw new Error("fail_before_end") + }, + })) + }, + }) + + await testEnv.start() + + const { rpcClient } = testEnv + const clientPort = await rpcClient.createPort("test1") + const service = loadBookService(clientPort) + + const req1 = new GetBookRequest() + const req2 = new QueryBooksRequest() + req1.setIsbn(1234) + req2.setAuthorPrefix("mr") + let iter = 0 + + while (iter++ < 100000) { + { + const ret = await service.GetBook(req1) + if (ret.getIsbn() != 1234) throw new Error("invalid number") + } + { + const results = [] + + for await (const book of service.QueryBooks(req2)) { + results.push(book) + } + + if (results.length != 4) throw new Error("invalid length") + } + } +} + +test().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/test/helpers.ts b/test/helpers.ts index d45905e..033294b 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -27,6 +27,9 @@ export function instrumentTransport(memoryTransport: ReturnType { try { log(" (wire server->client): " + JSON.stringify(serialize(data))) @@ -35,6 +38,7 @@ export function instrumentTransport(memoryTransport: ReturnType { try { log(" (wire client->server): " + JSON.stringify(serialize(data))) @@ -42,6 +46,7 @@ export function instrumentTransport(memoryTransport: ReturnType { + async function start() { log("> Creating RPC Client") setImmediate(() => rpcServer.attachTransport(memoryTransport.server)) rpcClient = await createRpcClient(memoryTransport.client) - }) + } + + if (typeof beforeAll !== "undefined") beforeAll(start) return { + start, get rpcServer() { if (!rpcServer) throw new Error("Must se the rpcServer only inside a `it`") return rpcServer From 7423049021388ae4495f4653105cb9fbb3d16ec3 Mon Sep 17 00:00:00 2001 From: menduz Date: Sun, 6 Feb 2022 15:27:18 -0300 Subject: [PATCH 02/11] custom serialization --- Makefile | 5 +- package-lock.json | 101 ++-- package.json | 3 +- scripts/print-proto-dsl.ts | 63 +-- src/ack-helper.ts | 35 +- src/client.ts | 123 ++-- src/encdec/binary.ts | 90 +++ src/encdec/buffer.ts | 65 +++ src/encdec/decoding.ts | 668 ++++++++++++++++++++++ src/encdec/encoding.ts | 845 ++++++++++++++++++++++++++++ src/encdec/math.ts | 60 ++ src/encdec/number.ts | 29 + src/encdec/string.ts | 129 +++++ src/message-number-handler.ts | 49 +- src/protocol/helpers.ts | 149 +++-- src/protocol/wire-protocol.ts | 199 ++++--- src/server.ts | 204 +++---- src/transports/Memory.ts | 3 +- test/bench.ts | 52 +- test/close-transport.spec.ts | 87 ++- test/codegen-client.spec.ts | 2 +- test/codegen-server.spec.ts | 2 +- test/failures.spec.ts | 34 +- test/helpers.ts | 86 +-- test/reuse-ports.spec.ts | 34 +- test/sanity.spec.ts | 2 +- test/stream-from-dispatcher.spec.ts | 21 +- test/stream.spec.ts | 10 +- 28 files changed, 2537 insertions(+), 613 deletions(-) create mode 100644 src/encdec/binary.ts create mode 100644 src/encdec/buffer.ts create mode 100644 src/encdec/decoding.ts create mode 100644 src/encdec/encoding.ts create mode 100644 src/encdec/math.ts create mode 100644 src/encdec/number.ts create mode 100644 src/encdec/string.ts diff --git a/Makefile b/Makefile index aa10d54..b8b712e 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ test: --ts_out="$(PWD)/test/codegen" \ -I="$(PWD)/test/codegen" \ "$(PWD)/test/codegen/client.proto" - node_modules/.bin/jest --detectOpenHandles --colors --runInBand $(TESTARGS) --coverage + node_modules/.bin/jest --detectOpenHandles --colors --runInBand $(TESTARGS) --coverage $(TEST_FILE) test-watch: node_modules/.bin/jest --detectOpenHandles --colors --runInBand --watch $(TESTARGS) --coverage @@ -61,8 +61,5 @@ build: cheap-perf: @time node_modules/.bin/ts-node test/bench.ts - @time node_modules/.bin/ts-node test/bench.ts - @time node_modules/.bin/ts-node test/bench.ts - @time node_modules/.bin/ts-node test/bench.ts .PHONY: build test cheap-perf diff --git a/package-lock.json b/package-lock.json index 84bc23d..fed566d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,7 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@types/bytebuffer": "^5.0.43", "@types/google-protobuf": "^3.15.5", - "bytebuffer": "^5.0.1", "camelcase": "^6.3.0", "google-protobuf": "^3.19.1", "mitt": "^3.0.0", @@ -20,6 +18,7 @@ "devDependencies": { "@microsoft/api-extractor": "^7.17.0", "@types/jest": "^27.0.1", + "benchmark": "^2.1.4", "jest": "^27.0.6", "ts-jest": "^27.0.5", "ts-node": "^10.4.0", @@ -1102,15 +1101,6 @@ "@babel/types": "^7.3.0" } }, - "node_modules/@types/bytebuffer": { - "version": "5.0.43", - "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.43.tgz", - "integrity": "sha512-vQnTYvy4LpSojHjKdmg4nXFI1BAiYPvZ/k3ouczZAQnbDprk1xqxJiFmFHyy8y6MuUq3slz5erNMtn6n87uVKw==", - "dependencies": { - "@types/long": "*", - "@types/node": "*" - } - }, "node_modules/@types/google-protobuf": { "version": "3.15.5", "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", @@ -1159,15 +1149,11 @@ "pretty-format": "^27.0.0" } }, - "node_modules/@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, "node_modules/@types/node": { "version": "12.20.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==" + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", + "dev": true }, "node_modules/@types/prettier": { "version": "2.4.2", @@ -1463,6 +1449,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", + "dev": true, + "dependencies": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1541,17 +1537,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/bytebuffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", - "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", - "dependencies": { - "long": "~3" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3291,14 +3276,6 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, - "node_modules/long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", - "engines": { - "node": ">=0.6" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3639,6 +3616,12 @@ "node": ">=8" } }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "dev": true + }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -5425,15 +5408,6 @@ "@babel/types": "^7.3.0" } }, - "@types/bytebuffer": { - "version": "5.0.43", - "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.43.tgz", - "integrity": "sha512-vQnTYvy4LpSojHjKdmg4nXFI1BAiYPvZ/k3ouczZAQnbDprk1xqxJiFmFHyy8y6MuUq3slz5erNMtn6n87uVKw==", - "requires": { - "@types/long": "*", - "@types/node": "*" - } - }, "@types/google-protobuf": { "version": "3.15.5", "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", @@ -5482,15 +5456,11 @@ "pretty-format": "^27.0.0" } }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, "@types/node": { "version": "12.20.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", - "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==" + "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", + "dev": true }, "@types/prettier": { "version": "2.4.2", @@ -5723,6 +5693,16 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "benchmark": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", + "integrity": "sha1-CfPeMckWQl1JjMLuVloOvzwqVik=", + "dev": true, + "requires": { + "lodash": "^4.17.4", + "platform": "^1.3.3" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5785,14 +5765,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "bytebuffer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", - "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", - "requires": { - "long": "~3" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -7131,11 +7103,6 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, - "long": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7400,6 +7367,12 @@ "find-up": "^4.0.0" } }, + "platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", diff --git a/package.json b/package.json index 462fcbf..5daf4bd 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "devDependencies": { "@microsoft/api-extractor": "^7.17.0", "@types/jest": "^27.0.1", + "benchmark": "^2.1.4", "jest": "^27.0.6", "ts-jest": "^27.0.5", "ts-node": "^10.4.0", @@ -36,9 +37,7 @@ "dist" ], "dependencies": { - "@types/bytebuffer": "^5.0.43", "@types/google-protobuf": "^3.15.5", - "bytebuffer": "^5.0.1", "camelcase": "^6.3.0", "google-protobuf": "^3.19.1", "mitt": "^3.0.0", diff --git a/scripts/print-proto-dsl.ts b/scripts/print-proto-dsl.ts index c52b7cd..5349560 100644 --- a/scripts/print-proto-dsl.ts +++ b/scripts/print-proto-dsl.ts @@ -40,20 +40,20 @@ function mapTypescriptType(incomingType: string): string { function unaryReader(type: ProtoField): string { switch (type.type) { case "fixed32": - return "bb.readInt32()" + return "d.readUint32($)" case "string": - return "_readString(bb)" + return "_readString($)" case "bytes": - return "_readBytes(bb)" + return "_readBytes($)" case "bool": - return "bb.readByte() != 0" + return "d.readUint8($) != 0" } - return `read${type.type}(bb)` + return `read${type.type}($)` } function getReader(type: ProtoField): string { if (type.repeated) { - return `_readArray(bb, (bb) => ${unaryReader(type)})` + return `_readArray($, ($) => ${unaryReader(type)})` } return unaryReader(type) } @@ -62,20 +62,20 @@ function unaryWriter(type: ProtoField, valueName: string): string { const accessor = valueName switch (type.type) { case `fixed32`: - return `bb.writeInt32(${accessor})` + return `e.writeUint32($, ${accessor})` case `string`: - return `_writeString(bb, ${accessor})` + return `_writeString($, ${accessor})` case `bytes`: - return `_writeBytes(bb, ${accessor})` + return `_writeBytes($, ${accessor})` case `bool`: - return `bb.writeByte(${accessor} ? 1 : 0)` + return `e.writeUint8($, ${accessor} ? 1 : 0)` } - return `write${type.type}(bb, ${accessor})` + return `write${type.type}($, ${accessor})` } function getWriter(type: ProtoField, accessorName: string): string { if (type.repeated) { - return `_writeArray(bb, (bb, elem) => ${unaryWriter(type, "elem")}, ${accessorName})` + return `_writeArray($, ($, elem) => ${unaryWriter(type, "elem")}, ${accessorName})` } return unaryWriter(type, accessorName) } @@ -83,33 +83,30 @@ function getWriter(type: ProtoField, accessorName: string): string { export function generateTsProtocol(names: Map): string { const parts: string[] = [ `// THIS FILE IS AUTOGENERATED`, - `import ByteBuffer from 'bytebuffer'`, + `import * as e from '../encdec/encoding'`, + `import * as d from '../encdec/decoding'`, `export type fixed32 = number\n`, - `function _readArray(bb: ByteBuffer, reader: (bb: ByteBuffer) => T): Array {`, - ` const len = bb.readUint32(); const ret: T[] = [];`, - ` for(let i = 0; i < len; i++) ret.push(reader(bb));`, + `function _readArray($: d.Decoder, reader: ($: d.Decoder) => T): Array {`, + ` const len = d.readUint32($); const ret: T[] = [];`, + ` for(let i = 0; i < len; i++) ret.push(reader($));`, ` return ret;`, `}`, - `function _readString(bb: ByteBuffer) {`, - ` const len=bb.readUint32();`, - ` return bb.readString(len);`, + `function _readString($: d.Decoder) {`, + ` return d.readVarString($);`, `}`, - `function _readBytes(bb: ByteBuffer): Uint8Array {`, - ` const len=bb.readUint32();`, - ` return bb.readBytes(len).buffer;`, + `function _readBytes($: d.Decoder): Uint8Array {`, + ` return d.readVarUint8Array($);`, `}`, - `function _writeArray(bb: ByteBuffer, writer: (bb: ByteBuffer, value: T) => void, array: T[]) {`, - ` bb.writeUint32(array.length);`, - ` for(let element of array) writer(bb, element);`, + `function _writeArray($: e.Encoder, writer: ($: e.Encoder, value: T) => void, array: T[]) {`, + ` e.writeUint32($, array.length);`, + ` for(let element of array) writer($, element);`, `}`, - `function _writeString(bb: ByteBuffer, value: string) { // TODO: check encoding and WTF-16`, - ` bb.writeUint32(value.length);`, - ` bb.writeString(value);`, + `function _writeString($: e.Encoder, value: string) {`, + ` e.writeVarString($, value);`, `}`, - `function _writeBytes(bb: ByteBuffer, value: Uint8Array) {`, - ` bb.writeUint32(value.byteLength);`, - ` bb.writeBytes(value);`, + `function _writeBytes($: e.Encoder, value: Uint8Array) {`, + ` e.writeVarUint8Array($, value);`, `}`, ] @@ -124,13 +121,13 @@ export function generateTsProtocol(names: Map) } parts.push(`}\n`) - parts.push(`export function write${name}(bb: ByteBuffer, value: ${name}) {`) + parts.push(`export function write${name}($: e.Encoder, value: ${name}) {`) for (const field of fields) { parts.push(` ${getWriter(field, `value[${JSON.stringify(camelCase(field.name))}]`)};`) } parts.push(`}\n`) - parts.push(`export function read${name}(bb: ByteBuffer): ${name} {`) + parts.push(`export function read${name}($: d.Decoder): ${name} {`) parts.push(` return {`) for (const field of fields) { parts.push(` ${camelCase(field.name)}: ${getReader(field)},`) diff --git a/src/ack-helper.ts b/src/ack-helper.ts index e3b2e64..e84a734 100644 --- a/src/ack-helper.ts +++ b/src/ack-helper.ts @@ -1,7 +1,14 @@ -import { BinaryReader } from "google-protobuf" import { Transport } from "./types" -import { RpcMessageTypes, StreamMessage } from "./protocol/index_pb" -import { getMessageIdentifier, parseMessageIdentifier } from "./protocol/helpers" +import { parseMessageIdentifier } from "./protocol/helpers" +import { + readRpcMessageHeader, + readStreamMessage, + RpcMessageTypes, + StreamMessage, + writeStreamMessage, +} from "./protocol/wire-protocol" +import { createEncoder, toUint8Array } from "./encdec/encoding" +import { createDecoder } from "./encdec/decoding" export type AckDispatcher = { transport: Transport @@ -12,12 +19,14 @@ export function createAckHelper(transport: Transport): AckDispatcher { const oneTimeCallbacks = new Map void>() transport.on("message", (message) => { - const reader = new BinaryReader(message) - const [messageType, messageNumber] = getMessageIdentifier(reader) - if (messageType == RpcMessageTypes.RPCMESSAGETYPES_STREAM_ACK) { - reader.reset() - const data = StreamMessage.deserializeBinaryFromReader(new StreamMessage(), reader) - const key = `${messageNumber},${data.getSequenceId()}` + const reader = createDecoder(message) + const header = readRpcMessageHeader(reader) + reader.pos = 0 + const [messageType, messageNumber] = parseMessageIdentifier(header.messageIdentifier) + if (messageType == RpcMessageTypes.STREAM_ACK) { + reader.pos = 0 + const data = readStreamMessage(reader) + const key = `${messageNumber},${data.sequenceId}` const fut = oneTimeCallbacks.get(key) if (fut) { fut(data) @@ -30,9 +39,11 @@ export function createAckHelper(transport: Transport): AckDispatcher { transport, async sendWithAck(data: StreamMessage): Promise { return new Promise((ret) => { - const [_, messageNumber] = parseMessageIdentifier(data.getMessageIdentifier()) - oneTimeCallbacks.set(`${messageNumber},${data.getSequenceId()}`, ret) - transport.sendMessage(data.serializeBinary()) + const [_, messageNumber] = parseMessageIdentifier(data.messageIdentifier) + oneTimeCallbacks.set(`${messageNumber},${data.sequenceId}`, ret) + const bb = createEncoder() + writeStreamMessage(bb, data) + transport.sendMessage(toUint8Array(bb)) }) }, } diff --git a/src/client.ts b/src/client.ts index 55539d3..7b2cec0 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2,27 +2,28 @@ import { CallableProcedureClient, ClientModuleDefinition, RpcClient, RpcClientPo import { Transport } from "./types" import mitt from "mitt" import { - CreatePort, CreatePortResponse, - DestroyPort, RemoteError, Request, - RequestModule, RequestModuleResponse, Response, RpcMessageTypes, StreamMessage, -} from "./protocol/index_pb" -import { Message } from "google-protobuf" + writeCreatePort, + writeDestroyPort, + writeRequest, + writeRequestModule, +} from "./protocol/wire-protocol" import { MessageDispatcher, messageNumberHandler } from "./message-number-handler" import { pushableChannel } from "./push-channel" import { calculateMessageIdentifier, closeStreamMessage, - parseMessageIdentifier, parseProtocolMessage, streamAckMessage, } from "./protocol/helpers" +import { BinaryWriter } from "google-protobuf" +import { createEncoder, toUint8Array } from "./encdec/encoding" const EMPTY_U8 = new Uint8Array(0) @@ -41,29 +42,35 @@ export function createPort(portId: number, portName: string, dispatcher: Message return state }, close() { - const m = new DestroyPort() - m.setPortId(portId) - m.setMessageIdentifier(calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_DESTROY_PORT, 0)) - dispatcher.transport.sendMessage(m.serializeBinary()) + const bb = createEncoder() + writeDestroyPort(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.DESTROY_PORT, 0), + portId, + }) + + dispatcher.transport.sendMessage(toUint8Array(bb)) events.emit("close", {}) }, async loadModule(moduleName: string) { - const requestModuleMessage = new RequestModule() - requestModuleMessage.setModuleName(moduleName) - requestModuleMessage.setPortId(portId) - const ret = await dispatcher.request(requestModuleMessage, RpcMessageTypes.RPCMESSAGETYPES_REQUEST_MODULE) + const ret = await dispatcher.request((bb, messageNumber) => { + writeRequestModule(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REQUEST_MODULE, messageNumber), + moduleName, + portId, + }) + }) const parsedMessage = parseProtocolMessage(ret) if (parsedMessage) { - const [message] = parsedMessage - if (message instanceof RequestModuleResponse) { + const [messageType, message] = parsedMessage + if (messageType == RpcMessageTypes.REQUEST_MODULE_RESPONSE) { const ret: ClientModuleDefinition = {} - for (let procedure of message.getProceduresList()) { - ret[procedure.getProcedureName()] = createProcedure(portId, procedure.getProcedureId(), dispatcher) + for (let procedure of (message as RequestModuleResponse).procedures) { + ret[procedure.procedureName] = createProcedure(portId, procedure.procedureId, dispatcher) } return ret - } else if (message instanceof RemoteError) { + } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { throwIfRemoteError(message) } } @@ -72,10 +79,8 @@ export function createPort(portId: number, portName: string, dispatcher: Message } } -function throwIfRemoteError(parsedMessage: Message | null) { - if (parsedMessage instanceof RemoteError) { - throw new Error("RemoteError: " + parsedMessage.getErrorMessage()) - } +function throwIfRemoteError(parsedMessage: RemoteError) { + throw new Error("RemoteError: " + parsedMessage.errorMessage) } // @internal @@ -103,22 +108,20 @@ export function streamFromDispatcher( function localIteratorClosed() { if (!isRemoteClosed) { - dispatcher.transport.sendMessage( - closeStreamMessage(messageNumber, lastReceivedSequenceId, streamMessage.getPortId()) - ) + dispatcher.transport.sendMessage(closeStreamMessage(messageNumber, lastReceivedSequenceId, streamMessage.portId)) } dispatcher.removeListener(messageNumber) } function processMessage(message: StreamMessage, messageNumber: number) { - lastReceivedSequenceId = message.getSequenceId() + lastReceivedSequenceId = message.sequenceId - if (message.getClosed()) { + if (message.closed) { isRemoteClosed = true channel.close() } else { - const payload = message.getPayload_asU8() - const portId = message.getPortId() + const payload = message.payload + const portId = message.portId channel .push(payload) .then(() => { @@ -135,12 +138,14 @@ export function streamFromDispatcher( const ret = parseProtocolMessage(reader) if (ret) { - const [message, messageNumber] = ret - if (message instanceof StreamMessage) { + const [messageType, message, messageNumber] = ret + if (messageType == RpcMessageTypes.STREAM_MESSAGE) { processMessage(message, messageNumber) - } else if (message instanceof RemoteError) { + } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { isRemoteClosed = true - channel.failAndClose(new Error("RemoteError: " + (message.getErrorMessage() || "Unknown remote error"))) + channel.failAndClose( + new Error("RemoteError: " + ((message as RemoteError).errorMessage || "Unknown remote error")) + ) } else { channel.failAndClose(new Error("RemoteError: Protocol error")) } @@ -156,38 +161,41 @@ export function streamFromDispatcher( // @internal function createProcedure(portId: number, procedureId: number, dispatcher: MessageDispatcher): CallableProcedureClient { - const callProcedurePacket = new Request() - callProcedurePacket.setPortId(portId) - callProcedurePacket.setProcedureId(procedureId) + const callProcedurePacket: Request = { + portId, + messageIdentifier: 0, + payload: EMPTY_U8, + procedureId, + } return async function (data) { if (data) { - callProcedurePacket.setPayload(data) + callProcedurePacket.payload = data } else { - callProcedurePacket.setPayload(EMPTY_U8) + callProcedurePacket.payload = EMPTY_U8 } const ret = parseProtocolMessage( - await dispatcher.request(callProcedurePacket, RpcMessageTypes.RPCMESSAGETYPES_REQUEST) + await dispatcher.request((bb, messageNumber) => { + callProcedurePacket.messageIdentifier = calculateMessageIdentifier(RpcMessageTypes.REQUEST, messageNumber) + writeRequest(bb, callProcedurePacket) + }) ) if (ret) { - const [message, messageNumber] = ret - if (message instanceof Response) { - const u8 = message.getPayload_asU8() + const [messageType, message, messageNumber] = ret + if (messageType == RpcMessageTypes.RESPONSE) { + const u8 = (message as Response).payload if (u8.length) { return u8 } else { return undefined } - } else if (message instanceof StreamMessage) { + } else if (messageType == RpcMessageTypes.STREAM_MESSAGE) { return streamFromDispatcher(dispatcher, message, messageNumber) - } else { + } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { throwIfRemoteError(message) debugger } - } else { - throwIfRemoteError(null) - debugger } } } @@ -201,18 +209,23 @@ export async function createRpcClient(transport: Transport): Promise const dispatcher = messageNumberHandler(transport) async function internalCreatePort(portName: string): Promise { - const createPortMessage = new CreatePort() - createPortMessage.setPortName(portName) - const ret = await dispatcher.request(createPortMessage, RpcMessageTypes.RPCMESSAGETYPES_CREATE_PORT) + const ret = await dispatcher.request((bb, messageNumber) => { + writeCreatePort(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.CREATE_PORT, messageNumber), + portName, + }) + }) + const parsedMessage = parseProtocolMessage(ret) if (parsedMessage) { - const [message] = parsedMessage - throwIfRemoteError(message) + const [messageType, message] = parsedMessage - if (message instanceof CreatePortResponse) { - const portId = message.getPortId() + if (messageType == RpcMessageTypes.CREATE_PORT_RESPONSE) { + const portId = (message as CreatePortResponse).portId return createPort(portId, portName, dispatcher) + } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { + throwIfRemoteError(message) } } diff --git a/src/encdec/binary.ts b/src/encdec/binary.ts new file mode 100644 index 0000000..80880bb --- /dev/null +++ b/src/encdec/binary.ts @@ -0,0 +1,90 @@ +// https://github.com/dmonad/lib0 + +/** + * Binary data constants. + * + * @module binary + */ + +/** + * n-th bit activated. + * + * @type {number} + */ +export const BIT1 = 1 +export const BIT2 = 2 +export const BIT3 = 4 +export const BIT4 = 8 +export const BIT5 = 16 +export const BIT6 = 32 +export const BIT7 = 64 +export const BIT8 = 128 +export const BIT9 = 256 +export const BIT10 = 512 +export const BIT11 = 1024 +export const BIT12 = 2048 +export const BIT13 = 4096 +export const BIT14 = 8192 +export const BIT15 = 16384 +export const BIT16 = 32768 +export const BIT17 = 65536 +export const BIT18 = 1 << 17 +export const BIT19 = 1 << 18 +export const BIT20 = 1 << 19 +export const BIT21 = 1 << 20 +export const BIT22 = 1 << 21 +export const BIT23 = 1 << 22 +export const BIT24 = 1 << 23 +export const BIT25 = 1 << 24 +export const BIT26 = 1 << 25 +export const BIT27 = 1 << 26 +export const BIT28 = 1 << 27 +export const BIT29 = 1 << 28 +export const BIT30 = 1 << 29 +export const BIT31 = 1 << 30 +export const BIT32 = 1 << 31 + +/** + * First n bits activated. + * + * @type {number} + */ +export const BITS0 = 0 +export const BITS1 = 1 +export const BITS2 = 3 +export const BITS3 = 7 +export const BITS4 = 15 +export const BITS5 = 31 +export const BITS6 = 63 +export const BITS7 = 127 +export const BITS8 = 255 +export const BITS9 = 511 +export const BITS10 = 1023 +export const BITS11 = 2047 +export const BITS12 = 4095 +export const BITS13 = 8191 +export const BITS14 = 16383 +export const BITS15 = 32767 +export const BITS16 = 65535 +export const BITS17 = BIT18 - 1 +export const BITS18 = BIT19 - 1 +export const BITS19 = BIT20 - 1 +export const BITS20 = BIT21 - 1 +export const BITS21 = BIT22 - 1 +export const BITS22 = BIT23 - 1 +export const BITS23 = BIT24 - 1 +export const BITS24 = BIT25 - 1 +export const BITS25 = BIT26 - 1 +export const BITS26 = BIT27 - 1 +export const BITS27 = BIT28 - 1 +export const BITS28 = BIT29 - 1 +export const BITS29 = BIT30 - 1 +export const BITS30 = BIT31 - 1 +/** + * @type {number} + */ +export const BITS31 = 0x7fffffff +/** + * @type {number} + */ +export const BITS32 = 0xffffffff diff --git a/src/encdec/buffer.ts b/src/encdec/buffer.ts new file mode 100644 index 0000000..cb08247 --- /dev/null +++ b/src/encdec/buffer.ts @@ -0,0 +1,65 @@ +// https://github.com/dmonad/lib0 + +/** + * Utility functions to work with buffers (Uint8Array). + * + * @module buffer + */ + +import * as encoding from "./encoding" +import * as decoding from "./decoding" + +/** + * @param {number} len + */ +export const createUint8ArrayFromLen = (len: number) => new Uint8Array(len) + +/** + * Create Uint8Array with initial content from buffer + * + * @param {ArrayBuffer} buffer + * @param {number} byteOffset + * @param {number} length + */ +export const createUint8ArrayViewFromArrayBuffer = (buffer: ArrayBuffer, byteOffset: number, length: number) => + new Uint8Array(buffer, byteOffset, length) + +/** + * Create Uint8Array with initial content from buffer + * + * @param {ArrayBuffer} buffer + */ +export const createUint8ArrayFromArrayBuffer = (buffer: ArrayBuffer) => new Uint8Array(buffer) + +/** + * Copy the content of an Uint8Array view to a new ArrayBuffer. + * + * @param {Uint8Array} uint8Array + * @return {Uint8Array} + */ +export const copyUint8Array = (uint8Array: Uint8Array): Uint8Array => { + const newBuf = createUint8ArrayFromLen(uint8Array.byteLength) + newBuf.set(uint8Array) + return newBuf +} + +/** + * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type. + * See encoding.writeAny for more information. + * + * @param {any} data + * @return {Uint8Array} + */ +export const encodeAny = (data: any): Uint8Array => { + const encoder = encoding.createEncoder() + encoding.writeAny(encoder, data) + return encoding.toUint8Array(encoder) +} + +/** + * Decode an any-encoded value. + * + * @param {Uint8Array} buf + * @return {any} + */ +export const decodeAny = (buf: Uint8Array): any => decoding.readAny(decoding.createDecoder(buf)) diff --git a/src/encdec/decoding.ts b/src/encdec/decoding.ts new file mode 100644 index 0000000..e5e8d8b --- /dev/null +++ b/src/encdec/decoding.ts @@ -0,0 +1,668 @@ +// https://github.com/dmonad/lib0 + +/** + * Efficient schema-less binary decoding with support for variable length encoding. + * + * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function. + * + * Encodes numbers in little-endian order (least to most significant byte order) + * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/) + * which is also used in Protocol Buffers. + * + * ```js + * // encoding step + * const encoder = new encoding.createEncoder() + * encoding.writeVarUint(encoder, 256) + * encoding.writeVarString(encoder, 'Hello world!') + * const buf = encoding.toUint8Array(encoder) + * ``` + * + * ```js + * // decoding step + * const decoder = new decoding.createDecoder(buf) + * decoding.readVarUint(decoder) // => 256 + * decoding.readVarString(decoder) // => 'Hello world!' + * decoding.hasContent(decoder) // => false - all data is read + * ``` + * + * @module decoding + */ + +import * as buffer from "./buffer" +import * as binary from "./binary" +import * as math from "./math" + +/** + * A Decoder handles the decoding of an Uint8Array. + */ +export class Decoder { + arr: Uint8Array + pos: number + /** + * @param {Uint8Array} uint8Array Binary data to decode + */ + constructor(uint8Array: Uint8Array) { + /** + * Decoding target. + * + * @type {Uint8Array} + */ + this.arr = uint8Array + /** + * Current decoding position. + * + * @type {number} + */ + this.pos = 0 + } +} + +/** + * @function + * @param {Uint8Array} uint8Array + * @return {Decoder} + */ +export const createDecoder = (uint8Array: Uint8Array): Decoder => new Decoder(uint8Array) + +/** + * @function + * @param {Decoder} decoder + * @return {boolean} + */ +export const hasContent = (decoder: Decoder): boolean => decoder.pos !== decoder.arr.length + +/** + * Clone a decoder instance. + * Optionally set a new position parameter. + * + * @function + * @param {Decoder} decoder The decoder instance + * @param {number} [newPos] Defaults to current position + * @return {Decoder} A clone of `decoder` + */ +export const clone = (decoder: Decoder, newPos: number = decoder.pos): Decoder => { + const _decoder = createDecoder(decoder.arr) + _decoder.pos = newPos + return _decoder +} + +/** + * Create an Uint8Array view of the next `len` bytes and advance the position by `len`. + * + * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks. + * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array. + * + * @function + * @param {Decoder} decoder The decoder instance + * @param {number} len The length of bytes to read + * @return {Uint8Array} + */ +export const readUint8Array = (decoder: Decoder, len: number): Uint8Array => { + const view = buffer.createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len) + decoder.pos += len + return view +} + +/** + * Read variable length Uint8Array. + * + * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks. + * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array. + * + * @function + * @param {Decoder} decoder + * @return {Uint8Array} + */ +export const readVarUint8Array = (decoder: Decoder): Uint8Array => readUint8Array(decoder, readVarUint(decoder)) + +/** + * Read the rest of the content as an ArrayBuffer + * @function + * @param {Decoder} decoder + * @return {Uint8Array} + */ +export const readTailAsUint8Array = (decoder: Decoder): Uint8Array => + readUint8Array(decoder, decoder.arr.length - decoder.pos) + +/** + * Skip one byte, jump to the next position. + * @function + * @param {Decoder} decoder The decoder instance + * @return {number} The next position + */ +export const skip8 = (decoder: Decoder): number => decoder.pos++ + +/** + * Read one byte as unsigned integer. + * @function + * @param {Decoder} decoder The decoder instance + * @return {number} Unsigned 8-bit integer + */ +export const readUint8 = (decoder: Decoder): number => decoder.arr[decoder.pos++] + +/** + * Read 2 bytes as unsigned integer. + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer. + */ +export const readUint16 = (decoder: Decoder): number => { + const uint = decoder.arr[decoder.pos] + (decoder.arr[decoder.pos + 1] << 8) + decoder.pos += 2 + return uint +} + +/** + * Read 4 bytes as unsigned integer. + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer. + */ +export const readUint32 = (decoder: Decoder): number => { + const uint = + (decoder.arr[decoder.pos] + + (decoder.arr[decoder.pos + 1] << 8) + + (decoder.arr[decoder.pos + 2] << 16) + + (decoder.arr[decoder.pos + 3] << 24)) >>> + 0 + decoder.pos += 4 + return uint +} + +/** + * Read 4 bytes as unsigned integer in big endian order. + * (most significant byte first) + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer. + */ +export const readUint32BigEndian = (decoder: Decoder): number => { + const uint = + (decoder.arr[decoder.pos + 3] + + (decoder.arr[decoder.pos + 2] << 8) + + (decoder.arr[decoder.pos + 1] << 16) + + (decoder.arr[decoder.pos] << 24)) >>> + 0 + decoder.pos += 4 + return uint +} + +/** + * Look ahead without incrementing the position + * to the next byte and read it as unsigned integer. + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer. + */ +export const peekUint8 = (decoder: Decoder): number => decoder.arr[decoder.pos] + +/** + * Look ahead without incrementing the position + * to the next byte and read it as unsigned integer. + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer. + */ +export const peekUint16 = (decoder: Decoder): number => decoder.arr[decoder.pos] + (decoder.arr[decoder.pos + 1] << 8) + +/** + * Look ahead without incrementing the position + * to the next byte and read it as unsigned integer. + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer. + */ +export const peekUint32 = (decoder: Decoder): number => + (decoder.arr[decoder.pos] + + (decoder.arr[decoder.pos + 1] << 8) + + (decoder.arr[decoder.pos + 2] << 16) + + (decoder.arr[decoder.pos + 3] << 24)) >>> + 0 + +/** + * Read unsigned integer (32bit) with variable length. + * 1/8th of the storage is used as encoding overhead. + * * numbers < 2^7 is stored in one bytlength + * * numbers < 2^14 is stored in two bylength + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer.length + */ +export const readVarUint = (decoder: Decoder): number => { + let num = 0 + let len = 0 + while (true) { + const r = decoder.arr[decoder.pos++] + num = num | ((r & binary.BITS7) << len) + len += 7 + if (r < binary.BIT8) { + return num >>> 0 // return unsigned number! + } + /* istanbul ignore if */ + if (len > 35) { + throw new Error("Integer out of range!") + } + } +} + +/** + * Read signed integer (32bit) with variable length. + * 1/8th of the storage is used as encoding overhead. + * * numbers < 2^7 is stored in one bytlength + * * numbers < 2^14 is stored in two bylength + * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change. + * + * @function + * @param {Decoder} decoder + * @return {number} An unsigned integer.length + */ +export const readVarInt = (decoder: Decoder): number => { + let r = decoder.arr[decoder.pos++] + let num = r & binary.BITS6 + let len = 6 + const sign = (r & binary.BIT7) > 0 ? -1 : 1 + if ((r & binary.BIT8) === 0) { + // don't continue reading + return sign * num + } + while (true) { + r = decoder.arr[decoder.pos++] + num = num | ((r & binary.BITS7) << len) + len += 7 + if (r < binary.BIT8) { + return sign * (num >>> 0) + } + /* istanbul ignore if */ + if (len > 41) { + throw new Error("Integer out of range!") + } + } +} + +/** + * Look ahead and read varUint without incrementing position + * + * @function + * @param {Decoder} decoder + * @return {number} + */ +export const peekVarUint = (decoder: Decoder): number => { + const pos = decoder.pos + const s = readVarUint(decoder) + decoder.pos = pos + return s +} + +/** + * Look ahead and read varUint without incrementing position + * + * @function + * @param {Decoder} decoder + * @return {number} + */ +export const peekVarInt = (decoder: Decoder): number => { + const pos = decoder.pos + const s = readVarInt(decoder) + decoder.pos = pos + return s +} + +/** + * Read string of variable length + * * varUint is used to store the length of the string + * + * Transforming utf8 to a string is pretty expensive. The code performs 10x better + * when String.fromCodePoint is fed with all characters as arguments. + * But most environments have a maximum number of arguments per functions. + * For effiency reasons we apply a maximum of 10000 characters at once. + * + * @function + * @param {Decoder} decoder + * @return {String} The read String. + */ +export const readVarString = (decoder: Decoder): string => { + let remainingLen = readVarUint(decoder) + if (remainingLen === 0) { + return "" + } else { + let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen + if (--remainingLen < 100) { + // do not create a Uint8Array for small strings + while (remainingLen--) { + encodedString += String.fromCodePoint(readUint8(decoder)) + } + } else { + while (remainingLen > 0) { + const nextLen = remainingLen < 10000 ? remainingLen : 10000 + // this is dangerous, we create a fresh array view from the existing buffer + const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen) + decoder.pos += nextLen + // Starting with ES5.1 we can supply a generic array-like object as arguments + encodedString += String.fromCodePoint.apply(null, /** @type {any} */ bytes as any) + remainingLen -= nextLen + } + } + return decodeURIComponent(escape(encodedString)) + } +} + +/** + * Look ahead and read varString without incrementing position + * + * @function + * @param {Decoder} decoder + * @return {string} + */ +export const peekVarString = (decoder: Decoder): string => { + const pos = decoder.pos + const s = readVarString(decoder) + decoder.pos = pos + return s +} + +/** + * @param {Decoder} decoder + * @param {number} len + * @return {DataView} + */ +export const readFromDataView = (decoder: Decoder, len: number): DataView => { + const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len) + decoder.pos += len + return dv +} + +/** + * @param {Decoder} decoder + */ +export const readFloat32 = (decoder: Decoder) => readFromDataView(decoder, 4).getFloat32(0, false) + +/** + * @param {Decoder} decoder + */ +export const readFloat64 = (decoder: Decoder) => readFromDataView(decoder, 8).getFloat64(0, false) + +/** + * @param {Decoder} decoder + */ +export const readBigInt64 = (decoder: Decoder) => /** @type {any} */ readFromDataView(decoder, 8).getBigInt64(0, false) + +/** + * @param {Decoder} decoder + */ +export const readBigUint64 = (decoder: Decoder) => + /** @type {any} */ readFromDataView(decoder, 8).getBigUint64(0, false) + +/** + * @type {Array} + */ +const readAnyLookupTable: Array<(arg0: Decoder) => any> = [ + (decoder) => undefined, // CASE 127: undefined + (decoder) => null, // CASE 126: null + readVarInt, // CASE 125: integer + readFloat32, // CASE 124: float32 + readFloat64, // CASE 123: float64 + readBigInt64, // CASE 122: bigint + (decoder) => false, // CASE 121: boolean (false) + (decoder) => true, // CASE 120: boolean (true) + readVarString, // CASE 119: string + (decoder) => { + // CASE 118: object + const len = readVarUint(decoder) + /** + * @type {Object} + */ + const obj: { [s: string]: any } = {} + for (let i = 0; i < len; i++) { + const key = readVarString(decoder) + obj[key] = readAny(decoder) + } + return obj + }, + (decoder) => { + // CASE 117: array + const len = readVarUint(decoder) + const arr = [] + for (let i = 0; i < len; i++) { + arr.push(readAny(decoder)) + } + return arr + }, + readVarUint8Array, // CASE 116: Uint8Array +] + +/** + * @param {Decoder} decoder + */ +export const readAny = (decoder: Decoder) => readAnyLookupTable[127 - readUint8(decoder)](decoder) + +/** + * T must not be null. + * + * @template T + */ +export class RleDecoder extends Decoder { + reader: (arg0: Decoder) => T + /** + * @param {Uint8Array} uint8Array + * @param {function(Decoder):T} reader + */ + s: T | null + count: number + constructor(uint8Array: Uint8Array, reader: (arg0: Decoder) => T) { + super(uint8Array) + /** + * The reader + */ + this.reader = reader + /** + * Current state + * @type {T|null} + */ + this.s = null + this.count = 0 + } + + read() { + if (this.count === 0) { + this.s = this.reader(this) + if (hasContent(this)) { + this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented + } else { + this.count = -1 // read the current value forever + } + } + this.count-- + return /** @type {T} */ this.s + } +} + +export class IntDiffDecoder extends Decoder { + s: number + /** + * @param {Uint8Array} uint8Array + * @param {number} start + */ + constructor(uint8Array: Uint8Array, start: number) { + super(uint8Array) + /** + * Current state + * @type {number} + */ + this.s = start + } + + /** + * @return {number} + */ + read(): number { + this.s += readVarInt(this) + return this.s + } +} + +export class RleIntDiffDecoder extends Decoder { + s: number + count: number + /** + * @param {Uint8Array} uint8Array + * @param {number} start + */ + constructor(uint8Array: Uint8Array, start: number) { + super(uint8Array) + /** + * Current state + * @type {number} + */ + this.s = start + this.count = 0 + } + + /** + * @return {number} + */ + read(): number { + if (this.count === 0) { + this.s += readVarInt(this) + if (hasContent(this)) { + this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented + } else { + this.count = -1 // read the current value forever + } + } + this.count-- + return /** @type {number} */ this.s + } +} + +export class UintOptRleDecoder extends Decoder { + s: number + count: number + /** + * @param {Uint8Array} uint8Array + */ + constructor(uint8Array: Uint8Array) { + super(uint8Array) + /** + * @type {number} + */ + this.s = 0 + this.count = 0 + } + + read() { + if (this.count === 0) { + this.s = readVarInt(this) + // if the sign is negative, we read the count too, otherwise count is 1 + const isNegative = math.isNegativeZero(this.s) + this.count = 1 + if (isNegative) { + this.s = -this.s + this.count = readVarUint(this) + 2 + } + } + this.count-- + return /** @type {number} */ this.s + } +} + +export class IncUintOptRleDecoder extends Decoder { + s: number + count: number + /** + * @param {Uint8Array} uint8Array + */ + constructor(uint8Array: Uint8Array) { + super(uint8Array) + /** + * @type {number} + */ + this.s = 0 + this.count = 0 + } + + read() { + if (this.count === 0) { + this.s = readVarInt(this) + // if the sign is negative, we read the count too, otherwise count is 1 + const isNegative = math.isNegativeZero(this.s) + this.count = 1 + if (isNegative) { + this.s = -this.s + this.count = readVarUint(this) + 2 + } + } + this.count-- + return /** @type {number} */ this.s++ + } +} + +export class IntDiffOptRleDecoder extends Decoder { + s: number + count: number + diff: number + /** + * @param {Uint8Array} uint8Array + */ + constructor(uint8Array: Uint8Array) { + super(uint8Array) + /** + * @type {number} + */ + this.s = 0 + this.count = 0 + this.diff = 0 + } + + /** + * @return {number} + */ + read(): number { + if (this.count === 0) { + const diff = readVarInt(this) + // if the first bit is set, we read more data + const hasCount = diff & 1 + this.diff = diff >> 1 + this.count = 1 + if (hasCount) { + this.count = readVarUint(this) + 2 + } + } + this.s += this.diff + this.count-- + return this.s + } +} + +export class StringDecoder { + decoder: UintOptRleDecoder + str: string + spos: number + /** + * @param {Uint8Array} uint8Array + */ + constructor(uint8Array: Uint8Array) { + this.decoder = new UintOptRleDecoder(uint8Array) + this.str = readVarString(this.decoder) + /** + * @type {number} + */ + this.spos = 0 + } + + /** + * @return {string} + */ + read(): string { + const end = this.spos + this.decoder.read() + const res = this.str.slice(this.spos, end) + this.spos = end + return res + } +} diff --git a/src/encdec/encoding.ts b/src/encdec/encoding.ts new file mode 100644 index 0000000..798a188 --- /dev/null +++ b/src/encdec/encoding.ts @@ -0,0 +1,845 @@ +// https://github.com/dmonad/lib0 + +/** + * Efficient schema-less binary encoding with support for variable length encoding. + * + * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function. + * + * Encodes numbers in little-endian order (least to most significant byte order) + * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/) + * which is also used in Protocol Buffers. + * + * ```js + * // encoding step + * const encoder = new encoding.createEncoder() + * encoding.writeVarUint(encoder, 256) + * encoding.writeVarString(encoder, 'Hello world!') + * const buf = encoding.toUint8Array(encoder) + * ``` + * + * ```js + * // decoding step + * const decoder = new decoding.createDecoder(buf) + * decoding.readVarUint(decoder) // => 256 + * decoding.readVarString(decoder) // => 'Hello world!' + * decoding.hasContent(decoder) // => false - all data is read + * ``` + * + * @module encoding + */ + +import * as buffer from "./buffer" +import * as math from "./math" +import * as number from "./number" +import * as binary from "./binary" + +/** + * A BinaryEncoder handles the encoding to an Uint8Array. + */ +export class Encoder { + cpos = 0 + bufs: Array = [] + cbuf = new Uint8Array(100) +} + +/** + * @function + * @return {Encoder} + */ +export const createEncoder = (): Encoder => new Encoder() + +/** + * The current length of the encoded data. + * + * @function + * @param {Encoder} encoder + * @return {number} + */ +export const length = (encoder: Encoder): number => { + let len = encoder.cpos + for (let i = 0; i < encoder.bufs.length; i++) { + len += encoder.bufs[i].length + } + return len +} + +/** + * Transform to Uint8Array. + * + * @function + * @param {Encoder} encoder + * @return {Uint8Array} The created ArrayBuffer. + */ +export const toUint8Array = (encoder: Encoder): Uint8Array => { + const uint8arr = new Uint8Array(length(encoder)) + let curPos = 0 + for (let i = 0; i < encoder.bufs.length; i++) { + const d = encoder.bufs[i] + uint8arr.set(d, curPos) + curPos += d.length + } + uint8arr.set(buffer.createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos) + return uint8arr +} + +/** + * Verify that it is possible to write `len` bytes wtihout checking. If + * necessary, a new Buffer with the required length is attached. + * + * @param {Encoder} encoder + * @param {number} len + */ +const verifyLen = (encoder: Encoder, len: number) => { + const bufferLen = encoder.cbuf.length + if (bufferLen - encoder.cpos < len) { + encoder.bufs.push(buffer.createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos)) + encoder.cbuf = new Uint8Array(math.max(bufferLen, len) * 2) + encoder.cpos = 0 + } +} + +/** + * Write one byte to the encoder. + * + * @function + * @param {Encoder} encoder + * @param {number} num The byte that is to be encoded. + */ +export const write = (encoder: Encoder, num: number) => { + const bufferLen = encoder.cbuf.length + if (encoder.cpos === bufferLen) { + encoder.bufs.push(encoder.cbuf) + encoder.cbuf = new Uint8Array(bufferLen * 2) + encoder.cpos = 0 + } + encoder.cbuf[encoder.cpos++] = num +} + +/** + * Write one byte at a specific position. + * Position must already be written (i.e. encoder.length > pos) + * + * @function + * @param {Encoder} encoder + * @param {number} pos Position to which to write data + * @param {number} num Unsigned 8-bit integer + */ +export const set = (encoder: Encoder, pos: number, num: number) => { + let buffer = null + // iterate all buffers and adjust position + for (let i = 0; i < encoder.bufs.length && buffer === null; i++) { + const b = encoder.bufs[i] + if (pos < b.length) { + buffer = b // found buffer + } else { + pos -= b.length + } + } + if (buffer === null) { + // use current buffer + buffer = encoder.cbuf + } + buffer[pos] = num +} + +/** + * Write one byte as an unsigned integer. + * + * @function + * @param {Encoder} encoder + * @param {number} num The number that is to be encoded. + */ +export const writeUint8 = write + +/** + * Write one byte as an unsigned Integer at a specific location. + * + * @function + * @param {Encoder} encoder + * @param {number} pos The location where the data will be written. + * @param {number} num The number that is to be encoded. + */ +export const setUint8 = set + +/** + * Write two bytes as an unsigned integer. + * + * @function + * @param {Encoder} encoder + * @param {number} num The number that is to be encoded. + */ +export const writeUint16 = (encoder: Encoder, num: number) => { + write(encoder, num & binary.BITS8) + write(encoder, (num >>> 8) & binary.BITS8) +} +/** + * Write two bytes as an unsigned integer at a specific location. + * + * @function + * @param {Encoder} encoder + * @param {number} pos The location where the data will be written. + * @param {number} num The number that is to be encoded. + */ +export const setUint16 = (encoder: Encoder, pos: number, num: number) => { + set(encoder, pos, num & binary.BITS8) + set(encoder, pos + 1, (num >>> 8) & binary.BITS8) +} + +/** + * Write two bytes as an unsigned integer + * + * @function + * @param {Encoder} encoder + * @param {number} num The number that is to be encoded. + */ +export const writeUint32 = (encoder: Encoder, num: number) => { + for (let i = 0; i < 4; i++) { + write(encoder, num & binary.BITS8) + num >>>= 8 + } +} + +/** + * Write two bytes as an unsigned integer in big endian order. + * (most significant byte first) + * + * @function + * @param {Encoder} encoder + * @param {number} num The number that is to be encoded. + */ +export const writeUint32BigEndian = (encoder: Encoder, num: number) => { + for (let i = 3; i >= 0; i--) { + write(encoder, (num >>> (8 * i)) & binary.BITS8) + } +} + +/** + * Write two bytes as an unsigned integer at a specific location. + * + * @function + * @param {Encoder} encoder + * @param {number} pos The location where the data will be written. + * @param {number} num The number that is to be encoded. + */ +export const setUint32 = (encoder: Encoder, pos: number, num: number) => { + for (let i = 0; i < 4; i++) { + set(encoder, pos + i, num & binary.BITS8) + num >>>= 8 + } +} + +/** + * Write a variable length unsigned integer. + * + * Encodes integers in the range from [0, 4294967295] / [0, 0xffffffff]. (max 32 bit unsigned integer) + * + * @function + * @param {Encoder} encoder + * @param {number} num The number that is to be encoded. + */ +export const writeVarUint = (encoder: Encoder, num: number) => { + while (num > binary.BITS7) { + write(encoder, binary.BIT8 | (binary.BITS7 & num)) + num >>>= 7 + } + write(encoder, binary.BITS7 & num) +} + +/** + * Write a variable length integer. + * + * Encodes integers in the range from [-2147483648, -2147483647]. + * + * We don't use zig-zag encoding because we want to keep the option open + * to use the same function for BigInt and 53bit integers (doubles). + * + * We use the 7th bit instead for signaling that this is a negative number. + * + * @function + * @param {Encoder} encoder + * @param {number} num The number that is to be encoded. + */ +export const writeVarInt = (encoder: Encoder, num: number) => { + const isNegative = math.isNegativeZero(num) + if (isNegative) { + num = -num + } + // |- whether to continue reading |- whether is negative |- number + write(encoder, (num > binary.BITS6 ? binary.BIT8 : 0) | (isNegative ? binary.BIT7 : 0) | (binary.BITS6 & num)) + num >>>= 6 + // We don't need to consider the case of num === 0 so we can use a different + // pattern here than above. + while (num > 0) { + write(encoder, (num > binary.BITS7 ? binary.BIT8 : 0) | (binary.BITS7 & num)) + num >>>= 7 + } +} + +/** + * Write a variable length string. + * + * @function + * @param {Encoder} encoder + * @param {String} str The string that is to be encoded. + */ +export const writeVarString = (encoder: Encoder, str: string) => { + const encodedString = unescape(encodeURIComponent(str)) + const len = encodedString.length + writeVarUint(encoder, len) + for (let i = 0; i < len; i++) { + write(encoder, /** @type {number} */ encodedString.codePointAt(i)!) + } +} + +/** + * Write the content of another Encoder. + * + * @TODO: can be improved! + * - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure. + * Encoders start with a rather big initial buffer. + * + * @function + * @param {Encoder} encoder The enUint8Arr + * @param {Encoder} append The BinaryEncoder to be written. + */ +export const writeBinaryEncoder = (encoder: Encoder, append: Encoder) => writeUint8Array(encoder, toUint8Array(append)) + +/** + * Append fixed-length Uint8Array to the encoder. + * + * @function + * @param {Encoder} encoder + * @param {Uint8Array} uint8Array + */ +export const writeUint8Array = (encoder: Encoder, uint8Array: Uint8Array) => { + const bufferLen = encoder.cbuf.length + const cpos = encoder.cpos + const leftCopyLen = math.min(bufferLen - cpos, uint8Array.length) + const rightCopyLen = uint8Array.length - leftCopyLen + encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos) + encoder.cpos += leftCopyLen + if (rightCopyLen > 0) { + // Still something to write, write right half.. + // Append new buffer + encoder.bufs.push(encoder.cbuf) + // must have at least size of remaining buffer + encoder.cbuf = new Uint8Array(math.max(bufferLen * 2, rightCopyLen)) + // copy array + encoder.cbuf.set(uint8Array.subarray(leftCopyLen)) + encoder.cpos = rightCopyLen + } +} + +/** + * Append an Uint8Array to Encoder. + * + * @function + * @param {Encoder} encoder + * @param {Uint8Array} uint8Array + */ +export const writeVarUint8Array = (encoder: Encoder, uint8Array: Uint8Array) => { + writeVarUint(encoder, uint8Array.byteLength) + writeUint8Array(encoder, uint8Array) +} + +/** + * Create an DataView of the next `len` bytes. Use it to write data after + * calling this function. + * + * ```js + * // write float32 using DataView + * const dv = writeOnDataView(encoder, 4) + * dv.setFloat32(0, 1.1) + * // read float32 using DataView + * const dv = readFromDataView(encoder, 4) + * dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result) + * ``` + * + * @param {Encoder} encoder + * @param {number} len + * @return {DataView} + */ +export const writeOnDataView = (encoder: Encoder, len: number): DataView => { + verifyLen(encoder, len) + const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len) + encoder.cpos += len + return dview +} + +/** + * @param {Encoder} encoder + * @param {number} num + */ +export const writeFloat32 = (encoder: Encoder, num: number) => writeOnDataView(encoder, 4).setFloat32(0, num, false) + +/** + * @param {Encoder} encoder + * @param {number} num + */ +export const writeFloat64 = (encoder: Encoder, num: number) => writeOnDataView(encoder, 8).setFloat64(0, num, false) + +/** + * @param {Encoder} encoder + * @param {bigint} num + */ +export const writeBigInt64 = (encoder: Encoder, num: bigint) => + /** @type {any} */ writeOnDataView(encoder, 8).setBigInt64(0, num, false) + +/** + * @param {Encoder} encoder + * @param {bigint} num + */ +export const writeBigUint64 = (encoder: Encoder, num: bigint) => + /** @type {any} */ writeOnDataView(encoder, 8).setBigUint64(0, num, false) + +const floatTestBed = new DataView(new ArrayBuffer(4)) +/** + * Check if a number can be encoded as a 32 bit float. + * + * @param {number} num + * @return {boolean} + */ +const isFloat32 = (num: number): boolean => { + floatTestBed.setFloat32(0, num) + return floatTestBed.getFloat32(0) === num +} + +/** + * Encode data with efficient binary format. + * + * Differences to JSON: + * • Transforms data to a binary format (not to a string) + * • Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON) + * • Numbers are efficiently encoded either as a variable length integer, as a + * 32 bit float, as a 64 bit float, or as a 64 bit bigint. + * + * Encoding table: + * + * | Data Type | Prefix | Encoding Method | Comment | + * | ------------------- | -------- | ------------------ | ------- | + * | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined | + * | null | 126 | | | + * | integer | 125 | writeVarInt | Only encodes 32 bit signed integers | + * | float32 | 124 | writeFloat32 | | + * | float64 | 123 | writeFloat64 | | + * | bigint | 122 | writeBigInt64 | | + * | boolean (false) | 121 | | True and false are different data types so we save the following byte | + * | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false | + * | string | 119 | writeVarString | | + * | object | 118 | custom | Writes {length} then {length} key-value pairs | + * | array | 117 | custom | Writes {length} then {length} json values | + * | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data | + * + * Reasons for the decreasing prefix: + * We need the first bit for extendability (later we may want to encode the + * prefix with writeVarUint). The remaining 7 bits are divided as follows: + * [0-30] the beginning of the data range is used for custom purposes + * (defined by the function that uses this library) + * [31-127] the end of the data range is used for data encoding by + * lib0/encoding.js + * + * @param {Encoder} encoder + * @param {undefined|null|number|bigint|boolean|string|Object|Array|Uint8Array} data + */ +export const writeAny = ( + encoder: Encoder, + data: undefined | null | number | bigint | boolean | string | { [s: string]: any } | Array | Uint8Array +) => { + switch (typeof data) { + case "string": + // TYPE 119: STRING + write(encoder, 119) + writeVarString(encoder, data) + break + case "number": + if (number.isInteger(data) && data <= binary.BITS31) { + // TYPE 125: INTEGER + write(encoder, 125) + writeVarInt(encoder, data) + } else if (isFloat32(data)) { + // TYPE 124: FLOAT32 + write(encoder, 124) + writeFloat32(encoder, data) + } else { + // TYPE 123: FLOAT64 + write(encoder, 123) + writeFloat64(encoder, data) + } + break + case "bigint": + // TYPE 122: BigInt + write(encoder, 122) + writeBigInt64(encoder, data) + break + case "object": + if (data === null) { + // TYPE 126: null + write(encoder, 126) + } else if (data instanceof Array) { + // TYPE 117: Array + write(encoder, 117) + writeVarUint(encoder, data.length) + for (let i = 0; i < data.length; i++) { + writeAny(encoder, data[i]) + } + } else if (data instanceof Uint8Array) { + // TYPE 116: ArrayBuffer + write(encoder, 116) + writeVarUint8Array(encoder, data) + } else { + // TYPE 118: Object + write(encoder, 118) + const keys = Object.keys(data) + writeVarUint(encoder, keys.length) + for (let i = 0; i < keys.length; i++) { + const key = keys[i] + writeVarString(encoder, key) + writeAny(encoder, data[key]) + } + } + break + case "boolean": + // TYPE 120/121: boolean (true/false) + write(encoder, data ? 120 : 121) + break + default: + // TYPE 127: undefined + write(encoder, 127) + } +} + +/** + * Now come a few stateful encoder that have their own classes. + */ + +/** + * Basic Run Length Encoder - a basic compression implementation. + * + * Encodes [1,1,1,7] to [1,3,7,1] (3 times 1, 1 time 7). This encoder might do more harm than good if there are a lot of values that are not repeated. + * + * It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf + * + * @note T must not be null! + * + * @template T + */ +export class RleEncoder extends Encoder { + /** + * @param {function(Encoder, T):void} writer + */ + w: (arg0: Encoder, arg1: T) => void + s: T | null = null + count: number + constructor(writer: (arg0: Encoder, arg1: T) => void) { + super() + /** + * The writer + */ + this.w = writer + /** + * Current state + * @type {T|null} + */ + this.s = null + this.count = 0 + } + + /** + * @param {T} v + */ + write(v: T) { + if (this.s === v) { + this.count++ + } else { + if (this.count > 0) { + // flush counter, unless this is the first value (count = 0) + writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw + } + this.count = 1 + // write first value + this.w(this, v) + this.s = v + } + } +} + +/** + * Basic diff decoder using variable length encoding. + * + * Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt. + */ +export class IntDiffEncoder extends Encoder { + /** + * @param {number} start + */ + s: number + constructor(start: number) { + super() + /** + * Current state + * @type {number} + */ + this.s = start + } + + /** + * @param {number} v + */ + write(v: number) { + writeVarInt(this, v - this.s) + this.s = v + } +} + +/** + * A combination of IntDiffEncoder and RleEncoder. + * + * Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding. + * + * Encodes the values [1,1,1,2,3,4,5,6] as [1,1,0,2,1,5] (RLE([1,0,0,1,1,1,1,1]) ⇒ RleIntDiff[1,1,0,2,1,5]) + */ +export class RleIntDiffEncoder extends Encoder { + s: number + count: number + /** + * @param {number} start + */ + constructor(start: number) { + super() + /** + * Current state + * @type {number} + */ + this.s = start + this.count = 0 + } + + /** + * @param {number} v + */ + write(v: number) { + if (this.s === v && this.count > 0) { + this.count++ + } else { + if (this.count > 0) { + // flush counter, unless this is the first value (count = 0) + writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw + } + this.count = 1 + // write first value + writeVarInt(this, v - this.s) + this.s = v + } + } +} + +/** + * @param {UintOptRleEncoder} encoder + */ +const flushUintOptRleEncoder = (encoder: UintOptRleEncoder) => { + /* istanbul ignore else */ + if (encoder.count > 0) { + // flush counter, unless this is the first value (count = 0) + // case 1: just a single value. set sign to positive + // case 2: write several values. set sign to negative to indicate that there is a length coming + writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s) + if (encoder.count > 1) { + writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw + } + } +} + +/** + * Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder. + * + * Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write + * write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count. + * + * Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3) + */ +export class UintOptRleEncoder { + encoder: Encoder + s: number + count: number + constructor() { + this.encoder = new Encoder() + /** + * @type {number} + */ + this.s = 0 + this.count = 0 + } + + /** + * @param {number} v + */ + write(v: number) { + if (this.s === v) { + this.count++ + } else { + flushUintOptRleEncoder(this) + this.count = 1 + this.s = v + } + } + + toUint8Array() { + flushUintOptRleEncoder(this) + return toUint8Array(this.encoder) + } +} + +/** + * Increasing Uint Optimized RLE Encoder + * + * The RLE encoder counts the number of same occurences of the same value. + * The IncUintOptRle encoder counts if the value increases. + * I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded + * as [1, 3, 5]. + */ +export class IncUintOptRleEncoder { + encoder: Encoder + s: number + count: number + constructor() { + this.encoder = new Encoder() + /** + * @type {number} + */ + this.s = 0 + this.count = 0 + } + + /** + * @param {number} v + */ + write(v: number) { + if (this.s + this.count === v) { + this.count++ + } else { + flushUintOptRleEncoder(this) + this.count = 1 + this.s = v + } + } + + toUint8Array() { + flushUintOptRleEncoder(this) + return toUint8Array(this.encoder) + } +} + +/** + * @param {IntDiffOptRleEncoder} encoder + */ +const flushIntDiffOptRleEncoder = (encoder: IntDiffOptRleEncoder) => { + if (encoder.count > 0) { + // 31 bit making up the diff | wether to write the counter + const encodedDiff = (encoder.diff << 1) | (encoder.count === 1 ? 0 : 1) + // flush counter, unless this is the first value (count = 0) + // case 1: just a single value. set first bit to positive + // case 2: write several values. set first bit to negative to indicate that there is a length coming + writeVarInt(encoder.encoder, encodedDiff) + if (encoder.count > 1) { + writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw + } + } +} + +/** + * A combination of the IntDiffEncoder and the UintOptRleEncoder. + * + * The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes + * in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers! + * + * Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1]) + * + * Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains: + * * 1 bit that denotes whether the next value is a count (LSB) + * * 1 bit that denotes whether this value is negative (MSB - 1) + * * 1 bit that denotes whether to continue reading the variable length integer (MSB) + * + * Therefore, only five bits remain to encode diff ranges. + * + * Use this Encoder only when appropriate. In most cases, this is probably a bad idea. + */ +export class IntDiffOptRleEncoder { + encoder: Encoder + s: number + count: number + diff: number + constructor() { + this.encoder = new Encoder() + /** + * @type {number} + */ + this.s = 0 + this.count = 0 + this.diff = 0 + } + + /** + * @param {number} v + */ + write(v: number) { + if (this.diff === v - this.s) { + this.s = v + this.count++ + } else { + flushIntDiffOptRleEncoder(this) + this.count = 1 + this.diff = v - this.s + this.s = v + } + } + + toUint8Array() { + flushIntDiffOptRleEncoder(this) + return toUint8Array(this.encoder) + } +} + +/** + * Optimized String Encoder. + * + * Encoding many small strings in a simple Encoder is not very efficient. The function call to decode a string takes some time and creates references that must be eventually deleted. + * In practice, when decoding several million small strings, the GC will kick in more and more often to collect orphaned string objects (or maybe there is another reason?). + * + * This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call. + * + * The lengths are encoded using a UintOptRleEncoder. + */ +export class StringEncoder { + sarr: string[] + s: string + lensE: UintOptRleEncoder + constructor() { + /** + * @type {Array} + */ + this.sarr = [] + this.s = "" + this.lensE = new UintOptRleEncoder() + } + + /** + * @param {string} string + */ + write(string: string) { + this.s += string + if (this.s.length > 19) { + this.sarr.push(this.s) + this.s = "" + } + this.lensE.write(string.length) + } + + toUint8Array() { + const encoder = new Encoder() + this.sarr.push(this.s) + this.s = "" + writeVarString(encoder, this.sarr.join("")) + writeUint8Array(encoder, this.lensE.toUint8Array()) + return toUint8Array(encoder) + } +} diff --git a/src/encdec/math.ts b/src/encdec/math.ts new file mode 100644 index 0000000..e8c2177 --- /dev/null +++ b/src/encdec/math.ts @@ -0,0 +1,60 @@ +// https://github.com/dmonad/lib0 + +/** + * Common Math expressions. + * + * @module math + */ + +export const floor = Math.floor +export const ceil = Math.ceil +export const abs = Math.abs +export const imul = Math.imul +export const round = Math.round +export const log10 = Math.log10 +export const log2 = Math.log2 +export const log = Math.log +export const sqrt = Math.sqrt + +/** + * @function + * @param {number} a + * @param {number} b + * @return {number} The sum of a and b + */ +export const add = (a: number, b: number): number => a + b + +/** + * @function + * @param {number} a + * @param {number} b + * @return {number} The smaller element of a and b + */ +export const min = (a: number, b: number): number => (a < b ? a : b) + +/** + * @function + * @param {number} a + * @param {number} b + * @return {number} The bigger element of a and b + */ +export const max = (a: number, b: number): number => (a > b ? a : b) + +export const isNaN = Number.isNaN + +export const pow = Math.pow +/** + * Base 10 exponential function. Returns the value of 10 raised to the power of pow. + * + * @param {number} exp + * @return {number} + */ +export const exp10 = (exp: number): number => Math.pow(10, exp) + +export const sign = Math.sign + +/** + * @param {number} n + * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0 + */ +export const isNegativeZero = (n: number): boolean => (n !== 0 ? n < 0 : 1 / n < 0) diff --git a/src/encdec/number.ts b/src/encdec/number.ts new file mode 100644 index 0000000..ec532be --- /dev/null +++ b/src/encdec/number.ts @@ -0,0 +1,29 @@ +// https://github.com/dmonad/lib0 + +/** + * Utility helpers for working with numbers. + * + * @module number + */ + +import * as math from "./math" +import * as binary from "./binary" + +export const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER +export const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER + +export const LOWEST_INT32 = 1 << 31 +/** + * @type {number} + */ +export const HIGHEST_INT32 = binary.BITS31 + +/** + * @module number + */ + +/* istanbul ignore next */ +export const isInteger = + Number.isInteger || ((num) => typeof num === "number" && isFinite(num) && math.floor(num) === num) +export const isNaN = Number.isNaN +export const parseInt = Number.parseInt diff --git a/src/encdec/string.ts b/src/encdec/string.ts new file mode 100644 index 0000000..2e82d4e --- /dev/null +++ b/src/encdec/string.ts @@ -0,0 +1,129 @@ +// https://github.com/dmonad/lib0 + +declare var TextEncoder: any +declare var TextDecoder: any + +/** + * Utility module to work with strings. + * + * @module string + */ + +export const fromCharCode = String.fromCharCode +export const fromCodePoint = String.fromCodePoint + +/** + * @param {string} s + * @return {string} + */ +const toLowerCase = (s: string): string => s.toLowerCase() + +const trimLeftRegex = /^\s*/g + +/** + * @param {string} s + * @return {string} + */ +export const trimLeft = (s: string): string => s.replace(trimLeftRegex, "") + +const fromCamelCaseRegex = /([A-Z])/g + +/** + * @param {string} s + * @param {string} separator + * @return {string} + */ +export const fromCamelCase = (s: string, separator: string): string => + trimLeft(s.replace(fromCamelCaseRegex, (match: any) => `${separator}${toLowerCase(match)}`)) + +/** + * Compute the utf8ByteLength + * @param {string} str + * @return {number} + */ +export const utf8ByteLength = (str: string | number | boolean): number => unescape(encodeURIComponent(str)).length + +/** + * @param {string} str + * @return {Uint8Array} + */ +export const _encodeUtf8Polyfill = (str: string | number | boolean): Uint8Array => { + const encodedString = unescape(encodeURIComponent(str)) + const len = encodedString.length + const buf = new Uint8Array(len) + for (let i = 0; i < len; i++) { + buf[i] = /** @type {number} */ encodedString.codePointAt(i)! + } + return buf +} + +/* istanbul ignore next */ +export const utf8TextEncoder = /** @type {TextEncoder} */ new TextEncoder() + +/** + * @param {string} str + * @return {Uint8Array} + */ +export const _encodeUtf8Native = (str: any): Uint8Array => utf8TextEncoder.encode(str) + +/** + * @param {string} str + * @return {Uint8Array} + */ +/* istanbul ignore next */ +export const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill + +/** + * @param {Uint8Array} buf + * @return {string} + */ +export const _decodeUtf8Polyfill = (buf: { length: any; subarray: (arg0: number, arg1: any) => any }): string => { + let remainingLen = buf.length + let encodedString = "" + let bufPos = 0 + while (remainingLen > 0) { + const nextLen = remainingLen < 10000 ? remainingLen : 10000 + const bytes = buf.subarray(bufPos, bufPos + nextLen) + bufPos += nextLen + // Starting with ES5.1 we can supply a generic array-like object as arguments + encodedString += String.fromCodePoint.apply(null, /** @type {any} */ bytes) + remainingLen -= nextLen + } + return decodeURIComponent(escape(encodedString)) +} + +/* istanbul ignore next */ +export let utf8TextDecoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }) + +/* istanbul ignore next */ +if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) { + // Safari doesn't handle BOM correctly. + // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called. + // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and + // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call + // Another issue is that from then on no BOM chars are recognized anymore + /* istanbul ignore next */ + utf8TextDecoder = null +} + +/** + * @param {Uint8Array} buf + * @return {string} + */ +export const _decodeUtf8Native = (buf: any): string => /** @type {TextDecoder} */ utf8TextDecoder.decode(buf) + +/** + * @param {Uint8Array} buf + * @return {string} + */ +/* istanbul ignore next */ +export const decodeUtf8 = utf8TextDecoder ? _decodeUtf8Native : _decodeUtf8Polyfill + +/** + * @param {string} str The initial string + * @param {number} index Starting position + * @param {number} remove Number of characters to remove + * @param {string} insert New content to insert + */ +export const splice = (str: string, index: any, remove: any, insert: string = "") => + str.slice(0, index) + insert + str.slice(index + remove) diff --git a/src/message-number-handler.ts b/src/message-number-handler.ts index 030ad35..eaf3242 100644 --- a/src/message-number-handler.ts +++ b/src/message-number-handler.ts @@ -1,40 +1,42 @@ -import { BinaryReader } from "google-protobuf" import { Transport } from "." -import { calculateMessageIdentifier, getMessageIdentifier } from "./protocol/helpers" +import { createDecoder, Decoder } from "./encdec/decoding" +import { Encoder, toUint8Array } from "./encdec/encoding" +import { parseMessageIdentifier } from "./protocol/helpers" +import { readRpcMessageHeader } from "./protocol/wire-protocol" let globalMessageNumber = 0 export type SendableMessage = { - setMessageIdentifier(number: number): void - serializeBinary(): Uint8Array - toObject(): any + messageIdentifier: number } export type MessageDispatcher = { transport: Transport - request(data: SendableMessage, messageType: number): Promise - addListener(messageId: number, handler: (reader: BinaryReader) => void): void + request(cb: (bb: Encoder, messageNumber: number) => void): Promise + addListener(messageId: number, handler: (reader: Decoder) => void): void removeListener(messageId: number): void } export function messageNumberHandler(transport: Transport): MessageDispatcher { // message_number -> future - type ReaderCallback = (reader: BinaryReader) => void + type ReaderCallback = (reader: Decoder) => void const oneTimeCallbacks = new Map() - const listeners = new Map void>() + const listeners = new Map void>() transport.on("message", (message) => { - const reader = new BinaryReader(message) - const [_, messageId] = getMessageIdentifier(reader) - if (messageId > 0) { - const fut = oneTimeCallbacks.get(messageId) + const reader = createDecoder(message) + const header = readRpcMessageHeader(reader) + const [_, messageNumber] = parseMessageIdentifier(header.messageIdentifier) + + if (messageNumber > 0) { + const fut = oneTimeCallbacks.get(messageNumber) if (fut) { - reader.reset() + reader.pos = 0 fut(reader) - oneTimeCallbacks.delete(messageId) + oneTimeCallbacks.delete(messageNumber) } - const handler = listeners.get(messageId) + const handler = listeners.get(messageNumber) if (handler) { - reader.reset() + reader.pos = 0 handler(reader) } } @@ -50,13 +52,14 @@ export function messageNumberHandler(transport: Transport): MessageDispatcher { if (!listeners.has(messageId)) throw new Error("A handler is missing for messageId " + messageId) listeners.delete(messageId) }, - async request(data: SendableMessage, messageType: number): Promise { - const messageId = ++globalMessageNumber + async request(cb: (bb: Encoder, messageNumber: number) => void): Promise { + const messageNumber = ++globalMessageNumber if (globalMessageNumber > 0x01000000) globalMessageNumber = 0 - return new Promise((resolve) => { - data.setMessageIdentifier(calculateMessageIdentifier(messageType, messageId)) - oneTimeCallbacks.set(messageId, resolve) - transport.sendMessage(data.serializeBinary()) + return new Promise((resolve) => { + oneTimeCallbacks.set(messageNumber, resolve) + const bb = new Encoder() + cb(bb, messageNumber) + transport.sendMessage(toUint8Array(bb)) }) }, } diff --git a/src/protocol/helpers.ts b/src/protocol/helpers.ts index 218995e..ea6f23b 100644 --- a/src/protocol/helpers.ts +++ b/src/protocol/helpers.ts @@ -1,25 +1,31 @@ -import { BinaryConstants, BinaryReader, Message } from "google-protobuf" +import { Decoder } from "../encdec/decoding" +import { createEncoder, toUint8Array } from "../encdec/encoding" import { - CreatePort, - CreatePortResponse, - DestroyPort, - RemoteError, - Request, - RequestModule, - RequestModuleResponse, - Response, RpcMessageTypes, - StreamMessage, -} from "./index_pb" + readRpcMessageHeader, + readCreatePortResponse, + readResponse, + readRequestModuleResponse, + readStreamMessage, + readRemoteError, + readRequest, + readCreatePort, + readRequestModule, + readDestroyPort, + writeStreamMessage, +} from "./wire-protocol" -export function closeStreamMessage(messageId: number, sequenceId: number, portId: number): Uint8Array { - const m = new StreamMessage() - m.setMessageIdentifier(calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_STREAM_MESSAGE, messageId)) - m.setSequenceId(sequenceId) - m.setPortId(portId) - m.setAck(false) - m.setClosed(true) - return m.serializeBinary() +export function closeStreamMessage(messageNumber: number, sequenceId: number, portId: number): Uint8Array { + const bb = createEncoder() + writeStreamMessage(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.STREAM_MESSAGE, messageNumber), + sequenceId, + portId, + ack: false, + closed: true, + payload: Uint8Array.of(), + }) + return toUint8Array(bb) } export function streamMessage( @@ -28,24 +34,29 @@ export function streamMessage( portId: number, payload: Uint8Array ): Uint8Array { - const m = new StreamMessage() - m.setMessageIdentifier(calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_STREAM_MESSAGE, messageNumber)) - m.setSequenceId(sequenceId) - m.setPortId(portId) - m.setAck(false) - m.setClosed(false) - m.setPayload(payload) - return m.serializeBinary() + const bb = createEncoder() + writeStreamMessage(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.STREAM_MESSAGE, messageNumber), + sequenceId, + portId, + ack: false, + closed: false, + payload, + }) + return toUint8Array(bb) } -export function streamAckMessage(messageId: number, sequenceId: number, portId: number): Uint8Array { - const m = new StreamMessage() - m.setMessageIdentifier(calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_STREAM_ACK, messageId)) - m.setSequenceId(sequenceId) - m.setPortId(portId) - m.setAck(true) - m.setClosed(false) - return m.serializeBinary() +export function streamAckMessage(messageNumber: number, sequenceId: number, portId: number): Uint8Array { + const bb = createEncoder() + writeStreamMessage(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.STREAM_ACK, messageNumber), + sequenceId, + portId, + ack: true, + closed: false, + payload: Uint8Array.of(), + }) + return toUint8Array(bb) } // @internal @@ -58,52 +69,34 @@ export function calculateMessageIdentifier(messageType: number, messageNumber: n return ((messageType & 0xf) << 27) | (messageNumber & 0x07ffffff) } -export function getMessageIdentifier(reader: BinaryReader): [number, number] { - while (reader.nextField()) { - if (reader.isEndGroup()) { - return [0, 0] - } - const field = reader.getFieldNumber() - switch (field) { - case 1 /* message_identifier */: - if (reader.getWireType() != 5) return [0, 0] - const value = /** @type {number} */ reader.readFixed32() - return parseMessageIdentifier(value) - default: - reader.skipField() - break - } - } - return [0, 0] -} - -export function parseProtocolMessage(reader: BinaryReader): [Message, number] | null { - const [messageType, messageNumber] = getMessageIdentifier(reader) - reader.reset() +export function parseProtocolMessage(reader: Decoder): [number, any, number] | null { + const originalPos = reader.pos + const [messageType, messageNumber] = parseMessageIdentifier(readRpcMessageHeader(reader).messageIdentifier) + reader.pos = originalPos switch (messageType) { - case RpcMessageTypes.RPCMESSAGETYPES_CREATE_PORT_RESPONSE: - return [CreatePortResponse.deserializeBinaryFromReader(new CreatePortResponse(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_RESPONSE: - return [Response.deserializeBinaryFromReader(new Response(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_REQUEST_MODULE_RESPONSE: - return [RequestModuleResponse.deserializeBinaryFromReader(new RequestModuleResponse(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_STREAM_MESSAGE: - return [StreamMessage.deserializeBinaryFromReader(new StreamMessage(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_SERVER_READY: + case RpcMessageTypes.CREATE_PORT_RESPONSE: + return [messageType, readCreatePortResponse(reader), messageNumber] + case RpcMessageTypes.RESPONSE: + return [messageType, readResponse(reader), messageNumber] + case RpcMessageTypes.REQUEST_MODULE_RESPONSE: + return [messageType, readRequestModuleResponse(reader), messageNumber] + case RpcMessageTypes.STREAM_MESSAGE: + return [messageType, readStreamMessage(reader), messageNumber] + case RpcMessageTypes.SERVER_READY: return null - case RpcMessageTypes.RPCMESSAGETYPES_REMOTE_ERROR_RESPONSE: - return [RemoteError.deserializeBinaryFromReader(new RemoteError(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_REQUEST: - return [Request.deserializeBinaryFromReader(new Request(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_CREATE_PORT: - return [CreatePort.deserializeBinaryFromReader(new CreatePort(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_STREAM_ACK: - return [StreamMessage.deserializeBinaryFromReader(new StreamMessage(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_REQUEST_MODULE: - return [RequestModule.deserializeBinaryFromReader(new RequestModule(), reader), messageNumber] - case RpcMessageTypes.RPCMESSAGETYPES_DESTROY_PORT: - return [DestroyPort.deserializeBinaryFromReader(new DestroyPort(), reader), messageNumber] + case RpcMessageTypes.REMOTE_ERROR_RESPONSE: + return [messageType, readRemoteError(reader), messageNumber] + case RpcMessageTypes.REQUEST: + return [messageType, readRequest(reader), messageNumber] + case RpcMessageTypes.CREATE_PORT: + return [messageType, readCreatePort(reader), messageNumber] + case RpcMessageTypes.STREAM_ACK: + return [messageType, readStreamMessage(reader), messageNumber] + case RpcMessageTypes.REQUEST_MODULE: + return [messageType, readRequestModule(reader), messageNumber] + case RpcMessageTypes.DESTROY_PORT: + return [messageType, readDestroyPort(reader), messageNumber] } return null diff --git a/src/protocol/wire-protocol.ts b/src/protocol/wire-protocol.ts index a4f13ea..1c69663 100644 --- a/src/protocol/wire-protocol.ts +++ b/src/protocol/wire-protocol.ts @@ -1,43 +1,40 @@ // THIS FILE IS AUTOGENERATED -import ByteBuffer from 'bytebuffer' +import * as e from '../encdec/encoding' +import * as d from '../encdec/decoding' export type fixed32 = number -function _readArray(bb: ByteBuffer, reader: (bb: ByteBuffer) => T): Array { - const len = bb.readUint32(); const ret: T[] = []; - for(let i = 0; i < len; i++) ret.push(reader(bb)); +function _readArray($: d.Decoder, reader: ($: d.Decoder) => T): Array { + const len = d.readUint32($); const ret: T[] = []; + for(let i = 0; i < len; i++) ret.push(reader($)); return ret; } -function _readString(bb: ByteBuffer) { - const len=bb.readUint32(); - return bb.readString(len); +function _readString($: d.Decoder) { + return d.readVarString($); } -function _readBytes(bb: ByteBuffer): Uint8Array { - const len=bb.readUint32(); - return bb.readBytes(len).buffer; +function _readBytes($: d.Decoder): Uint8Array { + return d.readVarUint8Array($); } -function _writeArray(bb: ByteBuffer, writer: (bb: ByteBuffer, value: T) => void, array: T[]) { - bb.writeUint32(array.length); - for(let element of array) writer(bb, element); +function _writeArray($: e.Encoder, writer: ($: e.Encoder, value: T) => void, array: T[]) { + e.writeUint32($, array.length); + for(let element of array) writer($, element); } -function _writeString(bb: ByteBuffer, value: string) { // TODO: check encoding and WTF-16 - bb.writeUint32(value.length); - bb.writeString(value); +function _writeString($: e.Encoder, value: string) { + e.writeVarString($, value); } -function _writeBytes(bb: ByteBuffer, value: Uint8Array) { - bb.writeUint32(value.byteLength); - bb.writeBytes(value); +function _writeBytes($: e.Encoder, value: Uint8Array) { + e.writeVarUint8Array($, value); } export type RpcMessageHeader = { messageIdentifier: fixed32 } -export function writeRpcMessageHeader(bb: ByteBuffer, value: RpcMessageHeader) { - bb.writeInt32(value["messageIdentifier"]); +export function writeRpcMessageHeader($: e.Encoder, value: RpcMessageHeader) { + e.writeUint32($, value["messageIdentifier"]); } -export function readRpcMessageHeader(bb: ByteBuffer): RpcMessageHeader { +export function readRpcMessageHeader($: d.Decoder): RpcMessageHeader { return { - messageIdentifier: bb.readInt32(), + messageIdentifier: d.readUint32($), } } @@ -61,15 +58,15 @@ export type CreatePort = { portName: string } -export function writeCreatePort(bb: ByteBuffer, value: CreatePort) { - bb.writeInt32(value["messageIdentifier"]); - _writeString(bb, value["portName"]); +export function writeCreatePort($: e.Encoder, value: CreatePort) { + e.writeUint32($, value["messageIdentifier"]); + _writeString($, value["portName"]); } -export function readCreatePort(bb: ByteBuffer): CreatePort { +export function readCreatePort($: d.Decoder): CreatePort { return { - messageIdentifier: bb.readInt32(), - portName: _readString(bb), + messageIdentifier: d.readUint32($), + portName: _readString($), } } @@ -78,15 +75,15 @@ export type CreatePortResponse = { portId: fixed32 } -export function writeCreatePortResponse(bb: ByteBuffer, value: CreatePortResponse) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["portId"]); +export function writeCreatePortResponse($: e.Encoder, value: CreatePortResponse) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["portId"]); } -export function readCreatePortResponse(bb: ByteBuffer): CreatePortResponse { +export function readCreatePortResponse($: d.Decoder): CreatePortResponse { return { - messageIdentifier: bb.readInt32(), - portId: bb.readInt32(), + messageIdentifier: d.readUint32($), + portId: d.readUint32($), } } @@ -96,17 +93,17 @@ export type RequestModule = { moduleName: string } -export function writeRequestModule(bb: ByteBuffer, value: RequestModule) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["portId"]); - _writeString(bb, value["moduleName"]); +export function writeRequestModule($: e.Encoder, value: RequestModule) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["portId"]); + _writeString($, value["moduleName"]); } -export function readRequestModule(bb: ByteBuffer): RequestModule { +export function readRequestModule($: d.Decoder): RequestModule { return { - messageIdentifier: bb.readInt32(), - portId: bb.readInt32(), - moduleName: _readString(bb), + messageIdentifier: d.readUint32($), + portId: d.readUint32($), + moduleName: _readString($), } } @@ -116,17 +113,17 @@ export type RequestModuleResponse = { procedures: Array } -export function writeRequestModuleResponse(bb: ByteBuffer, value: RequestModuleResponse) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["portId"]); - _writeArray(bb, (bb, elem) => writeModuleProcedure(bb, elem), value["procedures"]); +export function writeRequestModuleResponse($: e.Encoder, value: RequestModuleResponse) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["portId"]); + _writeArray($, ($, elem) => writeModuleProcedure($, elem), value["procedures"]); } -export function readRequestModuleResponse(bb: ByteBuffer): RequestModuleResponse { +export function readRequestModuleResponse($: d.Decoder): RequestModuleResponse { return { - messageIdentifier: bb.readInt32(), - portId: bb.readInt32(), - procedures: _readArray(bb, (bb) => readModuleProcedure(bb)), + messageIdentifier: d.readUint32($), + portId: d.readUint32($), + procedures: _readArray($, ($) => readModuleProcedure($)), } } @@ -135,15 +132,15 @@ export type DestroyPort = { portId: fixed32 } -export function writeDestroyPort(bb: ByteBuffer, value: DestroyPort) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["portId"]); +export function writeDestroyPort($: e.Encoder, value: DestroyPort) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["portId"]); } -export function readDestroyPort(bb: ByteBuffer): DestroyPort { +export function readDestroyPort($: d.Decoder): DestroyPort { return { - messageIdentifier: bb.readInt32(), - portId: bb.readInt32(), + messageIdentifier: d.readUint32($), + portId: d.readUint32($), } } @@ -152,15 +149,15 @@ export type ModuleProcedure = { procedureName: string } -export function writeModuleProcedure(bb: ByteBuffer, value: ModuleProcedure) { - bb.writeInt32(value["procedureId"]); - _writeString(bb, value["procedureName"]); +export function writeModuleProcedure($: e.Encoder, value: ModuleProcedure) { + e.writeUint32($, value["procedureId"]); + _writeString($, value["procedureName"]); } -export function readModuleProcedure(bb: ByteBuffer): ModuleProcedure { +export function readModuleProcedure($: d.Decoder): ModuleProcedure { return { - procedureId: bb.readInt32(), - procedureName: _readString(bb), + procedureId: d.readUint32($), + procedureName: _readString($), } } @@ -171,19 +168,19 @@ export type Request = { payload: Uint8Array } -export function writeRequest(bb: ByteBuffer, value: Request) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["portId"]); - bb.writeInt32(value["procedureId"]); - _writeBytes(bb, value["payload"]); +export function writeRequest($: e.Encoder, value: Request) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["portId"]); + e.writeUint32($, value["procedureId"]); + _writeBytes($, value["payload"]); } -export function readRequest(bb: ByteBuffer): Request { +export function readRequest($: d.Decoder): Request { return { - messageIdentifier: bb.readInt32(), - portId: bb.readInt32(), - procedureId: bb.readInt32(), - payload: _readBytes(bb), + messageIdentifier: d.readUint32($), + portId: d.readUint32($), + procedureId: d.readUint32($), + payload: _readBytes($), } } @@ -193,17 +190,17 @@ export type RemoteError = { errorMessage: string } -export function writeRemoteError(bb: ByteBuffer, value: RemoteError) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["errorCode"]); - _writeString(bb, value["errorMessage"]); +export function writeRemoteError($: e.Encoder, value: RemoteError) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["errorCode"]); + _writeString($, value["errorMessage"]); } -export function readRemoteError(bb: ByteBuffer): RemoteError { +export function readRemoteError($: d.Decoder): RemoteError { return { - messageIdentifier: bb.readInt32(), - errorCode: bb.readInt32(), - errorMessage: _readString(bb), + messageIdentifier: d.readUint32($), + errorCode: d.readUint32($), + errorMessage: _readString($), } } @@ -212,15 +209,15 @@ export type Response = { payload: Uint8Array } -export function writeResponse(bb: ByteBuffer, value: Response) { - bb.writeInt32(value["messageIdentifier"]); - _writeBytes(bb, value["payload"]); +export function writeResponse($: e.Encoder, value: Response) { + e.writeUint32($, value["messageIdentifier"]); + _writeBytes($, value["payload"]); } -export function readResponse(bb: ByteBuffer): Response { +export function readResponse($: d.Decoder): Response { return { - messageIdentifier: bb.readInt32(), - payload: _readBytes(bb), + messageIdentifier: d.readUint32($), + payload: _readBytes($), } } @@ -233,22 +230,22 @@ export type StreamMessage = { ack: boolean } -export function writeStreamMessage(bb: ByteBuffer, value: StreamMessage) { - bb.writeInt32(value["messageIdentifier"]); - bb.writeInt32(value["portId"]); - bb.writeInt32(value["sequenceId"]); - _writeBytes(bb, value["payload"]); - bb.writeByte(value["closed"] ? 1 : 0); - bb.writeByte(value["ack"] ? 1 : 0); +export function writeStreamMessage($: e.Encoder, value: StreamMessage) { + e.writeUint32($, value["messageIdentifier"]); + e.writeUint32($, value["portId"]); + e.writeUint32($, value["sequenceId"]); + _writeBytes($, value["payload"]); + e.writeUint8($, value["closed"] ? 1 : 0); + e.writeUint8($, value["ack"] ? 1 : 0); } -export function readStreamMessage(bb: ByteBuffer): StreamMessage { +export function readStreamMessage($: d.Decoder): StreamMessage { return { - messageIdentifier: bb.readInt32(), - portId: bb.readInt32(), - sequenceId: bb.readInt32(), - payload: _readBytes(bb), - closed: bb.readByte() != 0, - ack: bb.readByte() != 0, + messageIdentifier: d.readUint32($), + portId: d.readUint32($), + sequenceId: d.readUint32($), + payload: _readBytes($), + closed: d.readUint8($) != 0, + ack: d.readUint8($) != 0, } } diff --git a/src/server.ts b/src/server.ts index 4350b57..0263556 100644 --- a/src/server.ts +++ b/src/server.ts @@ -8,24 +8,27 @@ import { Transport, } from "./types" import mitt from "mitt" +import { AsyncProcedureResultServer, RpcPortEvents, ServerModuleDeclaration } from "." +import { AckDispatcher, createAckHelper } from "./ack-helper" +import { calculateMessageIdentifier, closeStreamMessage, parseProtocolMessage } from "./protocol/helpers" import { CreatePort, - CreatePortResponse, DestroyPort, ModuleProcedure, - RemoteError, Request, RequestModule, - RequestModuleResponse, Response, RpcMessageHeader, RpcMessageTypes, StreamMessage, -} from "./protocol/index_pb" -import { BinaryReader, Message } from "google-protobuf" -import { AsyncProcedureResultServer, RpcPortEvents, ServerModuleDeclaration } from "." -import { AckDispatcher, createAckHelper } from "./ack-helper" -import { calculateMessageIdentifier, closeStreamMessage, parseProtocolMessage } from "./protocol/helpers" + writeCreatePortResponse, + writeRemoteError, + writeRequestModuleResponse, + writeResponse, + writeRpcMessageHeader, +} from "./protocol/wire-protocol" +import { createEncoder, toUint8Array } from "./encdec/encoding" +import { createDecoder } from "./encdec/decoding" let lastPortId = 0 @@ -43,20 +46,15 @@ export type CreateRpcServerOptions = { } function getServerReadyMessage() { - const transportStartMessage = new RpcMessageHeader() - transportStartMessage.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_SERVER_READY, 0) - ) - return transportStartMessage.serializeBinary() + const bb = createEncoder() + writeRpcMessageHeader(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.SERVER_READY, 0), + }) + return toUint8Array(bb) } const transportStartMessageSerialized = getServerReadyMessage() -const reusedCreatePortResponse = new CreatePortResponse() -const reusedRequestModuleResponse = new RequestModuleResponse() -const reusedResponse = new Response() -const reusedRemoteError = new RemoteError() - function moduleProcedures(module: ServerModuleDefinition) { return Array.from(Object.entries(module)).filter(([name, value]) => typeof value == "function") } @@ -161,7 +159,7 @@ export async function handleCreatePort( ) { lastPortId++ - const port = createServerPort(lastPortId, createPortMessage.getPortName()) + const port = createServerPort(lastPortId, createPortMessage.portName) const byTransport = state.portsByTransport.get(transport) || new Map() byTransport.set(port.portId, port) @@ -170,11 +168,12 @@ export async function handleCreatePort( await options.initializePort(port, transport) - reusedCreatePortResponse.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_CREATE_PORT_RESPONSE, messageNumber) - ) - reusedCreatePortResponse.setPortId(port.portId) - transport.sendMessage(reusedCreatePortResponse.serializeBinary()) + const bb = createEncoder() + writeCreatePortResponse(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.CREATE_PORT_RESPONSE, messageNumber), + portId: port.portId, + }) + transport.sendMessage(toUint8Array(bb)) return port } @@ -186,26 +185,21 @@ export async function handleRequestModule( messageNumber: number, state: RpcServerState ) { - const port = getPortFromState(requestModule.getPortId(), transport, state) + const port = getPortFromState(requestModule.portId, transport, state) if (!port) { - throw new Error(`Cannot find port ${requestModule.getPortId()}`) + throw new Error(`Cannot find port ${requestModule.portId}`) } - const loadedModule = await port.loadModule(requestModule.getModuleName()) - - reusedRequestModuleResponse.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_REQUEST_MODULE_RESPONSE, messageNumber) - ) - reusedRequestModuleResponse.setPortId(port.portId) - reusedRequestModuleResponse.setProceduresList([]) - for (const procedure of loadedModule.procedures) { - const n = new ModuleProcedure() - n.setProcedureId(procedure.procedureId) - n.setProcedureName(procedure.procedureName) - reusedRequestModuleResponse.addProcedures(n) - } - transport.sendMessage(reusedRequestModuleResponse.serializeBinary()) + const loadedModule = await port.loadModule(requestModule.moduleName) + + const bb = createEncoder() + writeRequestModuleResponse(bb, { + procedures: loadedModule.procedures, + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REQUEST_MODULE_RESPONSE, messageNumber), + portId: port.portId, + }) + transport.sendMessage(toUint8Array(bb)) } // @internal @@ -215,7 +209,7 @@ export async function handleDestroyPort( _messageNumber: number, state: RpcServerState ) { - const port = getPortFromState(request.getPortId(), transport, state) + const port = getPortFromState(request.portId, transport, state) if (port) { port.emit("close", {}) @@ -229,59 +223,71 @@ export async function handleRequest( messageNumber: number, state: RpcServerState ) { - const port = getPortFromState(request.getPortId(), ackDispatcher.transport, state) + const port = getPortFromState(request.portId, ackDispatcher.transport, state) if (!port) { - reusedRemoteError.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_REMOTE_ERROR_RESPONSE, messageNumber) - ) - reusedRemoteError.setErrorMessage("invalid portId") - ackDispatcher.transport.sendMessage(reusedRemoteError.serializeBinary()) + const bb = createEncoder() + writeRemoteError(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REMOTE_ERROR_RESPONSE, messageNumber), + errorCode: 0, + errorMessage: "invalid portId", + }) + ackDispatcher.transport.sendMessage(toUint8Array(bb)) return } - const result = await port.callProcedure(request.getProcedureId(), request.getPayload_asU8()) - reusedResponse.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_RESPONSE, messageNumber) - ) - reusedResponse.setPayload("") + const result = await port.callProcedure(request.procedureId, request.payload) + const response: Response = { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RESPONSE, messageNumber), + payload: Uint8Array.from([]), + } if (result instanceof Uint8Array) { - reusedResponse.setPayload(result) - ackDispatcher.transport.sendMessage(reusedResponse.serializeBinary()) + response.payload = result + const bb = createEncoder() + writeResponse(bb, response) + ackDispatcher.transport.sendMessage(toUint8Array(bb)) } else if (result && Symbol.asyncIterator in result) { const iter: AsyncGenerator = await (result as any)[Symbol.asyncIterator]() let sequenceNumber = -1 - const reusedStreamMessage = new StreamMessage() - - const transportClosedRejection = new Promise((_, reject) => - ackDispatcher.transport.on("close", reject) - ) + const reusedStreamMessage: StreamMessage = { + closed: false, + ack: false, + sequenceId: 0, + messageIdentifier: 0, + payload: Uint8Array.of(), + portId: request.portId, + } for await (const elem of iter) { sequenceNumber++ - reusedStreamMessage.setClosed(false) - reusedStreamMessage.setAck(false) - reusedStreamMessage.setSequenceId(sequenceNumber) - reusedStreamMessage.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_STREAM_MESSAGE, messageNumber) - ) - reusedStreamMessage.setPayload(elem) - reusedStreamMessage.setPortId(request.getPortId()) + reusedStreamMessage.closed = false + reusedStreamMessage.ack = false + reusedStreamMessage.sequenceId = sequenceNumber + reusedStreamMessage.messageIdentifier = calculateMessageIdentifier(RpcMessageTypes.STREAM_MESSAGE, messageNumber) + reusedStreamMessage.payload = elem + reusedStreamMessage.portId = request.portId // we use Promise.race to react to the transport close events - const ret = await Promise.race([ackDispatcher.sendWithAck(reusedStreamMessage), transportClosedRejection]) - - if (ret.getAck()) { + const ret = await Promise.race([ + ackDispatcher.sendWithAck(reusedStreamMessage), + new Promise((_, reject) => + ackDispatcher.transport.on("close", () => reject(new Error("Transport closed while sending stream"))) + ), + ]) + + if (ret.ack) { continue - } else if (ret.getClosed()) { + } else if (ret.closed) { // if it was closed remotely, then we end the stream right away return } } - ackDispatcher.transport.sendMessage(closeStreamMessage(messageNumber, sequenceNumber, request.getPortId())) + ackDispatcher.transport.sendMessage(closeStreamMessage(messageNumber, sequenceNumber, request.portId)) } else { - ackDispatcher.transport.sendMessage(reusedResponse.serializeBinary()) + const bb = createEncoder() + writeResponse(bb, response) + ackDispatcher.transport.sendMessage(toUint8Array(bb)) } } @@ -320,35 +326,29 @@ export function createRpcServer(options: CreateRpcServerOptions): RpcServer { removeTransport(transport) } - function handleWithErrorMessage(promise: Promise, messageNumber: number, transport: Transport) { - promise.catch((err) => { - reusedRemoteError.setMessageIdentifier( - calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_REMOTE_ERROR_RESPONSE, messageNumber) - ) - reusedRemoteError.setErrorMessage(err.message) - transport.sendMessage(reusedRemoteError.serializeBinary()) - }) - } - async function handleMessage( - parsedMessage: Message, + messageType: number, + parsedMessage: any, messageNumber: number, transport: Transport, ackHelper: AckDispatcher ) { - if (parsedMessage instanceof Request) { + if (messageType == RpcMessageTypes.REQUEST) { await handleRequest(ackHelper, parsedMessage, messageNumber, state) - } else if (parsedMessage instanceof RequestModule) { + } else if (messageType == RpcMessageTypes.REQUEST_MODULE) { await handleRequestModule(transport, parsedMessage, messageNumber, state) - } else if (parsedMessage instanceof CreatePort) { + } else if (messageType == RpcMessageTypes.CREATE_PORT) { const port = await handleCreatePort(transport, parsedMessage, messageNumber, options, state) port.on("close", () => events.emit("portClosed", { port })) - } else if (parsedMessage instanceof DestroyPort) { + } else if (messageType == RpcMessageTypes.DESTROY_PORT) { await handleDestroyPort(transport, parsedMessage, messageNumber, state) - } else if (parsedMessage instanceof StreamMessage) { + } else if (messageType == RpcMessageTypes.STREAM_ACK) { // noop } else { - transport.emit("error", new Error(`Unknown message ${JSON.stringify((parsedMessage as any)?.toObject())}`)) + transport.emit( + "error", + new Error(`Unknown message from client ${JSON.stringify([messageType, parsedMessage, messageNumber])}`) + ) } } @@ -357,16 +357,24 @@ export function createRpcServer(options: CreateRpcServerOptions): RpcServer { attachTransport(newTransport: Transport) { state.transports.add(newTransport) const ackHelper = createAckHelper(newTransport) - newTransport.on("message", (message) => { - const reader = new BinaryReader(message) + newTransport.on("message", async (message) => { + const reader = createDecoder(message) const parsedMessage = parseProtocolMessage(reader) if (parsedMessage) { - const [message, messageNumber] = parsedMessage - handleWithErrorMessage( - handleMessage(message, messageNumber, newTransport, ackHelper), - messageNumber, - newTransport - ) + const [messageType, message, messageNumber] = parsedMessage + try { + await handleMessage(messageType, message, messageNumber, newTransport, ackHelper) + } catch (err: any) { + const bb = createEncoder() + writeRemoteError(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REMOTE_ERROR_RESPONSE, messageNumber), + errorMessage: err.message || "Error processing the request", + errorCode: 0, + }) + newTransport.sendMessage(toUint8Array(bb)) + } + } else { + newTransport.emit("error", new Error(`Unknown message ${message}`)) } }) diff --git a/src/transports/Memory.ts b/src/transports/Memory.ts index 14e5b4e..6ef371b 100644 --- a/src/transports/Memory.ts +++ b/src/transports/Memory.ts @@ -13,7 +13,6 @@ export function MemoryTransport() { }, close() { sender.emit("close", {}) - receiver.emit("close", {}) }, } } @@ -29,6 +28,8 @@ export function MemoryTransport() { } }) + server.on("close", () => client.close()) + return { client, server, diff --git a/test/bench.ts b/test/bench.ts index 0be9546..54e3443 100644 --- a/test/bench.ts +++ b/test/bench.ts @@ -1,3 +1,4 @@ +import { Suite } from "benchmark" import * as helpers from "./helpers" import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client_pb" import { RpcClientPort, RpcServerPort } from "../src" @@ -78,9 +79,7 @@ async function test() { }, }) - await testEnv.start() - - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const clientPort = await rpcClient.createPort("test1") const service = loadBookService(clientPort) @@ -88,23 +87,38 @@ async function test() { const req2 = new QueryBooksRequest() req1.setIsbn(1234) req2.setAuthorPrefix("mr") - let iter = 0 - - while (iter++ < 100000) { - { - const ret = await service.GetBook(req1) - if (ret.getIsbn() != 1234) throw new Error("invalid number") - } - { - const results = [] - for await (const book of service.QueryBooks(req2)) { - results.push(book) - } - - if (results.length != 4) throw new Error("invalid length") - } - } + const suite = new Suite() + + suite + .add("GetBook", { + defer: true, + async fn(deferred) { + const ret = await service.GetBook(req1) + if (ret.getIsbn() != 1234) deferred.reject(new Error("invalid number")) + deferred.resolve() + }, + }) + .add("QueryBooks", { + defer: true, + async fn(deferred) { + const results = [] + + for await (const book of service.QueryBooks(req2)) { + results.push(book) + } + + if (results.length != 4) throw new Error("invalid length") + deferred.resolve() + }, + }) + .on("cycle", function(event) { + console.log(String(event.target)); + }) + .on("complete", function() { + console.log("Fastest is " + this.filter("fastest").map("name")); + }) + .run({ async: true }) } test().catch((err) => { diff --git a/test/close-transport.spec.ts b/test/close-transport.spec.ts index 4d96da5..7fe993e 100644 --- a/test/close-transport.spec.ts +++ b/test/close-transport.spec.ts @@ -1,6 +1,7 @@ import { RpcClient } from "../src" +import { createEncoder, toUint8Array } from "../src/encdec/encoding" import { calculateMessageIdentifier } from "../src/protocol/helpers" -import { RpcMessageHeader, RpcMessageTypes } from "../src/protocol/index_pb" +import { RpcMessageTypes, writeRpcMessageHeader } from "../src/protocol/wire-protocol" import { createSimpleTestEnvironment } from "./helpers" async function testPort(rpcClient: RpcClient, portName: string) { @@ -30,7 +31,7 @@ describe("Close transport closes streams (server side)", () => { }) it("creates the server", async () => { - const { rpcClient, transportServer } = testEnv + const { rpcClient, transportServer } = await testEnv.start() const { infinite } = await testPort(rpcClient, "port1") @@ -50,7 +51,6 @@ describe("Close transport closes streams (server side)", () => { }) }) - describe("Error in transport finalizes streams", () => { let infiniteStreamClosed = false const testEnv = createSimpleTestEnvironment({ @@ -71,7 +71,7 @@ describe("Error in transport finalizes streams", () => { }) it("creates the server", async () => { - const { rpcClient, transportServer } = testEnv + const { rpcClient, transportServer } = await testEnv.start() const { infinite } = await testPort(rpcClient, "port1") @@ -81,7 +81,7 @@ describe("Error in transport finalizes streams", () => { await expect(async () => { for await (const _ of await infinite()) { if (count++ == 10) { - transportServer.emit('error', new Error('SOCKET DISCONNECTED')) + transportServer.emit("error", new Error("SOCKET DISCONNECTED")) } } }).rejects.toThrow("RPC Transport closed") @@ -91,8 +91,6 @@ describe("Error in transport finalizes streams", () => { }) }) - - describe("Close transport closes streams (client side)", () => { let infiniteStreamClosed = false const testEnv = createSimpleTestEnvironment({ @@ -113,7 +111,7 @@ describe("Close transport closes streams (client side)", () => { }) it("creates the server", async () => { - const { rpcClient, transportClient } = testEnv + const { rpcClient, transportClient } = await testEnv.start() const { infinite } = await testPort(rpcClient, "port1") @@ -153,7 +151,7 @@ describe("Error in transport closes the transport", () => { }) it("creates the server", async () => { - const { rpcClient, transportServer } = testEnv + const { rpcClient, transportServer } = await testEnv.start() const { infinite } = await testPort(rpcClient, "port1") @@ -173,7 +171,7 @@ describe("Error in transport closes the transport", () => { }) }) -describe("Unknown packets in the network close the transport", () => { +async function setupForFailures() { const testEnv = createSimpleTestEnvironment({ async initializePort(port) { port.registerModule("echo", async () => ({ @@ -184,31 +182,66 @@ describe("Unknown packets in the network close the transport", () => { }, }) - it("disconnects the transport under unknown messages", async () => { - const { rpcClient, rpcServer, transportServer } = testEnv + const { rpcClient, rpcServer, transportServer } = await testEnv.start() - const { infinite } = await testPort(rpcClient, "port1") + const { infinite } = await testPort(rpcClient, "port1") + + const events: string[] = [] - const events: string[] = [] + function logEvent(evt: string) { + events.push(evt) + process.stderr.write(evt + '\n') + } - transportServer.on("close", () => events.push("transport: close")) - transportServer.on("error", () => events.push("transport: error")) - rpcServer.on("transportClosed", () => events.push("rpc: transportClosed")) - rpcServer.on("transportError", () => events.push("rpc: transportError")) + transportServer.on("close", () => logEvent("transport: close")) + transportServer.on("error", () => logEvent("transport: error")) + rpcServer.on("transportClosed", () => logEvent("rpc: transportClosed")) + rpcServer.on("transportError", () => logEvent("rpc: transportError")) - // make sure everything works - await infinite() + // make sure everything works + await infinite() - expect(events).toEqual([]) + expect(events).toEqual([]) - // sending random things should not break anything - transportServer.emit("message", Uint8Array.from([8, 109])) - expect(events).toEqual([]) + return { events, rpcClient, rpcServer, transportServer, testEnv } +} + +describe("Unknown packets in the network close the transport", () => { + it("disconnects the transport on empty messages", async () => { + const { events, transportServer } = await setupForFailures() + transportServer.emit("message", Uint8Array.of()) + expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) + }) + + it("disconnects the transport under known malformed messages", async () => { + const { events, transportServer } = await setupForFailures() + + // sending invalid packages should raise an error + const bb = createEncoder() + writeRpcMessageHeader(bb, { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.CREATE_PORT_RESPONSE, 0), + }) + transportServer.emit("message", toUint8Array(bb)) + expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) + }) + + it("disconnects the transport under unknown message type", async () => { + const { events, transportServer } = await setupForFailures() // sending invalid packages should raise an error - const badPacket = new RpcMessageHeader() - badPacket.setMessageIdentifier(calculateMessageIdentifier(RpcMessageTypes.RPCMESSAGETYPES_CREATE_PORT_RESPONSE, 0)) - transportServer.emit("message", badPacket.serializeBinary()) + const bb = createEncoder() + writeRpcMessageHeader(bb, { + messageIdentifier: calculateMessageIdentifier(0xfff, 0), + }) + transportServer.emit("message", toUint8Array(bb)) + expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) + }) + + it("disconnects the transport under unknown messages", async () => { + const { events, transportServer } = await setupForFailures() + + // sending random things should not break anything + transportServer.emit("message", Uint8Array.from([8, 109])) expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) }) }) diff --git a/test/codegen-client.spec.ts b/test/codegen-client.spec.ts index 8458b45..62d3cf5 100644 --- a/test/codegen-client.spec.ts +++ b/test/codegen-client.spec.ts @@ -68,7 +68,7 @@ describe("codegen client", () => { let service: BookService it("basic service wraper creation", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const clientPort = await rpcClient.createPort("test1") service = loadBookService(clientPort) diff --git a/test/codegen-server.spec.ts b/test/codegen-server.spec.ts index 34cafed..e837e07 100644 --- a/test/codegen-server.spec.ts +++ b/test/codegen-server.spec.ts @@ -69,7 +69,7 @@ describe("codegen client & server", () => { let service: BookService it("basic service wraper creation", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const clientPort = await rpcClient.createPort("test1") service = loadBookService(clientPort) diff --git a/test/failures.spec.ts b/test/failures.spec.ts index 6a25c91..b05d965 100644 --- a/test/failures.spec.ts +++ b/test/failures.spec.ts @@ -8,30 +8,30 @@ async function testPort(rpcClient: RpcClient, moduleName: string) { } } -describe("Fails creating port", () => { - const testEnv = createSimpleTestEnvironment({ - async initializePort(port) { - port.registerModule("fails", async (port) => { - throw new Error("Access denied") - }) - port.registerModule("works", async (port) => { - return { - async basic() { - return Uint8Array.from([1]) - }, - } - }) - }, - }) +const testEnv = createSimpleTestEnvironment({ + async initializePort(port) { + port.registerModule("fails", async (port) => { + throw new Error("Access denied") + }) + port.registerModule("works", async (port) => { + return { + async basic() { + return Uint8Array.from([1]) + }, + } + }) + }, +}) +describe("Fails creating port", () => { it("fails to create a port", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() await expect(testPort(rpcClient, "fails")).rejects.toThrow("RemoteError: Access denied") }) it("rpcClient still works after failure", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const { basic } = await testPort(rpcClient, "works") expect(await basic()).toEqual(Uint8Array.from([1])) diff --git a/test/helpers.ts b/test/helpers.ts index 033294b..dc20838 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -1,8 +1,9 @@ -import { BinaryReader } from "google-protobuf" import { createRpcClient, createRpcServer, CreateRpcServerOptions, RpcClient } from "../src" import { log } from "./logger" +import { inspect } from "util" import { MemoryTransport } from "../src/transports/Memory" import { parseProtocolMessage } from "../src/protocol/helpers" +import { createDecoder } from "../src/encdec/decoding" // async Array.from(generator*) with support for max elements export async function takeAsync(iter: AsyncGenerator, max?: number) { @@ -22,61 +23,68 @@ export function instrumentTransport(memoryTransport: ReturnType Creating memory transport") function serialize(data: Uint8Array) { - const ret = parseProtocolMessage(new BinaryReader(data)) - if (!ret) return null - return ret[0].toObject() + const ret = parseProtocolMessage(createDecoder(data)) + if (!ret) return inspect(data) + return ret[1] } // only instrument while running tests - if(typeof it == 'function'){ + if (typeof it == "function") { + client.on("close", (data) => { + log(" (client): closed") + }) + client.on("error", (data) => { + log(" (client error): " + data) + }) + client.on("message", (data) => { + try { + log(" (wire server->client): " + JSON.stringify(serialize(data))) + } catch (err) { + console.error(err) + } + }) - client.on("message", (data) => { - try { - log(" (wire server->client): " + JSON.stringify(serialize(data))) - } catch (err) { - console.error(err) - } - }) - - - server.on("message", (data) => { - try { - log(" (wire client->server): " + JSON.stringify(serialize(data))) - } catch (err) { - console.error(err) - } - }) -} + server.on("close", (data) => { + log(" (server): closed") + }) + server.on("error", (data) => { + log(" (server error): " + data) + }) + server.on("message", (data) => { + try { + log(" (wire client->server): " + JSON.stringify(serialize(data))) + } catch (err) { + console.error(err) + } + }) + } return memoryTransport } export function createSimpleTestEnvironment(options: CreateRpcServerOptions) { - const memoryTransport = MemoryTransport() - let rpcClient: RpcClient - instrumentTransport(memoryTransport) + async function start() { + const memoryTransport = MemoryTransport() + let rpcClient: RpcClient + instrumentTransport(memoryTransport) - const rpcServer = createRpcServer(options) + const rpcServer = createRpcServer(options) - async function start() { + let clientClosed = false + let serverClosed = false + memoryTransport.client.on("close", () => (clientClosed = true)) + memoryTransport.server.on("close", () => (serverClosed = true)) + + if (serverClosed) throw new Error("This server is already closed. Use a new testing environment") log("> Creating RPC Client") setImmediate(() => rpcServer.attachTransport(memoryTransport.server)) rpcClient = await createRpcClient(memoryTransport.client) - } + clientClosed = false - if (typeof beforeAll !== "undefined") beforeAll(start) + return { rpcClient, rpcServer, transportClient: memoryTransport.client, transportServer: memoryTransport.server } + } return { start, - get rpcServer() { - if (!rpcServer) throw new Error("Must se the rpcServer only inside a `it`") - return rpcServer - }, - get rpcClient() { - if (!rpcClient) throw new Error("Must se the rpcClient only inside a `it`") - return rpcClient - }, - transportClient: memoryTransport.client, - transportServer: memoryTransport.server, } } diff --git a/test/reuse-ports.spec.ts b/test/reuse-ports.spec.ts index e291880..5c0cb54 100644 --- a/test/reuse-ports.spec.ts +++ b/test/reuse-ports.spec.ts @@ -15,19 +15,19 @@ async function testPort(rpcClient: RpcClient, portName: string) { return port } -describe("Helpers simple req/res", () => { - const testEnv = createSimpleTestEnvironment({ - async initializePort(port) { - port.registerModule("echo", async (port) => ({ - async getPortId() { - return Uint8Array.from([port.portId % 0xff]) - }, - })) - }, - }) +const testEnv = createSimpleTestEnvironment({ + async initializePort(port) { + port.registerModule("echo", async (port) => ({ + async getPortId() { + return Uint8Array.from([port.portId % 0xff]) + }, + })) + }, +}) +describe("Helpers simple req/res", () => { it("creates the server", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port1 = await testPort(rpcClient, "port1") const port2 = await testPort(rpcClient, "port2") @@ -41,18 +41,8 @@ describe("Helpers simple req/res", () => { }) describe("Close ports", () => { - const testEnv = createSimpleTestEnvironment({ - async initializePort(port) { - port.registerModule("echo", async (port) => ({ - async getPortId() { - return Uint8Array.from([port.portId % 0xff]) - }, - })) - }, - }) - it("When reusing open ports it returns the same ports", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port1 = await testPort(rpcClient, "port") const port2 = await testPort(rpcClient, "port") diff --git a/test/sanity.spec.ts b/test/sanity.spec.ts index 55515f1..634ff91 100644 --- a/test/sanity.spec.ts +++ b/test/sanity.spec.ts @@ -52,7 +52,7 @@ describe("Helpers simple req/res", () => { }) it("creates the server", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port1 = await testPort(rpcClient, "port1") const port2 = await testPort(rpcClient, "port2") diff --git a/test/stream-from-dispatcher.spec.ts b/test/stream-from-dispatcher.spec.ts index 41c6349..08cd7be 100644 --- a/test/stream-from-dispatcher.spec.ts +++ b/test/stream-from-dispatcher.spec.ts @@ -1,7 +1,8 @@ import { streamFromDispatcher } from "../src/client" +import { createDecoder } from "../src/encdec/decoding" import { messageNumberHandler } from "../src/message-number-handler" import { closeStreamMessage, streamMessage } from "../src/protocol/helpers" -import { StreamMessage } from "../src/protocol/index_pb" +import { readStreamMessage } from "../src/protocol/wire-protocol" import { MemoryTransport } from "../src/transports/Memory" import { instrumentTransport, takeAsync } from "./helpers" @@ -14,7 +15,7 @@ describe("streamFromDispatcher", () => { const removeListenerSpy = jest.spyOn(dispatcher, "removeListener") const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array())), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array()))), MESSAGE_NUMBER ) @@ -35,7 +36,7 @@ describe("streamFromDispatcher", () => { const addListenerSpy = jest.spyOn(dispatcher, "addListener") const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array())), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array()))), MESSAGE_NUMBER ) @@ -57,7 +58,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array())), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array()))), MESSAGE_NUMBER ) @@ -77,7 +78,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, 0, 0, PAYLOAD)), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, 0, 0, PAYLOAD))), MESSAGE_NUMBER ) @@ -97,7 +98,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD)), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD))), MESSAGE_NUMBER ) @@ -115,7 +116,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD)), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD))), MESSAGE_NUMBER ) transport.server.sendMessage(closeStreamMessage(MESSAGE_NUMBER, seq++, 0)) @@ -130,7 +131,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1]))), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1])))), MESSAGE_NUMBER ) @@ -152,7 +153,7 @@ describe("streamFromDispatcher", () => { const removeListenerSpy = jest.spyOn(dispatcher, "removeListener") const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1]))), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1])))), MESSAGE_NUMBER ) @@ -179,7 +180,7 @@ describe("streamFromDispatcher", () => { const removeListenerSpy = jest.spyOn(dispatcher, "removeListener") const stream = streamFromDispatcher( dispatcher, - StreamMessage.deserializeBinary(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1]))), + readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1])))), MESSAGE_NUMBER ) diff --git a/test/stream.spec.ts b/test/stream.spec.ts index 1c73892..8d4511c 100644 --- a/test/stream.spec.ts +++ b/test/stream.spec.ts @@ -69,7 +69,7 @@ describe("Helpers simple req/res", () => { }) it("basic iteration", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port = await rpcClient.createPort("test1") const module = (await port.loadModule("echo")) as { basic(): Promise> @@ -82,7 +82,7 @@ describe("Helpers simple req/res", () => { }) it("fails in async generator before yielding, the async iterator in our end throws", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port = await rpcClient.createPort("test1") const module = (await port.loadModule("echo")) as { throwFirst(): Promise> @@ -99,7 +99,7 @@ describe("Helpers simple req/res", () => { }) it("yields one result and then throws. must end the stream with exception and the first result must arrive correctly", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port = await rpcClient.createPort("test1") const module = (await port.loadModule("echo")) as { throwSecond(): Promise> @@ -116,7 +116,7 @@ describe("Helpers simple req/res", () => { }) it("a remote infiniteCounter is stopped via exception from client side on third iteration", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port = await rpcClient.createPort("test1") const module = (await port.loadModule("echo")) as { infiniteCounter(): Promise> @@ -140,7 +140,7 @@ describe("Helpers simple req/res", () => { }) it("a remote infiniteCounter is gracefully stopped from client side on third iteration", async () => { - const { rpcClient } = testEnv + const { rpcClient } = await testEnv.start() const port = await rpcClient.createPort("test1") const module = (await port.loadModule("echo")) as { infiniteCounter(): Promise> From a6fa7c768cd6976be89adba5e4ac7244444a0910 Mon Sep 17 00:00:00 2001 From: menduz Date: Sun, 6 Feb 2022 15:54:53 -0300 Subject: [PATCH 03/11] pbjs is faster than vanilla serialization --- Makefile | 2 + package-lock.json | 188 +- package.json | 3 +- scripts/generate-proto-file.ts | 2 +- src/ack-helper.ts | 38 +- src/client.ts | 82 +- src/encdec/binary.ts | 90 - src/encdec/buffer.ts | 65 - src/encdec/decoding.ts | 668 ------- src/encdec/encoding.ts | 845 --------- src/encdec/math.ts | 60 - src/encdec/number.ts | 29 - src/encdec/string.ts | 129 -- src/message-number-handler.ts | 25 +- src/protocol/helpers.ts | 141 +- src/protocol/pbjs.d.ts | 993 +++++++++++ src/protocol/pbjs.js | 2580 +++++++++++++++++++++++++++ src/protocol/wire-protocol.ts | 251 --- src/server.ts | 180 +- src/transports/Memory.ts | 7 +- test/close-transport.spec.ts | 47 +- test/helpers.ts | 9 +- test/stream-from-dispatcher.spec.ts | 22 +- 23 files changed, 4070 insertions(+), 2386 deletions(-) delete mode 100644 src/encdec/binary.ts delete mode 100644 src/encdec/buffer.ts delete mode 100644 src/encdec/decoding.ts delete mode 100644 src/encdec/encoding.ts delete mode 100644 src/encdec/math.ts delete mode 100644 src/encdec/number.ts delete mode 100644 src/encdec/string.ts create mode 100644 src/protocol/pbjs.d.ts create mode 100644 src/protocol/pbjs.js delete mode 100644 src/protocol/wire-protocol.ts diff --git a/Makefile b/Makefile index b8b712e..8be9200 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,8 @@ test-watch: build: node_modules/.bin/ts-node scripts/generate-proto-file.ts + node_modules/.bin/pbjs -t static-module -w commonjs -o src/protocol/pbjs.js src/protocol/index.proto + node_modules/.bin/pbts -o src/protocol/pbjs.d.ts src/protocol/pbjs.js @rm -rf dist || true @mkdir -p dist ${PROTOC} "--js_out=binary,import_style=commonjs_strict:$(PWD)/src/protocol" \ diff --git a/package-lock.json b/package-lock.json index fed566d..7a8dc7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "camelcase": "^6.3.0", "google-protobuf": "^3.19.1", "mitt": "^3.0.0", - "pascalcase": "^2.0.0" + "pascalcase": "^2.0.0", + "protobufjs": "^6.11.2" }, "devDependencies": { "@microsoft/api-extractor": "^7.17.0", @@ -964,6 +965,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "node_modules/@rushstack/node-core-library": { "version": "3.44.2", "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.44.2.tgz", @@ -1149,6 +1204,11 @@ "pretty-format": "^27.0.0" } }, + "node_modules/@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "node_modules/@types/node": { "version": "12.20.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", @@ -3276,6 +3336,11 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -3671,6 +3736,36 @@ "node": ">= 6" } }, + "node_modules/protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/protobufjs/node_modules/@types/node": { + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", + "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" + }, "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -5274,6 +5369,60 @@ } } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, "@rushstack/node-core-library": { "version": "3.44.2", "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.44.2.tgz", @@ -5456,6 +5605,11 @@ "pretty-format": "^27.0.0" } }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, "@types/node": { "version": "12.20.24", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz", @@ -7103,6 +7257,11 @@ "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7409,6 +7568,33 @@ "sisteransi": "^1.0.5" } }, + "protobufjs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", + "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "17.0.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", + "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" + } + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", diff --git a/package.json b/package.json index 5daf4bd..271a5a8 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "camelcase": "^6.3.0", "google-protobuf": "^3.19.1", "mitt": "^3.0.0", - "pascalcase": "^2.0.0" + "pascalcase": "^2.0.0", + "protobufjs": "^6.11.2" } } diff --git a/scripts/generate-proto-file.ts b/scripts/generate-proto-file.ts index 45599f5..72b6332 100644 --- a/scripts/generate-proto-file.ts +++ b/scripts/generate-proto-file.ts @@ -157,4 +157,4 @@ proto.addMessage( ) writeFileSync("src/protocol/index.proto", generateProtoFile(proto.validate())) -writeFileSync("src/protocol/wire-protocol.ts", generateTsProtocol(proto.validate())) +// writeFileSync("src/protocol/wire-protocol.ts", generateTsProtocol(proto.validate())) diff --git a/src/ack-helper.ts b/src/ack-helper.ts index e84a734..e809fba 100644 --- a/src/ack-helper.ts +++ b/src/ack-helper.ts @@ -1,49 +1,35 @@ +import { Writer } from "protobufjs" import { Transport } from "./types" import { parseMessageIdentifier } from "./protocol/helpers" -import { - readRpcMessageHeader, - readStreamMessage, - RpcMessageTypes, - StreamMessage, - writeStreamMessage, -} from "./protocol/wire-protocol" -import { createEncoder, toUint8Array } from "./encdec/encoding" -import { createDecoder } from "./encdec/decoding" +import { StreamMessage } from "./protocol/pbjs" export type AckDispatcher = { - transport: Transport sendWithAck(data: StreamMessage): Promise + receiveAck(data: StreamMessage, messageNumber: number): void } export function createAckHelper(transport: Transport): AckDispatcher { const oneTimeCallbacks = new Map void>() - transport.on("message", (message) => { - const reader = createDecoder(message) - const header = readRpcMessageHeader(reader) - reader.pos = 0 - const [messageType, messageNumber] = parseMessageIdentifier(header.messageIdentifier) - if (messageType == RpcMessageTypes.STREAM_ACK) { - reader.pos = 0 - const data = readStreamMessage(reader) + const bb = new Writer() + + return { + receiveAck(data: StreamMessage, messageNumber: number) { const key = `${messageNumber},${data.sequenceId}` const fut = oneTimeCallbacks.get(key) if (fut) { fut(data) oneTimeCallbacks.delete(key) } - } - }) - - return { - transport, + }, async sendWithAck(data: StreamMessage): Promise { return new Promise((ret) => { const [_, messageNumber] = parseMessageIdentifier(data.messageIdentifier) oneTimeCallbacks.set(`${messageNumber},${data.sequenceId}`, ret) - const bb = createEncoder() - writeStreamMessage(bb, data) - transport.sendMessage(toUint8Array(bb)) + + bb.reset() + StreamMessage.encode(data, bb) + transport.sendMessage(bb.finish()) }) }, } diff --git a/src/client.ts b/src/client.ts index 7b2cec0..5fbde1b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,19 +1,19 @@ import { CallableProcedureClient, ClientModuleDefinition, RpcClient, RpcClientPort, RpcPortEvents } from "." import { Transport } from "./types" import mitt from "mitt" +import { Writer } from "protobufjs" import { + CreatePort, CreatePortResponse, + DestroyPort, RemoteError, Request, + RequestModule, RequestModuleResponse, Response, RpcMessageTypes, StreamMessage, - writeCreatePort, - writeDestroyPort, - writeRequest, - writeRequestModule, -} from "./protocol/wire-protocol" +} from "./protocol/pbjs" import { MessageDispatcher, messageNumberHandler } from "./message-number-handler" import { pushableChannel } from "./push-channel" import { @@ -22,8 +22,6 @@ import { parseProtocolMessage, streamAckMessage, } from "./protocol/helpers" -import { BinaryWriter } from "google-protobuf" -import { createEncoder, toUint8Array } from "./encdec/encoding" const EMPTY_U8 = new Uint8Array(0) @@ -42,27 +40,35 @@ export function createPort(portId: number, portName: string, dispatcher: Message return state }, close() { - const bb = createEncoder() - writeDestroyPort(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.DESTROY_PORT, 0), - portId, - }) - - dispatcher.transport.sendMessage(toUint8Array(bb)) + const bb = new Writer() + DestroyPort.encode( + { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_DESTROY_PORT, 0), + portId, + }, + bb + ) + dispatcher.transport.sendMessage(bb.finish()) events.emit("close", {}) }, async loadModule(moduleName: string) { const ret = await dispatcher.request((bb, messageNumber) => { - writeRequestModule(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REQUEST_MODULE, messageNumber), - moduleName, - portId, - }) + RequestModule.encode( + { + messageIdentifier: calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE, + messageNumber + ), + moduleName, + portId, + }, + bb + ) }) const parsedMessage = parseProtocolMessage(ret) if (parsedMessage) { const [messageType, message] = parsedMessage - if (messageType == RpcMessageTypes.REQUEST_MODULE_RESPONSE) { + if (messageType == RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE) { const ret: ClientModuleDefinition = {} for (let procedure of (message as RequestModuleResponse).procedures) { @@ -70,7 +76,7 @@ export function createPort(portId: number, portName: string, dispatcher: Message } return ret - } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE) { throwIfRemoteError(message) } } @@ -139,9 +145,9 @@ export function streamFromDispatcher( if (ret) { const [messageType, message, messageNumber] = ret - if (messageType == RpcMessageTypes.STREAM_MESSAGE) { + if (messageType == RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE) { processMessage(message, messageNumber) - } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE) { isRemoteClosed = true channel.failAndClose( new Error("RemoteError: " + ((message as RemoteError).errorMessage || "Unknown remote error")) @@ -161,7 +167,7 @@ export function streamFromDispatcher( // @internal function createProcedure(portId: number, procedureId: number, dispatcher: MessageDispatcher): CallableProcedureClient { - const callProcedurePacket: Request = { + const callProcedurePacket = { portId, messageIdentifier: 0, payload: EMPTY_U8, @@ -176,23 +182,26 @@ function createProcedure(portId: number, procedureId: number, dispatcher: Messag } const ret = parseProtocolMessage( await dispatcher.request((bb, messageNumber) => { - callProcedurePacket.messageIdentifier = calculateMessageIdentifier(RpcMessageTypes.REQUEST, messageNumber) - writeRequest(bb, callProcedurePacket) + callProcedurePacket.messageIdentifier = calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_REQUEST, + messageNumber + ) + Request.encode(callProcedurePacket, bb) }) ) if (ret) { const [messageType, message, messageNumber] = ret - if (messageType == RpcMessageTypes.RESPONSE) { + if (messageType == RpcMessageTypes.RpcMessageTypes_RESPONSE) { const u8 = (message as Response).payload if (u8.length) { return u8 } else { return undefined } - } else if (messageType == RpcMessageTypes.STREAM_MESSAGE) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE) { return streamFromDispatcher(dispatcher, message, messageNumber) - } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE) { throwIfRemoteError(message) debugger } @@ -210,10 +219,13 @@ export async function createRpcClient(transport: Transport): Promise async function internalCreatePort(portName: string): Promise { const ret = await dispatcher.request((bb, messageNumber) => { - writeCreatePort(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.CREATE_PORT, messageNumber), - portName, - }) + CreatePort.encode( + { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_CREATE_PORT, messageNumber), + portName, + }, + bb + ) }) const parsedMessage = parseProtocolMessage(ret) @@ -221,10 +233,10 @@ export async function createRpcClient(transport: Transport): Promise if (parsedMessage) { const [messageType, message] = parsedMessage - if (messageType == RpcMessageTypes.CREATE_PORT_RESPONSE) { + if (messageType == RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE) { const portId = (message as CreatePortResponse).portId return createPort(portId, portName, dispatcher) - } else if (messageType == RpcMessageTypes.REMOTE_ERROR_RESPONSE) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE) { throwIfRemoteError(message) } } diff --git a/src/encdec/binary.ts b/src/encdec/binary.ts deleted file mode 100644 index 80880bb..0000000 --- a/src/encdec/binary.ts +++ /dev/null @@ -1,90 +0,0 @@ -// https://github.com/dmonad/lib0 - -/** - * Binary data constants. - * - * @module binary - */ - -/** - * n-th bit activated. - * - * @type {number} - */ -export const BIT1 = 1 -export const BIT2 = 2 -export const BIT3 = 4 -export const BIT4 = 8 -export const BIT5 = 16 -export const BIT6 = 32 -export const BIT7 = 64 -export const BIT8 = 128 -export const BIT9 = 256 -export const BIT10 = 512 -export const BIT11 = 1024 -export const BIT12 = 2048 -export const BIT13 = 4096 -export const BIT14 = 8192 -export const BIT15 = 16384 -export const BIT16 = 32768 -export const BIT17 = 65536 -export const BIT18 = 1 << 17 -export const BIT19 = 1 << 18 -export const BIT20 = 1 << 19 -export const BIT21 = 1 << 20 -export const BIT22 = 1 << 21 -export const BIT23 = 1 << 22 -export const BIT24 = 1 << 23 -export const BIT25 = 1 << 24 -export const BIT26 = 1 << 25 -export const BIT27 = 1 << 26 -export const BIT28 = 1 << 27 -export const BIT29 = 1 << 28 -export const BIT30 = 1 << 29 -export const BIT31 = 1 << 30 -export const BIT32 = 1 << 31 - -/** - * First n bits activated. - * - * @type {number} - */ -export const BITS0 = 0 -export const BITS1 = 1 -export const BITS2 = 3 -export const BITS3 = 7 -export const BITS4 = 15 -export const BITS5 = 31 -export const BITS6 = 63 -export const BITS7 = 127 -export const BITS8 = 255 -export const BITS9 = 511 -export const BITS10 = 1023 -export const BITS11 = 2047 -export const BITS12 = 4095 -export const BITS13 = 8191 -export const BITS14 = 16383 -export const BITS15 = 32767 -export const BITS16 = 65535 -export const BITS17 = BIT18 - 1 -export const BITS18 = BIT19 - 1 -export const BITS19 = BIT20 - 1 -export const BITS20 = BIT21 - 1 -export const BITS21 = BIT22 - 1 -export const BITS22 = BIT23 - 1 -export const BITS23 = BIT24 - 1 -export const BITS24 = BIT25 - 1 -export const BITS25 = BIT26 - 1 -export const BITS26 = BIT27 - 1 -export const BITS27 = BIT28 - 1 -export const BITS28 = BIT29 - 1 -export const BITS29 = BIT30 - 1 -export const BITS30 = BIT31 - 1 -/** - * @type {number} - */ -export const BITS31 = 0x7fffffff -/** - * @type {number} - */ -export const BITS32 = 0xffffffff diff --git a/src/encdec/buffer.ts b/src/encdec/buffer.ts deleted file mode 100644 index cb08247..0000000 --- a/src/encdec/buffer.ts +++ /dev/null @@ -1,65 +0,0 @@ -// https://github.com/dmonad/lib0 - -/** - * Utility functions to work with buffers (Uint8Array). - * - * @module buffer - */ - -import * as encoding from "./encoding" -import * as decoding from "./decoding" - -/** - * @param {number} len - */ -export const createUint8ArrayFromLen = (len: number) => new Uint8Array(len) - -/** - * Create Uint8Array with initial content from buffer - * - * @param {ArrayBuffer} buffer - * @param {number} byteOffset - * @param {number} length - */ -export const createUint8ArrayViewFromArrayBuffer = (buffer: ArrayBuffer, byteOffset: number, length: number) => - new Uint8Array(buffer, byteOffset, length) - -/** - * Create Uint8Array with initial content from buffer - * - * @param {ArrayBuffer} buffer - */ -export const createUint8ArrayFromArrayBuffer = (buffer: ArrayBuffer) => new Uint8Array(buffer) - -/** - * Copy the content of an Uint8Array view to a new ArrayBuffer. - * - * @param {Uint8Array} uint8Array - * @return {Uint8Array} - */ -export const copyUint8Array = (uint8Array: Uint8Array): Uint8Array => { - const newBuf = createUint8ArrayFromLen(uint8Array.byteLength) - newBuf.set(uint8Array) - return newBuf -} - -/** - * Encode anything as a UInt8Array. It's a pun on typescripts's `any` type. - * See encoding.writeAny for more information. - * - * @param {any} data - * @return {Uint8Array} - */ -export const encodeAny = (data: any): Uint8Array => { - const encoder = encoding.createEncoder() - encoding.writeAny(encoder, data) - return encoding.toUint8Array(encoder) -} - -/** - * Decode an any-encoded value. - * - * @param {Uint8Array} buf - * @return {any} - */ -export const decodeAny = (buf: Uint8Array): any => decoding.readAny(decoding.createDecoder(buf)) diff --git a/src/encdec/decoding.ts b/src/encdec/decoding.ts deleted file mode 100644 index e5e8d8b..0000000 --- a/src/encdec/decoding.ts +++ /dev/null @@ -1,668 +0,0 @@ -// https://github.com/dmonad/lib0 - -/** - * Efficient schema-less binary decoding with support for variable length encoding. - * - * Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function. - * - * Encodes numbers in little-endian order (least to most significant byte order) - * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/) - * which is also used in Protocol Buffers. - * - * ```js - * // encoding step - * const encoder = new encoding.createEncoder() - * encoding.writeVarUint(encoder, 256) - * encoding.writeVarString(encoder, 'Hello world!') - * const buf = encoding.toUint8Array(encoder) - * ``` - * - * ```js - * // decoding step - * const decoder = new decoding.createDecoder(buf) - * decoding.readVarUint(decoder) // => 256 - * decoding.readVarString(decoder) // => 'Hello world!' - * decoding.hasContent(decoder) // => false - all data is read - * ``` - * - * @module decoding - */ - -import * as buffer from "./buffer" -import * as binary from "./binary" -import * as math from "./math" - -/** - * A Decoder handles the decoding of an Uint8Array. - */ -export class Decoder { - arr: Uint8Array - pos: number - /** - * @param {Uint8Array} uint8Array Binary data to decode - */ - constructor(uint8Array: Uint8Array) { - /** - * Decoding target. - * - * @type {Uint8Array} - */ - this.arr = uint8Array - /** - * Current decoding position. - * - * @type {number} - */ - this.pos = 0 - } -} - -/** - * @function - * @param {Uint8Array} uint8Array - * @return {Decoder} - */ -export const createDecoder = (uint8Array: Uint8Array): Decoder => new Decoder(uint8Array) - -/** - * @function - * @param {Decoder} decoder - * @return {boolean} - */ -export const hasContent = (decoder: Decoder): boolean => decoder.pos !== decoder.arr.length - -/** - * Clone a decoder instance. - * Optionally set a new position parameter. - * - * @function - * @param {Decoder} decoder The decoder instance - * @param {number} [newPos] Defaults to current position - * @return {Decoder} A clone of `decoder` - */ -export const clone = (decoder: Decoder, newPos: number = decoder.pos): Decoder => { - const _decoder = createDecoder(decoder.arr) - _decoder.pos = newPos - return _decoder -} - -/** - * Create an Uint8Array view of the next `len` bytes and advance the position by `len`. - * - * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks. - * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array. - * - * @function - * @param {Decoder} decoder The decoder instance - * @param {number} len The length of bytes to read - * @return {Uint8Array} - */ -export const readUint8Array = (decoder: Decoder, len: number): Uint8Array => { - const view = buffer.createUint8ArrayViewFromArrayBuffer(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len) - decoder.pos += len - return view -} - -/** - * Read variable length Uint8Array. - * - * Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks. - * Use `buffer.copyUint8Array` to copy the result into a new Uint8Array. - * - * @function - * @param {Decoder} decoder - * @return {Uint8Array} - */ -export const readVarUint8Array = (decoder: Decoder): Uint8Array => readUint8Array(decoder, readVarUint(decoder)) - -/** - * Read the rest of the content as an ArrayBuffer - * @function - * @param {Decoder} decoder - * @return {Uint8Array} - */ -export const readTailAsUint8Array = (decoder: Decoder): Uint8Array => - readUint8Array(decoder, decoder.arr.length - decoder.pos) - -/** - * Skip one byte, jump to the next position. - * @function - * @param {Decoder} decoder The decoder instance - * @return {number} The next position - */ -export const skip8 = (decoder: Decoder): number => decoder.pos++ - -/** - * Read one byte as unsigned integer. - * @function - * @param {Decoder} decoder The decoder instance - * @return {number} Unsigned 8-bit integer - */ -export const readUint8 = (decoder: Decoder): number => decoder.arr[decoder.pos++] - -/** - * Read 2 bytes as unsigned integer. - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer. - */ -export const readUint16 = (decoder: Decoder): number => { - const uint = decoder.arr[decoder.pos] + (decoder.arr[decoder.pos + 1] << 8) - decoder.pos += 2 - return uint -} - -/** - * Read 4 bytes as unsigned integer. - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer. - */ -export const readUint32 = (decoder: Decoder): number => { - const uint = - (decoder.arr[decoder.pos] + - (decoder.arr[decoder.pos + 1] << 8) + - (decoder.arr[decoder.pos + 2] << 16) + - (decoder.arr[decoder.pos + 3] << 24)) >>> - 0 - decoder.pos += 4 - return uint -} - -/** - * Read 4 bytes as unsigned integer in big endian order. - * (most significant byte first) - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer. - */ -export const readUint32BigEndian = (decoder: Decoder): number => { - const uint = - (decoder.arr[decoder.pos + 3] + - (decoder.arr[decoder.pos + 2] << 8) + - (decoder.arr[decoder.pos + 1] << 16) + - (decoder.arr[decoder.pos] << 24)) >>> - 0 - decoder.pos += 4 - return uint -} - -/** - * Look ahead without incrementing the position - * to the next byte and read it as unsigned integer. - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer. - */ -export const peekUint8 = (decoder: Decoder): number => decoder.arr[decoder.pos] - -/** - * Look ahead without incrementing the position - * to the next byte and read it as unsigned integer. - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer. - */ -export const peekUint16 = (decoder: Decoder): number => decoder.arr[decoder.pos] + (decoder.arr[decoder.pos + 1] << 8) - -/** - * Look ahead without incrementing the position - * to the next byte and read it as unsigned integer. - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer. - */ -export const peekUint32 = (decoder: Decoder): number => - (decoder.arr[decoder.pos] + - (decoder.arr[decoder.pos + 1] << 8) + - (decoder.arr[decoder.pos + 2] << 16) + - (decoder.arr[decoder.pos + 3] << 24)) >>> - 0 - -/** - * Read unsigned integer (32bit) with variable length. - * 1/8th of the storage is used as encoding overhead. - * * numbers < 2^7 is stored in one bytlength - * * numbers < 2^14 is stored in two bylength - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer.length - */ -export const readVarUint = (decoder: Decoder): number => { - let num = 0 - let len = 0 - while (true) { - const r = decoder.arr[decoder.pos++] - num = num | ((r & binary.BITS7) << len) - len += 7 - if (r < binary.BIT8) { - return num >>> 0 // return unsigned number! - } - /* istanbul ignore if */ - if (len > 35) { - throw new Error("Integer out of range!") - } - } -} - -/** - * Read signed integer (32bit) with variable length. - * 1/8th of the storage is used as encoding overhead. - * * numbers < 2^7 is stored in one bytlength - * * numbers < 2^14 is stored in two bylength - * @todo This should probably create the inverse ~num if number is negative - but this would be a breaking change. - * - * @function - * @param {Decoder} decoder - * @return {number} An unsigned integer.length - */ -export const readVarInt = (decoder: Decoder): number => { - let r = decoder.arr[decoder.pos++] - let num = r & binary.BITS6 - let len = 6 - const sign = (r & binary.BIT7) > 0 ? -1 : 1 - if ((r & binary.BIT8) === 0) { - // don't continue reading - return sign * num - } - while (true) { - r = decoder.arr[decoder.pos++] - num = num | ((r & binary.BITS7) << len) - len += 7 - if (r < binary.BIT8) { - return sign * (num >>> 0) - } - /* istanbul ignore if */ - if (len > 41) { - throw new Error("Integer out of range!") - } - } -} - -/** - * Look ahead and read varUint without incrementing position - * - * @function - * @param {Decoder} decoder - * @return {number} - */ -export const peekVarUint = (decoder: Decoder): number => { - const pos = decoder.pos - const s = readVarUint(decoder) - decoder.pos = pos - return s -} - -/** - * Look ahead and read varUint without incrementing position - * - * @function - * @param {Decoder} decoder - * @return {number} - */ -export const peekVarInt = (decoder: Decoder): number => { - const pos = decoder.pos - const s = readVarInt(decoder) - decoder.pos = pos - return s -} - -/** - * Read string of variable length - * * varUint is used to store the length of the string - * - * Transforming utf8 to a string is pretty expensive. The code performs 10x better - * when String.fromCodePoint is fed with all characters as arguments. - * But most environments have a maximum number of arguments per functions. - * For effiency reasons we apply a maximum of 10000 characters at once. - * - * @function - * @param {Decoder} decoder - * @return {String} The read String. - */ -export const readVarString = (decoder: Decoder): string => { - let remainingLen = readVarUint(decoder) - if (remainingLen === 0) { - return "" - } else { - let encodedString = String.fromCodePoint(readUint8(decoder)) // remember to decrease remainingLen - if (--remainingLen < 100) { - // do not create a Uint8Array for small strings - while (remainingLen--) { - encodedString += String.fromCodePoint(readUint8(decoder)) - } - } else { - while (remainingLen > 0) { - const nextLen = remainingLen < 10000 ? remainingLen : 10000 - // this is dangerous, we create a fresh array view from the existing buffer - const bytes = decoder.arr.subarray(decoder.pos, decoder.pos + nextLen) - decoder.pos += nextLen - // Starting with ES5.1 we can supply a generic array-like object as arguments - encodedString += String.fromCodePoint.apply(null, /** @type {any} */ bytes as any) - remainingLen -= nextLen - } - } - return decodeURIComponent(escape(encodedString)) - } -} - -/** - * Look ahead and read varString without incrementing position - * - * @function - * @param {Decoder} decoder - * @return {string} - */ -export const peekVarString = (decoder: Decoder): string => { - const pos = decoder.pos - const s = readVarString(decoder) - decoder.pos = pos - return s -} - -/** - * @param {Decoder} decoder - * @param {number} len - * @return {DataView} - */ -export const readFromDataView = (decoder: Decoder, len: number): DataView => { - const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len) - decoder.pos += len - return dv -} - -/** - * @param {Decoder} decoder - */ -export const readFloat32 = (decoder: Decoder) => readFromDataView(decoder, 4).getFloat32(0, false) - -/** - * @param {Decoder} decoder - */ -export const readFloat64 = (decoder: Decoder) => readFromDataView(decoder, 8).getFloat64(0, false) - -/** - * @param {Decoder} decoder - */ -export const readBigInt64 = (decoder: Decoder) => /** @type {any} */ readFromDataView(decoder, 8).getBigInt64(0, false) - -/** - * @param {Decoder} decoder - */ -export const readBigUint64 = (decoder: Decoder) => - /** @type {any} */ readFromDataView(decoder, 8).getBigUint64(0, false) - -/** - * @type {Array} - */ -const readAnyLookupTable: Array<(arg0: Decoder) => any> = [ - (decoder) => undefined, // CASE 127: undefined - (decoder) => null, // CASE 126: null - readVarInt, // CASE 125: integer - readFloat32, // CASE 124: float32 - readFloat64, // CASE 123: float64 - readBigInt64, // CASE 122: bigint - (decoder) => false, // CASE 121: boolean (false) - (decoder) => true, // CASE 120: boolean (true) - readVarString, // CASE 119: string - (decoder) => { - // CASE 118: object - const len = readVarUint(decoder) - /** - * @type {Object} - */ - const obj: { [s: string]: any } = {} - for (let i = 0; i < len; i++) { - const key = readVarString(decoder) - obj[key] = readAny(decoder) - } - return obj - }, - (decoder) => { - // CASE 117: array - const len = readVarUint(decoder) - const arr = [] - for (let i = 0; i < len; i++) { - arr.push(readAny(decoder)) - } - return arr - }, - readVarUint8Array, // CASE 116: Uint8Array -] - -/** - * @param {Decoder} decoder - */ -export const readAny = (decoder: Decoder) => readAnyLookupTable[127 - readUint8(decoder)](decoder) - -/** - * T must not be null. - * - * @template T - */ -export class RleDecoder extends Decoder { - reader: (arg0: Decoder) => T - /** - * @param {Uint8Array} uint8Array - * @param {function(Decoder):T} reader - */ - s: T | null - count: number - constructor(uint8Array: Uint8Array, reader: (arg0: Decoder) => T) { - super(uint8Array) - /** - * The reader - */ - this.reader = reader - /** - * Current state - * @type {T|null} - */ - this.s = null - this.count = 0 - } - - read() { - if (this.count === 0) { - this.s = this.reader(this) - if (hasContent(this)) { - this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented - } else { - this.count = -1 // read the current value forever - } - } - this.count-- - return /** @type {T} */ this.s - } -} - -export class IntDiffDecoder extends Decoder { - s: number - /** - * @param {Uint8Array} uint8Array - * @param {number} start - */ - constructor(uint8Array: Uint8Array, start: number) { - super(uint8Array) - /** - * Current state - * @type {number} - */ - this.s = start - } - - /** - * @return {number} - */ - read(): number { - this.s += readVarInt(this) - return this.s - } -} - -export class RleIntDiffDecoder extends Decoder { - s: number - count: number - /** - * @param {Uint8Array} uint8Array - * @param {number} start - */ - constructor(uint8Array: Uint8Array, start: number) { - super(uint8Array) - /** - * Current state - * @type {number} - */ - this.s = start - this.count = 0 - } - - /** - * @return {number} - */ - read(): number { - if (this.count === 0) { - this.s += readVarInt(this) - if (hasContent(this)) { - this.count = readVarUint(this) + 1 // see encoder implementation for the reason why this is incremented - } else { - this.count = -1 // read the current value forever - } - } - this.count-- - return /** @type {number} */ this.s - } -} - -export class UintOptRleDecoder extends Decoder { - s: number - count: number - /** - * @param {Uint8Array} uint8Array - */ - constructor(uint8Array: Uint8Array) { - super(uint8Array) - /** - * @type {number} - */ - this.s = 0 - this.count = 0 - } - - read() { - if (this.count === 0) { - this.s = readVarInt(this) - // if the sign is negative, we read the count too, otherwise count is 1 - const isNegative = math.isNegativeZero(this.s) - this.count = 1 - if (isNegative) { - this.s = -this.s - this.count = readVarUint(this) + 2 - } - } - this.count-- - return /** @type {number} */ this.s - } -} - -export class IncUintOptRleDecoder extends Decoder { - s: number - count: number - /** - * @param {Uint8Array} uint8Array - */ - constructor(uint8Array: Uint8Array) { - super(uint8Array) - /** - * @type {number} - */ - this.s = 0 - this.count = 0 - } - - read() { - if (this.count === 0) { - this.s = readVarInt(this) - // if the sign is negative, we read the count too, otherwise count is 1 - const isNegative = math.isNegativeZero(this.s) - this.count = 1 - if (isNegative) { - this.s = -this.s - this.count = readVarUint(this) + 2 - } - } - this.count-- - return /** @type {number} */ this.s++ - } -} - -export class IntDiffOptRleDecoder extends Decoder { - s: number - count: number - diff: number - /** - * @param {Uint8Array} uint8Array - */ - constructor(uint8Array: Uint8Array) { - super(uint8Array) - /** - * @type {number} - */ - this.s = 0 - this.count = 0 - this.diff = 0 - } - - /** - * @return {number} - */ - read(): number { - if (this.count === 0) { - const diff = readVarInt(this) - // if the first bit is set, we read more data - const hasCount = diff & 1 - this.diff = diff >> 1 - this.count = 1 - if (hasCount) { - this.count = readVarUint(this) + 2 - } - } - this.s += this.diff - this.count-- - return this.s - } -} - -export class StringDecoder { - decoder: UintOptRleDecoder - str: string - spos: number - /** - * @param {Uint8Array} uint8Array - */ - constructor(uint8Array: Uint8Array) { - this.decoder = new UintOptRleDecoder(uint8Array) - this.str = readVarString(this.decoder) - /** - * @type {number} - */ - this.spos = 0 - } - - /** - * @return {string} - */ - read(): string { - const end = this.spos + this.decoder.read() - const res = this.str.slice(this.spos, end) - this.spos = end - return res - } -} diff --git a/src/encdec/encoding.ts b/src/encdec/encoding.ts deleted file mode 100644 index 798a188..0000000 --- a/src/encdec/encoding.ts +++ /dev/null @@ -1,845 +0,0 @@ -// https://github.com/dmonad/lib0 - -/** - * Efficient schema-less binary encoding with support for variable length encoding. - * - * Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function. - * - * Encodes numbers in little-endian order (least to most significant byte order) - * and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/) - * which is also used in Protocol Buffers. - * - * ```js - * // encoding step - * const encoder = new encoding.createEncoder() - * encoding.writeVarUint(encoder, 256) - * encoding.writeVarString(encoder, 'Hello world!') - * const buf = encoding.toUint8Array(encoder) - * ``` - * - * ```js - * // decoding step - * const decoder = new decoding.createDecoder(buf) - * decoding.readVarUint(decoder) // => 256 - * decoding.readVarString(decoder) // => 'Hello world!' - * decoding.hasContent(decoder) // => false - all data is read - * ``` - * - * @module encoding - */ - -import * as buffer from "./buffer" -import * as math from "./math" -import * as number from "./number" -import * as binary from "./binary" - -/** - * A BinaryEncoder handles the encoding to an Uint8Array. - */ -export class Encoder { - cpos = 0 - bufs: Array = [] - cbuf = new Uint8Array(100) -} - -/** - * @function - * @return {Encoder} - */ -export const createEncoder = (): Encoder => new Encoder() - -/** - * The current length of the encoded data. - * - * @function - * @param {Encoder} encoder - * @return {number} - */ -export const length = (encoder: Encoder): number => { - let len = encoder.cpos - for (let i = 0; i < encoder.bufs.length; i++) { - len += encoder.bufs[i].length - } - return len -} - -/** - * Transform to Uint8Array. - * - * @function - * @param {Encoder} encoder - * @return {Uint8Array} The created ArrayBuffer. - */ -export const toUint8Array = (encoder: Encoder): Uint8Array => { - const uint8arr = new Uint8Array(length(encoder)) - let curPos = 0 - for (let i = 0; i < encoder.bufs.length; i++) { - const d = encoder.bufs[i] - uint8arr.set(d, curPos) - curPos += d.length - } - uint8arr.set(buffer.createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos), curPos) - return uint8arr -} - -/** - * Verify that it is possible to write `len` bytes wtihout checking. If - * necessary, a new Buffer with the required length is attached. - * - * @param {Encoder} encoder - * @param {number} len - */ -const verifyLen = (encoder: Encoder, len: number) => { - const bufferLen = encoder.cbuf.length - if (bufferLen - encoder.cpos < len) { - encoder.bufs.push(buffer.createUint8ArrayViewFromArrayBuffer(encoder.cbuf.buffer, 0, encoder.cpos)) - encoder.cbuf = new Uint8Array(math.max(bufferLen, len) * 2) - encoder.cpos = 0 - } -} - -/** - * Write one byte to the encoder. - * - * @function - * @param {Encoder} encoder - * @param {number} num The byte that is to be encoded. - */ -export const write = (encoder: Encoder, num: number) => { - const bufferLen = encoder.cbuf.length - if (encoder.cpos === bufferLen) { - encoder.bufs.push(encoder.cbuf) - encoder.cbuf = new Uint8Array(bufferLen * 2) - encoder.cpos = 0 - } - encoder.cbuf[encoder.cpos++] = num -} - -/** - * Write one byte at a specific position. - * Position must already be written (i.e. encoder.length > pos) - * - * @function - * @param {Encoder} encoder - * @param {number} pos Position to which to write data - * @param {number} num Unsigned 8-bit integer - */ -export const set = (encoder: Encoder, pos: number, num: number) => { - let buffer = null - // iterate all buffers and adjust position - for (let i = 0; i < encoder.bufs.length && buffer === null; i++) { - const b = encoder.bufs[i] - if (pos < b.length) { - buffer = b // found buffer - } else { - pos -= b.length - } - } - if (buffer === null) { - // use current buffer - buffer = encoder.cbuf - } - buffer[pos] = num -} - -/** - * Write one byte as an unsigned integer. - * - * @function - * @param {Encoder} encoder - * @param {number} num The number that is to be encoded. - */ -export const writeUint8 = write - -/** - * Write one byte as an unsigned Integer at a specific location. - * - * @function - * @param {Encoder} encoder - * @param {number} pos The location where the data will be written. - * @param {number} num The number that is to be encoded. - */ -export const setUint8 = set - -/** - * Write two bytes as an unsigned integer. - * - * @function - * @param {Encoder} encoder - * @param {number} num The number that is to be encoded. - */ -export const writeUint16 = (encoder: Encoder, num: number) => { - write(encoder, num & binary.BITS8) - write(encoder, (num >>> 8) & binary.BITS8) -} -/** - * Write two bytes as an unsigned integer at a specific location. - * - * @function - * @param {Encoder} encoder - * @param {number} pos The location where the data will be written. - * @param {number} num The number that is to be encoded. - */ -export const setUint16 = (encoder: Encoder, pos: number, num: number) => { - set(encoder, pos, num & binary.BITS8) - set(encoder, pos + 1, (num >>> 8) & binary.BITS8) -} - -/** - * Write two bytes as an unsigned integer - * - * @function - * @param {Encoder} encoder - * @param {number} num The number that is to be encoded. - */ -export const writeUint32 = (encoder: Encoder, num: number) => { - for (let i = 0; i < 4; i++) { - write(encoder, num & binary.BITS8) - num >>>= 8 - } -} - -/** - * Write two bytes as an unsigned integer in big endian order. - * (most significant byte first) - * - * @function - * @param {Encoder} encoder - * @param {number} num The number that is to be encoded. - */ -export const writeUint32BigEndian = (encoder: Encoder, num: number) => { - for (let i = 3; i >= 0; i--) { - write(encoder, (num >>> (8 * i)) & binary.BITS8) - } -} - -/** - * Write two bytes as an unsigned integer at a specific location. - * - * @function - * @param {Encoder} encoder - * @param {number} pos The location where the data will be written. - * @param {number} num The number that is to be encoded. - */ -export const setUint32 = (encoder: Encoder, pos: number, num: number) => { - for (let i = 0; i < 4; i++) { - set(encoder, pos + i, num & binary.BITS8) - num >>>= 8 - } -} - -/** - * Write a variable length unsigned integer. - * - * Encodes integers in the range from [0, 4294967295] / [0, 0xffffffff]. (max 32 bit unsigned integer) - * - * @function - * @param {Encoder} encoder - * @param {number} num The number that is to be encoded. - */ -export const writeVarUint = (encoder: Encoder, num: number) => { - while (num > binary.BITS7) { - write(encoder, binary.BIT8 | (binary.BITS7 & num)) - num >>>= 7 - } - write(encoder, binary.BITS7 & num) -} - -/** - * Write a variable length integer. - * - * Encodes integers in the range from [-2147483648, -2147483647]. - * - * We don't use zig-zag encoding because we want to keep the option open - * to use the same function for BigInt and 53bit integers (doubles). - * - * We use the 7th bit instead for signaling that this is a negative number. - * - * @function - * @param {Encoder} encoder - * @param {number} num The number that is to be encoded. - */ -export const writeVarInt = (encoder: Encoder, num: number) => { - const isNegative = math.isNegativeZero(num) - if (isNegative) { - num = -num - } - // |- whether to continue reading |- whether is negative |- number - write(encoder, (num > binary.BITS6 ? binary.BIT8 : 0) | (isNegative ? binary.BIT7 : 0) | (binary.BITS6 & num)) - num >>>= 6 - // We don't need to consider the case of num === 0 so we can use a different - // pattern here than above. - while (num > 0) { - write(encoder, (num > binary.BITS7 ? binary.BIT8 : 0) | (binary.BITS7 & num)) - num >>>= 7 - } -} - -/** - * Write a variable length string. - * - * @function - * @param {Encoder} encoder - * @param {String} str The string that is to be encoded. - */ -export const writeVarString = (encoder: Encoder, str: string) => { - const encodedString = unescape(encodeURIComponent(str)) - const len = encodedString.length - writeVarUint(encoder, len) - for (let i = 0; i < len; i++) { - write(encoder, /** @type {number} */ encodedString.codePointAt(i)!) - } -} - -/** - * Write the content of another Encoder. - * - * @TODO: can be improved! - * - Note: Should consider that when appending a lot of small Encoders, we should rather clone than referencing the old structure. - * Encoders start with a rather big initial buffer. - * - * @function - * @param {Encoder} encoder The enUint8Arr - * @param {Encoder} append The BinaryEncoder to be written. - */ -export const writeBinaryEncoder = (encoder: Encoder, append: Encoder) => writeUint8Array(encoder, toUint8Array(append)) - -/** - * Append fixed-length Uint8Array to the encoder. - * - * @function - * @param {Encoder} encoder - * @param {Uint8Array} uint8Array - */ -export const writeUint8Array = (encoder: Encoder, uint8Array: Uint8Array) => { - const bufferLen = encoder.cbuf.length - const cpos = encoder.cpos - const leftCopyLen = math.min(bufferLen - cpos, uint8Array.length) - const rightCopyLen = uint8Array.length - leftCopyLen - encoder.cbuf.set(uint8Array.subarray(0, leftCopyLen), cpos) - encoder.cpos += leftCopyLen - if (rightCopyLen > 0) { - // Still something to write, write right half.. - // Append new buffer - encoder.bufs.push(encoder.cbuf) - // must have at least size of remaining buffer - encoder.cbuf = new Uint8Array(math.max(bufferLen * 2, rightCopyLen)) - // copy array - encoder.cbuf.set(uint8Array.subarray(leftCopyLen)) - encoder.cpos = rightCopyLen - } -} - -/** - * Append an Uint8Array to Encoder. - * - * @function - * @param {Encoder} encoder - * @param {Uint8Array} uint8Array - */ -export const writeVarUint8Array = (encoder: Encoder, uint8Array: Uint8Array) => { - writeVarUint(encoder, uint8Array.byteLength) - writeUint8Array(encoder, uint8Array) -} - -/** - * Create an DataView of the next `len` bytes. Use it to write data after - * calling this function. - * - * ```js - * // write float32 using DataView - * const dv = writeOnDataView(encoder, 4) - * dv.setFloat32(0, 1.1) - * // read float32 using DataView - * const dv = readFromDataView(encoder, 4) - * dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result) - * ``` - * - * @param {Encoder} encoder - * @param {number} len - * @return {DataView} - */ -export const writeOnDataView = (encoder: Encoder, len: number): DataView => { - verifyLen(encoder, len) - const dview = new DataView(encoder.cbuf.buffer, encoder.cpos, len) - encoder.cpos += len - return dview -} - -/** - * @param {Encoder} encoder - * @param {number} num - */ -export const writeFloat32 = (encoder: Encoder, num: number) => writeOnDataView(encoder, 4).setFloat32(0, num, false) - -/** - * @param {Encoder} encoder - * @param {number} num - */ -export const writeFloat64 = (encoder: Encoder, num: number) => writeOnDataView(encoder, 8).setFloat64(0, num, false) - -/** - * @param {Encoder} encoder - * @param {bigint} num - */ -export const writeBigInt64 = (encoder: Encoder, num: bigint) => - /** @type {any} */ writeOnDataView(encoder, 8).setBigInt64(0, num, false) - -/** - * @param {Encoder} encoder - * @param {bigint} num - */ -export const writeBigUint64 = (encoder: Encoder, num: bigint) => - /** @type {any} */ writeOnDataView(encoder, 8).setBigUint64(0, num, false) - -const floatTestBed = new DataView(new ArrayBuffer(4)) -/** - * Check if a number can be encoded as a 32 bit float. - * - * @param {number} num - * @return {boolean} - */ -const isFloat32 = (num: number): boolean => { - floatTestBed.setFloat32(0, num) - return floatTestBed.getFloat32(0) === num -} - -/** - * Encode data with efficient binary format. - * - * Differences to JSON: - * • Transforms data to a binary format (not to a string) - * • Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON) - * • Numbers are efficiently encoded either as a variable length integer, as a - * 32 bit float, as a 64 bit float, or as a 64 bit bigint. - * - * Encoding table: - * - * | Data Type | Prefix | Encoding Method | Comment | - * | ------------------- | -------- | ------------------ | ------- | - * | undefined | 127 | | Functions, symbol, and everything that cannot be identified is encoded as undefined | - * | null | 126 | | | - * | integer | 125 | writeVarInt | Only encodes 32 bit signed integers | - * | float32 | 124 | writeFloat32 | | - * | float64 | 123 | writeFloat64 | | - * | bigint | 122 | writeBigInt64 | | - * | boolean (false) | 121 | | True and false are different data types so we save the following byte | - * | boolean (true) | 120 | | - 0b01111000 so the last bit determines whether true or false | - * | string | 119 | writeVarString | | - * | object | 118 | custom | Writes {length} then {length} key-value pairs | - * | array | 117 | custom | Writes {length} then {length} json values | - * | Uint8Array | 116 | writeVarUint8Array | We use Uint8Array for any kind of binary data | - * - * Reasons for the decreasing prefix: - * We need the first bit for extendability (later we may want to encode the - * prefix with writeVarUint). The remaining 7 bits are divided as follows: - * [0-30] the beginning of the data range is used for custom purposes - * (defined by the function that uses this library) - * [31-127] the end of the data range is used for data encoding by - * lib0/encoding.js - * - * @param {Encoder} encoder - * @param {undefined|null|number|bigint|boolean|string|Object|Array|Uint8Array} data - */ -export const writeAny = ( - encoder: Encoder, - data: undefined | null | number | bigint | boolean | string | { [s: string]: any } | Array | Uint8Array -) => { - switch (typeof data) { - case "string": - // TYPE 119: STRING - write(encoder, 119) - writeVarString(encoder, data) - break - case "number": - if (number.isInteger(data) && data <= binary.BITS31) { - // TYPE 125: INTEGER - write(encoder, 125) - writeVarInt(encoder, data) - } else if (isFloat32(data)) { - // TYPE 124: FLOAT32 - write(encoder, 124) - writeFloat32(encoder, data) - } else { - // TYPE 123: FLOAT64 - write(encoder, 123) - writeFloat64(encoder, data) - } - break - case "bigint": - // TYPE 122: BigInt - write(encoder, 122) - writeBigInt64(encoder, data) - break - case "object": - if (data === null) { - // TYPE 126: null - write(encoder, 126) - } else if (data instanceof Array) { - // TYPE 117: Array - write(encoder, 117) - writeVarUint(encoder, data.length) - for (let i = 0; i < data.length; i++) { - writeAny(encoder, data[i]) - } - } else if (data instanceof Uint8Array) { - // TYPE 116: ArrayBuffer - write(encoder, 116) - writeVarUint8Array(encoder, data) - } else { - // TYPE 118: Object - write(encoder, 118) - const keys = Object.keys(data) - writeVarUint(encoder, keys.length) - for (let i = 0; i < keys.length; i++) { - const key = keys[i] - writeVarString(encoder, key) - writeAny(encoder, data[key]) - } - } - break - case "boolean": - // TYPE 120/121: boolean (true/false) - write(encoder, data ? 120 : 121) - break - default: - // TYPE 127: undefined - write(encoder, 127) - } -} - -/** - * Now come a few stateful encoder that have their own classes. - */ - -/** - * Basic Run Length Encoder - a basic compression implementation. - * - * Encodes [1,1,1,7] to [1,3,7,1] (3 times 1, 1 time 7). This encoder might do more harm than good if there are a lot of values that are not repeated. - * - * It was originally used for image compression. Cool .. article http://csbruce.com/cbm/transactor/pdfs/trans_v7_i06.pdf - * - * @note T must not be null! - * - * @template T - */ -export class RleEncoder extends Encoder { - /** - * @param {function(Encoder, T):void} writer - */ - w: (arg0: Encoder, arg1: T) => void - s: T | null = null - count: number - constructor(writer: (arg0: Encoder, arg1: T) => void) { - super() - /** - * The writer - */ - this.w = writer - /** - * Current state - * @type {T|null} - */ - this.s = null - this.count = 0 - } - - /** - * @param {T} v - */ - write(v: T) { - if (this.s === v) { - this.count++ - } else { - if (this.count > 0) { - // flush counter, unless this is the first value (count = 0) - writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw - } - this.count = 1 - // write first value - this.w(this, v) - this.s = v - } - } -} - -/** - * Basic diff decoder using variable length encoding. - * - * Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt. - */ -export class IntDiffEncoder extends Encoder { - /** - * @param {number} start - */ - s: number - constructor(start: number) { - super() - /** - * Current state - * @type {number} - */ - this.s = start - } - - /** - * @param {number} v - */ - write(v: number) { - writeVarInt(this, v - this.s) - this.s = v - } -} - -/** - * A combination of IntDiffEncoder and RleEncoder. - * - * Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding. - * - * Encodes the values [1,1,1,2,3,4,5,6] as [1,1,0,2,1,5] (RLE([1,0,0,1,1,1,1,1]) ⇒ RleIntDiff[1,1,0,2,1,5]) - */ -export class RleIntDiffEncoder extends Encoder { - s: number - count: number - /** - * @param {number} start - */ - constructor(start: number) { - super() - /** - * Current state - * @type {number} - */ - this.s = start - this.count = 0 - } - - /** - * @param {number} v - */ - write(v: number) { - if (this.s === v && this.count > 0) { - this.count++ - } else { - if (this.count > 0) { - // flush counter, unless this is the first value (count = 0) - writeVarUint(this, this.count - 1) // since count is always > 0, we can decrement by one. non-standard encoding ftw - } - this.count = 1 - // write first value - writeVarInt(this, v - this.s) - this.s = v - } - } -} - -/** - * @param {UintOptRleEncoder} encoder - */ -const flushUintOptRleEncoder = (encoder: UintOptRleEncoder) => { - /* istanbul ignore else */ - if (encoder.count > 0) { - // flush counter, unless this is the first value (count = 0) - // case 1: just a single value. set sign to positive - // case 2: write several values. set sign to negative to indicate that there is a length coming - writeVarInt(encoder.encoder, encoder.count === 1 ? encoder.s : -encoder.s) - if (encoder.count > 1) { - writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw - } - } -} - -/** - * Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder. - * - * Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write - * write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count. - * - * Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3) - */ -export class UintOptRleEncoder { - encoder: Encoder - s: number - count: number - constructor() { - this.encoder = new Encoder() - /** - * @type {number} - */ - this.s = 0 - this.count = 0 - } - - /** - * @param {number} v - */ - write(v: number) { - if (this.s === v) { - this.count++ - } else { - flushUintOptRleEncoder(this) - this.count = 1 - this.s = v - } - } - - toUint8Array() { - flushUintOptRleEncoder(this) - return toUint8Array(this.encoder) - } -} - -/** - * Increasing Uint Optimized RLE Encoder - * - * The RLE encoder counts the number of same occurences of the same value. - * The IncUintOptRle encoder counts if the value increases. - * I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded - * as [1, 3, 5]. - */ -export class IncUintOptRleEncoder { - encoder: Encoder - s: number - count: number - constructor() { - this.encoder = new Encoder() - /** - * @type {number} - */ - this.s = 0 - this.count = 0 - } - - /** - * @param {number} v - */ - write(v: number) { - if (this.s + this.count === v) { - this.count++ - } else { - flushUintOptRleEncoder(this) - this.count = 1 - this.s = v - } - } - - toUint8Array() { - flushUintOptRleEncoder(this) - return toUint8Array(this.encoder) - } -} - -/** - * @param {IntDiffOptRleEncoder} encoder - */ -const flushIntDiffOptRleEncoder = (encoder: IntDiffOptRleEncoder) => { - if (encoder.count > 0) { - // 31 bit making up the diff | wether to write the counter - const encodedDiff = (encoder.diff << 1) | (encoder.count === 1 ? 0 : 1) - // flush counter, unless this is the first value (count = 0) - // case 1: just a single value. set first bit to positive - // case 2: write several values. set first bit to negative to indicate that there is a length coming - writeVarInt(encoder.encoder, encodedDiff) - if (encoder.count > 1) { - writeVarUint(encoder.encoder, encoder.count - 2) // since count is always > 1, we can decrement by one. non-standard encoding ftw - } - } -} - -/** - * A combination of the IntDiffEncoder and the UintOptRleEncoder. - * - * The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes - * in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers! - * - * Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 << 1) | 1, (3 << 0) | 0, -1]) - * - * Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains: - * * 1 bit that denotes whether the next value is a count (LSB) - * * 1 bit that denotes whether this value is negative (MSB - 1) - * * 1 bit that denotes whether to continue reading the variable length integer (MSB) - * - * Therefore, only five bits remain to encode diff ranges. - * - * Use this Encoder only when appropriate. In most cases, this is probably a bad idea. - */ -export class IntDiffOptRleEncoder { - encoder: Encoder - s: number - count: number - diff: number - constructor() { - this.encoder = new Encoder() - /** - * @type {number} - */ - this.s = 0 - this.count = 0 - this.diff = 0 - } - - /** - * @param {number} v - */ - write(v: number) { - if (this.diff === v - this.s) { - this.s = v - this.count++ - } else { - flushIntDiffOptRleEncoder(this) - this.count = 1 - this.diff = v - this.s - this.s = v - } - } - - toUint8Array() { - flushIntDiffOptRleEncoder(this) - return toUint8Array(this.encoder) - } -} - -/** - * Optimized String Encoder. - * - * Encoding many small strings in a simple Encoder is not very efficient. The function call to decode a string takes some time and creates references that must be eventually deleted. - * In practice, when decoding several million small strings, the GC will kick in more and more often to collect orphaned string objects (or maybe there is another reason?). - * - * This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call. - * - * The lengths are encoded using a UintOptRleEncoder. - */ -export class StringEncoder { - sarr: string[] - s: string - lensE: UintOptRleEncoder - constructor() { - /** - * @type {Array} - */ - this.sarr = [] - this.s = "" - this.lensE = new UintOptRleEncoder() - } - - /** - * @param {string} string - */ - write(string: string) { - this.s += string - if (this.s.length > 19) { - this.sarr.push(this.s) - this.s = "" - } - this.lensE.write(string.length) - } - - toUint8Array() { - const encoder = new Encoder() - this.sarr.push(this.s) - this.s = "" - writeVarString(encoder, this.sarr.join("")) - writeUint8Array(encoder, this.lensE.toUint8Array()) - return toUint8Array(encoder) - } -} diff --git a/src/encdec/math.ts b/src/encdec/math.ts deleted file mode 100644 index e8c2177..0000000 --- a/src/encdec/math.ts +++ /dev/null @@ -1,60 +0,0 @@ -// https://github.com/dmonad/lib0 - -/** - * Common Math expressions. - * - * @module math - */ - -export const floor = Math.floor -export const ceil = Math.ceil -export const abs = Math.abs -export const imul = Math.imul -export const round = Math.round -export const log10 = Math.log10 -export const log2 = Math.log2 -export const log = Math.log -export const sqrt = Math.sqrt - -/** - * @function - * @param {number} a - * @param {number} b - * @return {number} The sum of a and b - */ -export const add = (a: number, b: number): number => a + b - -/** - * @function - * @param {number} a - * @param {number} b - * @return {number} The smaller element of a and b - */ -export const min = (a: number, b: number): number => (a < b ? a : b) - -/** - * @function - * @param {number} a - * @param {number} b - * @return {number} The bigger element of a and b - */ -export const max = (a: number, b: number): number => (a > b ? a : b) - -export const isNaN = Number.isNaN - -export const pow = Math.pow -/** - * Base 10 exponential function. Returns the value of 10 raised to the power of pow. - * - * @param {number} exp - * @return {number} - */ -export const exp10 = (exp: number): number => Math.pow(10, exp) - -export const sign = Math.sign - -/** - * @param {number} n - * @return {boolean} Wether n is negative. This function also differentiates between -0 and +0 - */ -export const isNegativeZero = (n: number): boolean => (n !== 0 ? n < 0 : 1 / n < 0) diff --git a/src/encdec/number.ts b/src/encdec/number.ts deleted file mode 100644 index ec532be..0000000 --- a/src/encdec/number.ts +++ /dev/null @@ -1,29 +0,0 @@ -// https://github.com/dmonad/lib0 - -/** - * Utility helpers for working with numbers. - * - * @module number - */ - -import * as math from "./math" -import * as binary from "./binary" - -export const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER -export const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER - -export const LOWEST_INT32 = 1 << 31 -/** - * @type {number} - */ -export const HIGHEST_INT32 = binary.BITS31 - -/** - * @module number - */ - -/* istanbul ignore next */ -export const isInteger = - Number.isInteger || ((num) => typeof num === "number" && isFinite(num) && math.floor(num) === num) -export const isNaN = Number.isNaN -export const parseInt = Number.parseInt diff --git a/src/encdec/string.ts b/src/encdec/string.ts deleted file mode 100644 index 2e82d4e..0000000 --- a/src/encdec/string.ts +++ /dev/null @@ -1,129 +0,0 @@ -// https://github.com/dmonad/lib0 - -declare var TextEncoder: any -declare var TextDecoder: any - -/** - * Utility module to work with strings. - * - * @module string - */ - -export const fromCharCode = String.fromCharCode -export const fromCodePoint = String.fromCodePoint - -/** - * @param {string} s - * @return {string} - */ -const toLowerCase = (s: string): string => s.toLowerCase() - -const trimLeftRegex = /^\s*/g - -/** - * @param {string} s - * @return {string} - */ -export const trimLeft = (s: string): string => s.replace(trimLeftRegex, "") - -const fromCamelCaseRegex = /([A-Z])/g - -/** - * @param {string} s - * @param {string} separator - * @return {string} - */ -export const fromCamelCase = (s: string, separator: string): string => - trimLeft(s.replace(fromCamelCaseRegex, (match: any) => `${separator}${toLowerCase(match)}`)) - -/** - * Compute the utf8ByteLength - * @param {string} str - * @return {number} - */ -export const utf8ByteLength = (str: string | number | boolean): number => unescape(encodeURIComponent(str)).length - -/** - * @param {string} str - * @return {Uint8Array} - */ -export const _encodeUtf8Polyfill = (str: string | number | boolean): Uint8Array => { - const encodedString = unescape(encodeURIComponent(str)) - const len = encodedString.length - const buf = new Uint8Array(len) - for (let i = 0; i < len; i++) { - buf[i] = /** @type {number} */ encodedString.codePointAt(i)! - } - return buf -} - -/* istanbul ignore next */ -export const utf8TextEncoder = /** @type {TextEncoder} */ new TextEncoder() - -/** - * @param {string} str - * @return {Uint8Array} - */ -export const _encodeUtf8Native = (str: any): Uint8Array => utf8TextEncoder.encode(str) - -/** - * @param {string} str - * @return {Uint8Array} - */ -/* istanbul ignore next */ -export const encodeUtf8 = utf8TextEncoder ? _encodeUtf8Native : _encodeUtf8Polyfill - -/** - * @param {Uint8Array} buf - * @return {string} - */ -export const _decodeUtf8Polyfill = (buf: { length: any; subarray: (arg0: number, arg1: any) => any }): string => { - let remainingLen = buf.length - let encodedString = "" - let bufPos = 0 - while (remainingLen > 0) { - const nextLen = remainingLen < 10000 ? remainingLen : 10000 - const bytes = buf.subarray(bufPos, bufPos + nextLen) - bufPos += nextLen - // Starting with ES5.1 we can supply a generic array-like object as arguments - encodedString += String.fromCodePoint.apply(null, /** @type {any} */ bytes) - remainingLen -= nextLen - } - return decodeURIComponent(escape(encodedString)) -} - -/* istanbul ignore next */ -export let utf8TextDecoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }) - -/* istanbul ignore next */ -if (utf8TextDecoder && utf8TextDecoder.decode(new Uint8Array()).length === 1) { - // Safari doesn't handle BOM correctly. - // This fixes a bug in Safari 13.0.5 where it produces a BOM the first time it is called. - // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the first call and - // utf8TextDecoder.decode(new Uint8Array()).length === 1 on the second call - // Another issue is that from then on no BOM chars are recognized anymore - /* istanbul ignore next */ - utf8TextDecoder = null -} - -/** - * @param {Uint8Array} buf - * @return {string} - */ -export const _decodeUtf8Native = (buf: any): string => /** @type {TextDecoder} */ utf8TextDecoder.decode(buf) - -/** - * @param {Uint8Array} buf - * @return {string} - */ -/* istanbul ignore next */ -export const decodeUtf8 = utf8TextDecoder ? _decodeUtf8Native : _decodeUtf8Polyfill - -/** - * @param {string} str The initial string - * @param {number} index Starting position - * @param {number} remove Number of characters to remove - * @param {string} insert New content to insert - */ -export const splice = (str: string, index: any, remove: any, insert: string = "") => - str.slice(0, index) + insert + str.slice(index + remove) diff --git a/src/message-number-handler.ts b/src/message-number-handler.ts index eaf3242..ebdb658 100644 --- a/src/message-number-handler.ts +++ b/src/message-number-handler.ts @@ -1,8 +1,7 @@ import { Transport } from "." -import { createDecoder, Decoder } from "./encdec/decoding" -import { Encoder, toUint8Array } from "./encdec/encoding" +import { Writer,Reader } from "protobufjs" import { parseMessageIdentifier } from "./protocol/helpers" -import { readRpcMessageHeader } from "./protocol/wire-protocol" +import { RpcMessageHeader } from "./protocol/pbjs" let globalMessageNumber = 0 export type SendableMessage = { @@ -11,20 +10,20 @@ export type SendableMessage = { export type MessageDispatcher = { transport: Transport - request(cb: (bb: Encoder, messageNumber: number) => void): Promise - addListener(messageId: number, handler: (reader: Decoder) => void): void + request(cb: (bb: Writer, messageNumber: number) => void): Promise + addListener(messageId: number, handler: (reader: Reader) => void): void removeListener(messageId: number): void } export function messageNumberHandler(transport: Transport): MessageDispatcher { // message_number -> future - type ReaderCallback = (reader: Decoder) => void + type ReaderCallback = (reader: Reader) => void const oneTimeCallbacks = new Map() - const listeners = new Map void>() + const listeners = new Map void>() transport.on("message", (message) => { - const reader = createDecoder(message) - const header = readRpcMessageHeader(reader) + const reader = Reader.create(message) + const header = RpcMessageHeader.decode(reader) const [_, messageNumber] = parseMessageIdentifier(header.messageIdentifier) if (messageNumber > 0) { @@ -52,14 +51,14 @@ export function messageNumberHandler(transport: Transport): MessageDispatcher { if (!listeners.has(messageId)) throw new Error("A handler is missing for messageId " + messageId) listeners.delete(messageId) }, - async request(cb: (bb: Encoder, messageNumber: number) => void): Promise { + async request(cb: (bb: Writer, messageNumber: number) => void): Promise { const messageNumber = ++globalMessageNumber if (globalMessageNumber > 0x01000000) globalMessageNumber = 0 - return new Promise((resolve) => { + return new Promise((resolve) => { oneTimeCallbacks.set(messageNumber, resolve) - const bb = new Encoder() + const bb = new Writer() cb(bb, messageNumber) - transport.sendMessage(toUint8Array(bb)) + transport.sendMessage(bb.finish()) }) }, } diff --git a/src/protocol/helpers.ts b/src/protocol/helpers.ts index ea6f23b..8863e3d 100644 --- a/src/protocol/helpers.ts +++ b/src/protocol/helpers.ts @@ -1,31 +1,32 @@ -import { Decoder } from "../encdec/decoding" -import { createEncoder, toUint8Array } from "../encdec/encoding" +import { Writer, Reader } from "protobufjs" import { RpcMessageTypes, - readRpcMessageHeader, - readCreatePortResponse, - readResponse, - readRequestModuleResponse, - readStreamMessage, - readRemoteError, - readRequest, - readCreatePort, - readRequestModule, - readDestroyPort, - writeStreamMessage, -} from "./wire-protocol" + RpcMessageHeader, + CreatePortResponse, + Response, + RequestModuleResponse, + StreamMessage, + RemoteError, + Request, + CreatePort, + RequestModule, + DestroyPort, +} from "./pbjs" export function closeStreamMessage(messageNumber: number, sequenceId: number, portId: number): Uint8Array { - const bb = createEncoder() - writeStreamMessage(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.STREAM_MESSAGE, messageNumber), - sequenceId, - portId, - ack: false, - closed: true, - payload: Uint8Array.of(), - }) - return toUint8Array(bb) + const bb = new Writer() + StreamMessage.encode( + { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE, messageNumber), + sequenceId, + portId, + ack: false, + closed: true, + payload: Uint8Array.of(), + }, + bb + ) + return bb.finish() } export function streamMessage( @@ -34,29 +35,35 @@ export function streamMessage( portId: number, payload: Uint8Array ): Uint8Array { - const bb = createEncoder() - writeStreamMessage(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.STREAM_MESSAGE, messageNumber), - sequenceId, - portId, - ack: false, - closed: false, - payload, - }) - return toUint8Array(bb) + const bb = new Writer() + StreamMessage.encode( + { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE, messageNumber), + sequenceId, + portId, + ack: false, + closed: false, + payload, + }, + bb + ) + return bb.finish() } export function streamAckMessage(messageNumber: number, sequenceId: number, portId: number): Uint8Array { - const bb = createEncoder() - writeStreamMessage(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.STREAM_ACK, messageNumber), - sequenceId, - portId, - ack: true, - closed: false, - payload: Uint8Array.of(), - }) - return toUint8Array(bb) + const bb = new Writer() + StreamMessage.encode( + { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_STREAM_ACK, messageNumber), + sequenceId, + portId, + ack: true, + closed: false, + payload: Uint8Array.of(), + }, + bb + ) + return bb.finish() } // @internal @@ -69,34 +76,34 @@ export function calculateMessageIdentifier(messageType: number, messageNumber: n return ((messageType & 0xf) << 27) | (messageNumber & 0x07ffffff) } -export function parseProtocolMessage(reader: Decoder): [number, any, number] | null { +export function parseProtocolMessage(reader: Reader): [number, any, number] | null { const originalPos = reader.pos - const [messageType, messageNumber] = parseMessageIdentifier(readRpcMessageHeader(reader).messageIdentifier) + const [messageType, messageNumber] = parseMessageIdentifier(RpcMessageHeader.decode(reader).messageIdentifier) reader.pos = originalPos switch (messageType) { - case RpcMessageTypes.CREATE_PORT_RESPONSE: - return [messageType, readCreatePortResponse(reader), messageNumber] - case RpcMessageTypes.RESPONSE: - return [messageType, readResponse(reader), messageNumber] - case RpcMessageTypes.REQUEST_MODULE_RESPONSE: - return [messageType, readRequestModuleResponse(reader), messageNumber] - case RpcMessageTypes.STREAM_MESSAGE: - return [messageType, readStreamMessage(reader), messageNumber] - case RpcMessageTypes.SERVER_READY: + case RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE: + return [messageType, CreatePortResponse.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_RESPONSE: + return [messageType, Response.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE: + return [messageType, RequestModuleResponse.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE: + return [messageType, StreamMessage.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_SERVER_READY: return null - case RpcMessageTypes.REMOTE_ERROR_RESPONSE: - return [messageType, readRemoteError(reader), messageNumber] - case RpcMessageTypes.REQUEST: - return [messageType, readRequest(reader), messageNumber] - case RpcMessageTypes.CREATE_PORT: - return [messageType, readCreatePort(reader), messageNumber] - case RpcMessageTypes.STREAM_ACK: - return [messageType, readStreamMessage(reader), messageNumber] - case RpcMessageTypes.REQUEST_MODULE: - return [messageType, readRequestModule(reader), messageNumber] - case RpcMessageTypes.DESTROY_PORT: - return [messageType, readDestroyPort(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE: + return [messageType, RemoteError.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_REQUEST: + return [messageType, Request.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_CREATE_PORT: + return [messageType, CreatePort.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_STREAM_ACK: + return [messageType, StreamMessage.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE: + return [messageType, RequestModule.decode(reader), messageNumber] + case RpcMessageTypes.RpcMessageTypes_DESTROY_PORT: + return [messageType, DestroyPort.decode(reader), messageNumber] } return null diff --git a/src/protocol/pbjs.d.ts b/src/protocol/pbjs.d.ts new file mode 100644 index 0000000..2ab40cd --- /dev/null +++ b/src/protocol/pbjs.d.ts @@ -0,0 +1,993 @@ +import * as $protobuf from "protobufjs"; +/** Properties of a RpcMessageHeader. */ +export interface IRpcMessageHeader { + + /** RpcMessageHeader messageIdentifier */ + messageIdentifier?: (number|null); +} + +/** Represents a RpcMessageHeader. */ +export class RpcMessageHeader implements IRpcMessageHeader { + + /** + * Constructs a new RpcMessageHeader. + * @param [properties] Properties to set + */ + constructor(properties?: IRpcMessageHeader); + + /** RpcMessageHeader messageIdentifier. */ + public messageIdentifier: number; + + /** + * Creates a new RpcMessageHeader instance using the specified properties. + * @param [properties] Properties to set + * @returns RpcMessageHeader instance + */ + public static create(properties?: IRpcMessageHeader): RpcMessageHeader; + + /** + * Encodes the specified RpcMessageHeader message. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. + * @param message RpcMessageHeader message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IRpcMessageHeader, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified RpcMessageHeader message, length delimited. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. + * @param message RpcMessageHeader message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IRpcMessageHeader, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a RpcMessageHeader message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns RpcMessageHeader + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RpcMessageHeader; + + /** + * Decodes a RpcMessageHeader message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns RpcMessageHeader + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RpcMessageHeader; + + /** + * Verifies a RpcMessageHeader message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a RpcMessageHeader message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns RpcMessageHeader + */ + public static fromObject(object: { [k: string]: any }): RpcMessageHeader; + + /** + * Creates a plain object from a RpcMessageHeader message. Also converts values to other types if specified. + * @param message RpcMessageHeader + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: RpcMessageHeader, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this RpcMessageHeader to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** RpcMessageTypes enum. */ +export enum RpcMessageTypes { + RpcMessageTypes_EMPTY = 0, + RpcMessageTypes_REQUEST = 1, + RpcMessageTypes_RESPONSE = 2, + RpcMessageTypes_STREAM_MESSAGE = 3, + RpcMessageTypes_STREAM_ACK = 4, + RpcMessageTypes_CREATE_PORT = 5, + RpcMessageTypes_CREATE_PORT_RESPONSE = 6, + RpcMessageTypes_REQUEST_MODULE = 7, + RpcMessageTypes_REQUEST_MODULE_RESPONSE = 8, + RpcMessageTypes_REMOTE_ERROR_RESPONSE = 9, + RpcMessageTypes_DESTROY_PORT = 10, + RpcMessageTypes_SERVER_READY = 11 +} + +/** Represents a CreatePort. */ +export class CreatePort implements ICreatePort { + + /** + * Constructs a new CreatePort. + * @param [properties] Properties to set + */ + constructor(properties?: ICreatePort); + + /** CreatePort messageIdentifier. */ + public messageIdentifier: number; + + /** CreatePort portName. */ + public portName: string; + + /** + * Creates a new CreatePort instance using the specified properties. + * @param [properties] Properties to set + * @returns CreatePort instance + */ + public static create(properties?: ICreatePort): CreatePort; + + /** + * Encodes the specified CreatePort message. Does not implicitly {@link CreatePort.verify|verify} messages. + * @param message CreatePort message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: ICreatePort, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified CreatePort message, length delimited. Does not implicitly {@link CreatePort.verify|verify} messages. + * @param message CreatePort message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: ICreatePort, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a CreatePort message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns CreatePort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): CreatePort; + + /** + * Decodes a CreatePort message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns CreatePort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): CreatePort; + + /** + * Verifies a CreatePort message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a CreatePort message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns CreatePort + */ + public static fromObject(object: { [k: string]: any }): CreatePort; + + /** + * Creates a plain object from a CreatePort message. Also converts values to other types if specified. + * @param message CreatePort + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: CreatePort, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this CreatePort to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a CreatePortResponse. */ +export class CreatePortResponse implements ICreatePortResponse { + + /** + * Constructs a new CreatePortResponse. + * @param [properties] Properties to set + */ + constructor(properties?: ICreatePortResponse); + + /** CreatePortResponse messageIdentifier. */ + public messageIdentifier: number; + + /** CreatePortResponse portId. */ + public portId: number; + + /** + * Creates a new CreatePortResponse instance using the specified properties. + * @param [properties] Properties to set + * @returns CreatePortResponse instance + */ + public static create(properties?: ICreatePortResponse): CreatePortResponse; + + /** + * Encodes the specified CreatePortResponse message. Does not implicitly {@link CreatePortResponse.verify|verify} messages. + * @param message CreatePortResponse message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: ICreatePortResponse, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified CreatePortResponse message, length delimited. Does not implicitly {@link CreatePortResponse.verify|verify} messages. + * @param message CreatePortResponse message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: ICreatePortResponse, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a CreatePortResponse message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns CreatePortResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): CreatePortResponse; + + /** + * Decodes a CreatePortResponse message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns CreatePortResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): CreatePortResponse; + + /** + * Verifies a CreatePortResponse message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a CreatePortResponse message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns CreatePortResponse + */ + public static fromObject(object: { [k: string]: any }): CreatePortResponse; + + /** + * Creates a plain object from a CreatePortResponse message. Also converts values to other types if specified. + * @param message CreatePortResponse + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: CreatePortResponse, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this CreatePortResponse to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a RequestModule. */ +export class RequestModule implements IRequestModule { + + /** + * Constructs a new RequestModule. + * @param [properties] Properties to set + */ + constructor(properties?: IRequestModule); + + /** RequestModule messageIdentifier. */ + public messageIdentifier: number; + + /** RequestModule portId. */ + public portId: number; + + /** RequestModule moduleName. */ + public moduleName: string; + + /** + * Creates a new RequestModule instance using the specified properties. + * @param [properties] Properties to set + * @returns RequestModule instance + */ + public static create(properties?: IRequestModule): RequestModule; + + /** + * Encodes the specified RequestModule message. Does not implicitly {@link RequestModule.verify|verify} messages. + * @param message RequestModule message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IRequestModule, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified RequestModule message, length delimited. Does not implicitly {@link RequestModule.verify|verify} messages. + * @param message RequestModule message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IRequestModule, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a RequestModule message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns RequestModule + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RequestModule; + + /** + * Decodes a RequestModule message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns RequestModule + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RequestModule; + + /** + * Verifies a RequestModule message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a RequestModule message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns RequestModule + */ + public static fromObject(object: { [k: string]: any }): RequestModule; + + /** + * Creates a plain object from a RequestModule message. Also converts values to other types if specified. + * @param message RequestModule + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: RequestModule, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this RequestModule to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a RequestModuleResponse. */ +export class RequestModuleResponse implements IRequestModuleResponse { + + /** + * Constructs a new RequestModuleResponse. + * @param [properties] Properties to set + */ + constructor(properties?: IRequestModuleResponse); + + /** RequestModuleResponse messageIdentifier. */ + public messageIdentifier: number; + + /** RequestModuleResponse portId. */ + public portId: number; + + /** RequestModuleResponse procedures. */ + public procedures: IModuleProcedure[]; + + /** + * Creates a new RequestModuleResponse instance using the specified properties. + * @param [properties] Properties to set + * @returns RequestModuleResponse instance + */ + public static create(properties?: IRequestModuleResponse): RequestModuleResponse; + + /** + * Encodes the specified RequestModuleResponse message. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. + * @param message RequestModuleResponse message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IRequestModuleResponse, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified RequestModuleResponse message, length delimited. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. + * @param message RequestModuleResponse message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IRequestModuleResponse, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a RequestModuleResponse message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns RequestModuleResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RequestModuleResponse; + + /** + * Decodes a RequestModuleResponse message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns RequestModuleResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RequestModuleResponse; + + /** + * Verifies a RequestModuleResponse message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a RequestModuleResponse message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns RequestModuleResponse + */ + public static fromObject(object: { [k: string]: any }): RequestModuleResponse; + + /** + * Creates a plain object from a RequestModuleResponse message. Also converts values to other types if specified. + * @param message RequestModuleResponse + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: RequestModuleResponse, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this RequestModuleResponse to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a DestroyPort. */ +export class DestroyPort implements IDestroyPort { + + /** + * Constructs a new DestroyPort. + * @param [properties] Properties to set + */ + constructor(properties?: IDestroyPort); + + /** DestroyPort messageIdentifier. */ + public messageIdentifier: number; + + /** DestroyPort portId. */ + public portId: number; + + /** + * Creates a new DestroyPort instance using the specified properties. + * @param [properties] Properties to set + * @returns DestroyPort instance + */ + public static create(properties?: IDestroyPort): DestroyPort; + + /** + * Encodes the specified DestroyPort message. Does not implicitly {@link DestroyPort.verify|verify} messages. + * @param message DestroyPort message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IDestroyPort, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified DestroyPort message, length delimited. Does not implicitly {@link DestroyPort.verify|verify} messages. + * @param message DestroyPort message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IDestroyPort, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a DestroyPort message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns DestroyPort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DestroyPort; + + /** + * Decodes a DestroyPort message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns DestroyPort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DestroyPort; + + /** + * Verifies a DestroyPort message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a DestroyPort message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns DestroyPort + */ + public static fromObject(object: { [k: string]: any }): DestroyPort; + + /** + * Creates a plain object from a DestroyPort message. Also converts values to other types if specified. + * @param message DestroyPort + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: DestroyPort, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this DestroyPort to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a ModuleProcedure. */ +export class ModuleProcedure implements IModuleProcedure { + + /** + * Constructs a new ModuleProcedure. + * @param [properties] Properties to set + */ + constructor(properties?: IModuleProcedure); + + /** ModuleProcedure procedureId. */ + public procedureId: number; + + /** ModuleProcedure procedureName. */ + public procedureName: string; + + /** + * Creates a new ModuleProcedure instance using the specified properties. + * @param [properties] Properties to set + * @returns ModuleProcedure instance + */ + public static create(properties?: IModuleProcedure): ModuleProcedure; + + /** + * Encodes the specified ModuleProcedure message. Does not implicitly {@link ModuleProcedure.verify|verify} messages. + * @param message ModuleProcedure message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IModuleProcedure, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified ModuleProcedure message, length delimited. Does not implicitly {@link ModuleProcedure.verify|verify} messages. + * @param message ModuleProcedure message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IModuleProcedure, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a ModuleProcedure message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns ModuleProcedure + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): ModuleProcedure; + + /** + * Decodes a ModuleProcedure message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns ModuleProcedure + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): ModuleProcedure; + + /** + * Verifies a ModuleProcedure message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a ModuleProcedure message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns ModuleProcedure + */ + public static fromObject(object: { [k: string]: any }): ModuleProcedure; + + /** + * Creates a plain object from a ModuleProcedure message. Also converts values to other types if specified. + * @param message ModuleProcedure + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: ModuleProcedure, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this ModuleProcedure to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a Request. */ +export class Request implements IRequest { + + /** + * Constructs a new Request. + * @param [properties] Properties to set + */ + constructor(properties?: IRequest); + + /** Request messageIdentifier. */ + public messageIdentifier: number; + + /** Request portId. */ + public portId: number; + + /** Request procedureId. */ + public procedureId: number; + + /** Request payload. */ + public payload: Uint8Array; + + /** + * Creates a new Request instance using the specified properties. + * @param [properties] Properties to set + * @returns Request instance + */ + public static create(properties?: IRequest): Request; + + /** + * Encodes the specified Request message. Does not implicitly {@link Request.verify|verify} messages. + * @param message Request message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IRequest, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Request message, length delimited. Does not implicitly {@link Request.verify|verify} messages. + * @param message Request message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IRequest, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Request message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Request + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Request; + + /** + * Decodes a Request message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Request + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Request; + + /** + * Verifies a Request message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a Request message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Request + */ + public static fromObject(object: { [k: string]: any }): Request; + + /** + * Creates a plain object from a Request message. Also converts values to other types if specified. + * @param message Request + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: Request, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Request to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a RemoteError. */ +export class RemoteError implements IRemoteError { + + /** + * Constructs a new RemoteError. + * @param [properties] Properties to set + */ + constructor(properties?: IRemoteError); + + /** RemoteError messageIdentifier. */ + public messageIdentifier: number; + + /** RemoteError errorCode. */ + public errorCode: number; + + /** RemoteError errorMessage. */ + public errorMessage: string; + + /** + * Creates a new RemoteError instance using the specified properties. + * @param [properties] Properties to set + * @returns RemoteError instance + */ + public static create(properties?: IRemoteError): RemoteError; + + /** + * Encodes the specified RemoteError message. Does not implicitly {@link RemoteError.verify|verify} messages. + * @param message RemoteError message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IRemoteError, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified RemoteError message, length delimited. Does not implicitly {@link RemoteError.verify|verify} messages. + * @param message RemoteError message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IRemoteError, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a RemoteError message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns RemoteError + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RemoteError; + + /** + * Decodes a RemoteError message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns RemoteError + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RemoteError; + + /** + * Verifies a RemoteError message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a RemoteError message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns RemoteError + */ + public static fromObject(object: { [k: string]: any }): RemoteError; + + /** + * Creates a plain object from a RemoteError message. Also converts values to other types if specified. + * @param message RemoteError + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: RemoteError, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this RemoteError to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a Response. */ +export class Response implements IResponse { + + /** + * Constructs a new Response. + * @param [properties] Properties to set + */ + constructor(properties?: IResponse); + + /** Response messageIdentifier. */ + public messageIdentifier: number; + + /** Response payload. */ + public payload: Uint8Array; + + /** + * Creates a new Response instance using the specified properties. + * @param [properties] Properties to set + * @returns Response instance + */ + public static create(properties?: IResponse): Response; + + /** + * Encodes the specified Response message. Does not implicitly {@link Response.verify|verify} messages. + * @param message Response message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IResponse, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified Response message, length delimited. Does not implicitly {@link Response.verify|verify} messages. + * @param message Response message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IResponse, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a Response message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns Response + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Response; + + /** + * Decodes a Response message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns Response + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Response; + + /** + * Verifies a Response message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a Response message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns Response + */ + public static fromObject(object: { [k: string]: any }): Response; + + /** + * Creates a plain object from a Response message. Also converts values to other types if specified. + * @param message Response + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: Response, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this Response to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} + +/** Represents a StreamMessage. */ +export class StreamMessage implements IStreamMessage { + + /** + * Constructs a new StreamMessage. + * @param [properties] Properties to set + */ + constructor(properties?: IStreamMessage); + + /** StreamMessage messageIdentifier. */ + public messageIdentifier: number; + + /** StreamMessage portId. */ + public portId: number; + + /** StreamMessage sequenceId. */ + public sequenceId: number; + + /** StreamMessage payload. */ + public payload: Uint8Array; + + /** StreamMessage closed. */ + public closed: boolean; + + /** StreamMessage ack. */ + public ack: boolean; + + /** + * Creates a new StreamMessage instance using the specified properties. + * @param [properties] Properties to set + * @returns StreamMessage instance + */ + public static create(properties?: IStreamMessage): StreamMessage; + + /** + * Encodes the specified StreamMessage message. Does not implicitly {@link StreamMessage.verify|verify} messages. + * @param message StreamMessage message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encode(message: IStreamMessage, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Encodes the specified StreamMessage message, length delimited. Does not implicitly {@link StreamMessage.verify|verify} messages. + * @param message StreamMessage message or plain object to encode + * @param [writer] Writer to encode to + * @returns Writer + */ + public static encodeDelimited(message: IStreamMessage, writer?: $protobuf.Writer): $protobuf.Writer; + + /** + * Decodes a StreamMessage message from the specified reader or buffer. + * @param reader Reader or buffer to decode from + * @param [length] Message length if known beforehand + * @returns StreamMessage + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): StreamMessage; + + /** + * Decodes a StreamMessage message from the specified reader or buffer, length delimited. + * @param reader Reader or buffer to decode from + * @returns StreamMessage + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): StreamMessage; + + /** + * Verifies a StreamMessage message. + * @param message Plain object to verify + * @returns `null` if valid, otherwise the reason why it is not + */ + public static verify(message: { [k: string]: any }): (string|null); + + /** + * Creates a StreamMessage message from a plain object. Also converts values to their respective internal types. + * @param object Plain object + * @returns StreamMessage + */ + public static fromObject(object: { [k: string]: any }): StreamMessage; + + /** + * Creates a plain object from a StreamMessage message. Also converts values to other types if specified. + * @param message StreamMessage + * @param [options] Conversion options + * @returns Plain object + */ + public static toObject(message: StreamMessage, options?: $protobuf.IConversionOptions): { [k: string]: any }; + + /** + * Converts this StreamMessage to JSON. + * @returns JSON object + */ + public toJSON(): { [k: string]: any }; +} diff --git a/src/protocol/pbjs.js b/src/protocol/pbjs.js new file mode 100644 index 0000000..81eb007 --- /dev/null +++ b/src/protocol/pbjs.js @@ -0,0 +1,2580 @@ +/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/ +"use strict"; + +var $protobuf = require("protobufjs/minimal"); + +// Common aliases +var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; + +// Exported root namespace +var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); + +$root.RpcMessageHeader = (function() { + + /** + * Properties of a RpcMessageHeader. + * @exports IRpcMessageHeader + * @interface IRpcMessageHeader + * @property {number|null} [messageIdentifier] RpcMessageHeader messageIdentifier + */ + + /** + * Constructs a new RpcMessageHeader. + * @exports RpcMessageHeader + * @classdesc Represents a RpcMessageHeader. + * @implements IRpcMessageHeader + * @constructor + * @param {IRpcMessageHeader=} [properties] Properties to set + */ + function RpcMessageHeader(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * RpcMessageHeader messageIdentifier. + * @member {number} messageIdentifier + * @memberof RpcMessageHeader + * @instance + */ + RpcMessageHeader.prototype.messageIdentifier = 0; + + /** + * Creates a new RpcMessageHeader instance using the specified properties. + * @function create + * @memberof RpcMessageHeader + * @static + * @param {IRpcMessageHeader=} [properties] Properties to set + * @returns {RpcMessageHeader} RpcMessageHeader instance + */ + RpcMessageHeader.create = function create(properties) { + return new RpcMessageHeader(properties); + }; + + /** + * Encodes the specified RpcMessageHeader message. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. + * @function encode + * @memberof RpcMessageHeader + * @static + * @param {IRpcMessageHeader} message RpcMessageHeader message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RpcMessageHeader.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + return writer; + }; + + /** + * Encodes the specified RpcMessageHeader message, length delimited. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. + * @function encodeDelimited + * @memberof RpcMessageHeader + * @static + * @param {IRpcMessageHeader} message RpcMessageHeader message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RpcMessageHeader.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a RpcMessageHeader message from the specified reader or buffer. + * @function decode + * @memberof RpcMessageHeader + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {RpcMessageHeader} RpcMessageHeader + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RpcMessageHeader.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RpcMessageHeader(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a RpcMessageHeader message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof RpcMessageHeader + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {RpcMessageHeader} RpcMessageHeader + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RpcMessageHeader.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a RpcMessageHeader message. + * @function verify + * @memberof RpcMessageHeader + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + RpcMessageHeader.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + return null; + }; + + /** + * Creates a RpcMessageHeader message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof RpcMessageHeader + * @static + * @param {Object.} object Plain object + * @returns {RpcMessageHeader} RpcMessageHeader + */ + RpcMessageHeader.fromObject = function fromObject(object) { + if (object instanceof $root.RpcMessageHeader) + return object; + var message = new $root.RpcMessageHeader(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + return message; + }; + + /** + * Creates a plain object from a RpcMessageHeader message. Also converts values to other types if specified. + * @function toObject + * @memberof RpcMessageHeader + * @static + * @param {RpcMessageHeader} message RpcMessageHeader + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + RpcMessageHeader.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.messageIdentifier = 0; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + return object; + }; + + /** + * Converts this RpcMessageHeader to JSON. + * @function toJSON + * @memberof RpcMessageHeader + * @instance + * @returns {Object.} JSON object + */ + RpcMessageHeader.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return RpcMessageHeader; +})(); + +/** + * RpcMessageTypes enum. + * @exports RpcMessageTypes + * @enum {number} + * @property {number} RpcMessageTypes_EMPTY=0 RpcMessageTypes_EMPTY value + * @property {number} RpcMessageTypes_REQUEST=1 RpcMessageTypes_REQUEST value + * @property {number} RpcMessageTypes_RESPONSE=2 RpcMessageTypes_RESPONSE value + * @property {number} RpcMessageTypes_STREAM_MESSAGE=3 RpcMessageTypes_STREAM_MESSAGE value + * @property {number} RpcMessageTypes_STREAM_ACK=4 RpcMessageTypes_STREAM_ACK value + * @property {number} RpcMessageTypes_CREATE_PORT=5 RpcMessageTypes_CREATE_PORT value + * @property {number} RpcMessageTypes_CREATE_PORT_RESPONSE=6 RpcMessageTypes_CREATE_PORT_RESPONSE value + * @property {number} RpcMessageTypes_REQUEST_MODULE=7 RpcMessageTypes_REQUEST_MODULE value + * @property {number} RpcMessageTypes_REQUEST_MODULE_RESPONSE=8 RpcMessageTypes_REQUEST_MODULE_RESPONSE value + * @property {number} RpcMessageTypes_REMOTE_ERROR_RESPONSE=9 RpcMessageTypes_REMOTE_ERROR_RESPONSE value + * @property {number} RpcMessageTypes_DESTROY_PORT=10 RpcMessageTypes_DESTROY_PORT value + * @property {number} RpcMessageTypes_SERVER_READY=11 RpcMessageTypes_SERVER_READY value + */ +$root.RpcMessageTypes = (function() { + var valuesById = {}, values = Object.create(valuesById); + values[valuesById[0] = "RpcMessageTypes_EMPTY"] = 0; + values[valuesById[1] = "RpcMessageTypes_REQUEST"] = 1; + values[valuesById[2] = "RpcMessageTypes_RESPONSE"] = 2; + values[valuesById[3] = "RpcMessageTypes_STREAM_MESSAGE"] = 3; + values[valuesById[4] = "RpcMessageTypes_STREAM_ACK"] = 4; + values[valuesById[5] = "RpcMessageTypes_CREATE_PORT"] = 5; + values[valuesById[6] = "RpcMessageTypes_CREATE_PORT_RESPONSE"] = 6; + values[valuesById[7] = "RpcMessageTypes_REQUEST_MODULE"] = 7; + values[valuesById[8] = "RpcMessageTypes_REQUEST_MODULE_RESPONSE"] = 8; + values[valuesById[9] = "RpcMessageTypes_REMOTE_ERROR_RESPONSE"] = 9; + values[valuesById[10] = "RpcMessageTypes_DESTROY_PORT"] = 10; + values[valuesById[11] = "RpcMessageTypes_SERVER_READY"] = 11; + return values; +})(); + +$root.CreatePort = (function() { + + /** + * Properties of a CreatePort. + * @exports ICreatePort + * @interface ICreatePort + * @property {number|null} [messageIdentifier] CreatePort messageIdentifier + * @property {string|null} [portName] CreatePort portName + */ + + /** + * Constructs a new CreatePort. + * @exports CreatePort + * @classdesc Represents a CreatePort. + * @implements ICreatePort + * @constructor + * @param {ICreatePort=} [properties] Properties to set + */ + function CreatePort(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * CreatePort messageIdentifier. + * @member {number} messageIdentifier + * @memberof CreatePort + * @instance + */ + CreatePort.prototype.messageIdentifier = 0; + + /** + * CreatePort portName. + * @member {string} portName + * @memberof CreatePort + * @instance + */ + CreatePort.prototype.portName = ""; + + /** + * Creates a new CreatePort instance using the specified properties. + * @function create + * @memberof CreatePort + * @static + * @param {ICreatePort=} [properties] Properties to set + * @returns {CreatePort} CreatePort instance + */ + CreatePort.create = function create(properties) { + return new CreatePort(properties); + }; + + /** + * Encodes the specified CreatePort message. Does not implicitly {@link CreatePort.verify|verify} messages. + * @function encode + * @memberof CreatePort + * @static + * @param {ICreatePort} message CreatePort message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CreatePort.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portName != null && Object.hasOwnProperty.call(message, "portName")) + writer.uint32(/* id 4, wireType 2 =*/34).string(message.portName); + return writer; + }; + + /** + * Encodes the specified CreatePort message, length delimited. Does not implicitly {@link CreatePort.verify|verify} messages. + * @function encodeDelimited + * @memberof CreatePort + * @static + * @param {ICreatePort} message CreatePort message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CreatePort.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a CreatePort message from the specified reader or buffer. + * @function decode + * @memberof CreatePort + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {CreatePort} CreatePort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CreatePort.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.CreatePort(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 4: + message.portName = reader.string(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a CreatePort message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof CreatePort + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {CreatePort} CreatePort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CreatePort.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a CreatePort message. + * @function verify + * @memberof CreatePort + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + CreatePort.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portName != null && message.hasOwnProperty("portName")) + if (!$util.isString(message.portName)) + return "portName: string expected"; + return null; + }; + + /** + * Creates a CreatePort message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof CreatePort + * @static + * @param {Object.} object Plain object + * @returns {CreatePort} CreatePort + */ + CreatePort.fromObject = function fromObject(object) { + if (object instanceof $root.CreatePort) + return object; + var message = new $root.CreatePort(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portName != null) + message.portName = String(object.portName); + return message; + }; + + /** + * Creates a plain object from a CreatePort message. Also converts values to other types if specified. + * @function toObject + * @memberof CreatePort + * @static + * @param {CreatePort} message CreatePort + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + CreatePort.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.portName = ""; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portName != null && message.hasOwnProperty("portName")) + object.portName = message.portName; + return object; + }; + + /** + * Converts this CreatePort to JSON. + * @function toJSON + * @memberof CreatePort + * @instance + * @returns {Object.} JSON object + */ + CreatePort.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CreatePort; +})(); + +$root.CreatePortResponse = (function() { + + /** + * Properties of a CreatePortResponse. + * @exports ICreatePortResponse + * @interface ICreatePortResponse + * @property {number|null} [messageIdentifier] CreatePortResponse messageIdentifier + * @property {number|null} [portId] CreatePortResponse portId + */ + + /** + * Constructs a new CreatePortResponse. + * @exports CreatePortResponse + * @classdesc Represents a CreatePortResponse. + * @implements ICreatePortResponse + * @constructor + * @param {ICreatePortResponse=} [properties] Properties to set + */ + function CreatePortResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * CreatePortResponse messageIdentifier. + * @member {number} messageIdentifier + * @memberof CreatePortResponse + * @instance + */ + CreatePortResponse.prototype.messageIdentifier = 0; + + /** + * CreatePortResponse portId. + * @member {number} portId + * @memberof CreatePortResponse + * @instance + */ + CreatePortResponse.prototype.portId = 0; + + /** + * Creates a new CreatePortResponse instance using the specified properties. + * @function create + * @memberof CreatePortResponse + * @static + * @param {ICreatePortResponse=} [properties] Properties to set + * @returns {CreatePortResponse} CreatePortResponse instance + */ + CreatePortResponse.create = function create(properties) { + return new CreatePortResponse(properties); + }; + + /** + * Encodes the specified CreatePortResponse message. Does not implicitly {@link CreatePortResponse.verify|verify} messages. + * @function encode + * @memberof CreatePortResponse + * @static + * @param {ICreatePortResponse} message CreatePortResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CreatePortResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); + return writer; + }; + + /** + * Encodes the specified CreatePortResponse message, length delimited. Does not implicitly {@link CreatePortResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof CreatePortResponse + * @static + * @param {ICreatePortResponse} message CreatePortResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CreatePortResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a CreatePortResponse message from the specified reader or buffer. + * @function decode + * @memberof CreatePortResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {CreatePortResponse} CreatePortResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CreatePortResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.CreatePortResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.portId = reader.fixed32(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a CreatePortResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof CreatePortResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {CreatePortResponse} CreatePortResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CreatePortResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a CreatePortResponse message. + * @function verify + * @memberof CreatePortResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + CreatePortResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portId != null && message.hasOwnProperty("portId")) + if (!$util.isInteger(message.portId)) + return "portId: integer expected"; + return null; + }; + + /** + * Creates a CreatePortResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof CreatePortResponse + * @static + * @param {Object.} object Plain object + * @returns {CreatePortResponse} CreatePortResponse + */ + CreatePortResponse.fromObject = function fromObject(object) { + if (object instanceof $root.CreatePortResponse) + return object; + var message = new $root.CreatePortResponse(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portId != null) + message.portId = object.portId >>> 0; + return message; + }; + + /** + * Creates a plain object from a CreatePortResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof CreatePortResponse + * @static + * @param {CreatePortResponse} message CreatePortResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + CreatePortResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.portId = 0; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portId != null && message.hasOwnProperty("portId")) + object.portId = message.portId; + return object; + }; + + /** + * Converts this CreatePortResponse to JSON. + * @function toJSON + * @memberof CreatePortResponse + * @instance + * @returns {Object.} JSON object + */ + CreatePortResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CreatePortResponse; +})(); + +$root.RequestModule = (function() { + + /** + * Properties of a RequestModule. + * @exports IRequestModule + * @interface IRequestModule + * @property {number|null} [messageIdentifier] RequestModule messageIdentifier + * @property {number|null} [portId] RequestModule portId + * @property {string|null} [moduleName] RequestModule moduleName + */ + + /** + * Constructs a new RequestModule. + * @exports RequestModule + * @classdesc Represents a RequestModule. + * @implements IRequestModule + * @constructor + * @param {IRequestModule=} [properties] Properties to set + */ + function RequestModule(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * RequestModule messageIdentifier. + * @member {number} messageIdentifier + * @memberof RequestModule + * @instance + */ + RequestModule.prototype.messageIdentifier = 0; + + /** + * RequestModule portId. + * @member {number} portId + * @memberof RequestModule + * @instance + */ + RequestModule.prototype.portId = 0; + + /** + * RequestModule moduleName. + * @member {string} moduleName + * @memberof RequestModule + * @instance + */ + RequestModule.prototype.moduleName = ""; + + /** + * Creates a new RequestModule instance using the specified properties. + * @function create + * @memberof RequestModule + * @static + * @param {IRequestModule=} [properties] Properties to set + * @returns {RequestModule} RequestModule instance + */ + RequestModule.create = function create(properties) { + return new RequestModule(properties); + }; + + /** + * Encodes the specified RequestModule message. Does not implicitly {@link RequestModule.verify|verify} messages. + * @function encode + * @memberof RequestModule + * @static + * @param {IRequestModule} message RequestModule message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RequestModule.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); + if (message.moduleName != null && Object.hasOwnProperty.call(message, "moduleName")) + writer.uint32(/* id 4, wireType 2 =*/34).string(message.moduleName); + return writer; + }; + + /** + * Encodes the specified RequestModule message, length delimited. Does not implicitly {@link RequestModule.verify|verify} messages. + * @function encodeDelimited + * @memberof RequestModule + * @static + * @param {IRequestModule} message RequestModule message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RequestModule.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a RequestModule message from the specified reader or buffer. + * @function decode + * @memberof RequestModule + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {RequestModule} RequestModule + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RequestModule.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RequestModule(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.portId = reader.fixed32(); + break; + case 4: + message.moduleName = reader.string(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a RequestModule message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof RequestModule + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {RequestModule} RequestModule + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RequestModule.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a RequestModule message. + * @function verify + * @memberof RequestModule + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + RequestModule.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portId != null && message.hasOwnProperty("portId")) + if (!$util.isInteger(message.portId)) + return "portId: integer expected"; + if (message.moduleName != null && message.hasOwnProperty("moduleName")) + if (!$util.isString(message.moduleName)) + return "moduleName: string expected"; + return null; + }; + + /** + * Creates a RequestModule message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof RequestModule + * @static + * @param {Object.} object Plain object + * @returns {RequestModule} RequestModule + */ + RequestModule.fromObject = function fromObject(object) { + if (object instanceof $root.RequestModule) + return object; + var message = new $root.RequestModule(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portId != null) + message.portId = object.portId >>> 0; + if (object.moduleName != null) + message.moduleName = String(object.moduleName); + return message; + }; + + /** + * Creates a plain object from a RequestModule message. Also converts values to other types if specified. + * @function toObject + * @memberof RequestModule + * @static + * @param {RequestModule} message RequestModule + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + RequestModule.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.portId = 0; + object.moduleName = ""; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portId != null && message.hasOwnProperty("portId")) + object.portId = message.portId; + if (message.moduleName != null && message.hasOwnProperty("moduleName")) + object.moduleName = message.moduleName; + return object; + }; + + /** + * Converts this RequestModule to JSON. + * @function toJSON + * @memberof RequestModule + * @instance + * @returns {Object.} JSON object + */ + RequestModule.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return RequestModule; +})(); + +$root.RequestModuleResponse = (function() { + + /** + * Properties of a RequestModuleResponse. + * @exports IRequestModuleResponse + * @interface IRequestModuleResponse + * @property {number|null} [messageIdentifier] RequestModuleResponse messageIdentifier + * @property {number|null} [portId] RequestModuleResponse portId + * @property {Array.|null} [procedures] RequestModuleResponse procedures + */ + + /** + * Constructs a new RequestModuleResponse. + * @exports RequestModuleResponse + * @classdesc Represents a RequestModuleResponse. + * @implements IRequestModuleResponse + * @constructor + * @param {IRequestModuleResponse=} [properties] Properties to set + */ + function RequestModuleResponse(properties) { + this.procedures = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * RequestModuleResponse messageIdentifier. + * @member {number} messageIdentifier + * @memberof RequestModuleResponse + * @instance + */ + RequestModuleResponse.prototype.messageIdentifier = 0; + + /** + * RequestModuleResponse portId. + * @member {number} portId + * @memberof RequestModuleResponse + * @instance + */ + RequestModuleResponse.prototype.portId = 0; + + /** + * RequestModuleResponse procedures. + * @member {Array.} procedures + * @memberof RequestModuleResponse + * @instance + */ + RequestModuleResponse.prototype.procedures = $util.emptyArray; + + /** + * Creates a new RequestModuleResponse instance using the specified properties. + * @function create + * @memberof RequestModuleResponse + * @static + * @param {IRequestModuleResponse=} [properties] Properties to set + * @returns {RequestModuleResponse} RequestModuleResponse instance + */ + RequestModuleResponse.create = function create(properties) { + return new RequestModuleResponse(properties); + }; + + /** + * Encodes the specified RequestModuleResponse message. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. + * @function encode + * @memberof RequestModuleResponse + * @static + * @param {IRequestModuleResponse} message RequestModuleResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RequestModuleResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); + if (message.procedures != null && message.procedures.length) + for (var i = 0; i < message.procedures.length; ++i) + $root.ModuleProcedure.encode(message.procedures[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified RequestModuleResponse message, length delimited. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof RequestModuleResponse + * @static + * @param {IRequestModuleResponse} message RequestModuleResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RequestModuleResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a RequestModuleResponse message from the specified reader or buffer. + * @function decode + * @memberof RequestModuleResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {RequestModuleResponse} RequestModuleResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RequestModuleResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RequestModuleResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.portId = reader.fixed32(); + break; + case 5: + if (!(message.procedures && message.procedures.length)) + message.procedures = []; + message.procedures.push($root.ModuleProcedure.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a RequestModuleResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof RequestModuleResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {RequestModuleResponse} RequestModuleResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RequestModuleResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a RequestModuleResponse message. + * @function verify + * @memberof RequestModuleResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + RequestModuleResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portId != null && message.hasOwnProperty("portId")) + if (!$util.isInteger(message.portId)) + return "portId: integer expected"; + if (message.procedures != null && message.hasOwnProperty("procedures")) { + if (!Array.isArray(message.procedures)) + return "procedures: array expected"; + for (var i = 0; i < message.procedures.length; ++i) { + var error = $root.ModuleProcedure.verify(message.procedures[i]); + if (error) + return "procedures." + error; + } + } + return null; + }; + + /** + * Creates a RequestModuleResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof RequestModuleResponse + * @static + * @param {Object.} object Plain object + * @returns {RequestModuleResponse} RequestModuleResponse + */ + RequestModuleResponse.fromObject = function fromObject(object) { + if (object instanceof $root.RequestModuleResponse) + return object; + var message = new $root.RequestModuleResponse(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portId != null) + message.portId = object.portId >>> 0; + if (object.procedures) { + if (!Array.isArray(object.procedures)) + throw TypeError(".RequestModuleResponse.procedures: array expected"); + message.procedures = []; + for (var i = 0; i < object.procedures.length; ++i) { + if (typeof object.procedures[i] !== "object") + throw TypeError(".RequestModuleResponse.procedures: object expected"); + message.procedures[i] = $root.ModuleProcedure.fromObject(object.procedures[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a RequestModuleResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof RequestModuleResponse + * @static + * @param {RequestModuleResponse} message RequestModuleResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + RequestModuleResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.procedures = []; + if (options.defaults) { + object.messageIdentifier = 0; + object.portId = 0; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portId != null && message.hasOwnProperty("portId")) + object.portId = message.portId; + if (message.procedures && message.procedures.length) { + object.procedures = []; + for (var j = 0; j < message.procedures.length; ++j) + object.procedures[j] = $root.ModuleProcedure.toObject(message.procedures[j], options); + } + return object; + }; + + /** + * Converts this RequestModuleResponse to JSON. + * @function toJSON + * @memberof RequestModuleResponse + * @instance + * @returns {Object.} JSON object + */ + RequestModuleResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return RequestModuleResponse; +})(); + +$root.DestroyPort = (function() { + + /** + * Properties of a DestroyPort. + * @exports IDestroyPort + * @interface IDestroyPort + * @property {number|null} [messageIdentifier] DestroyPort messageIdentifier + * @property {number|null} [portId] DestroyPort portId + */ + + /** + * Constructs a new DestroyPort. + * @exports DestroyPort + * @classdesc Represents a DestroyPort. + * @implements IDestroyPort + * @constructor + * @param {IDestroyPort=} [properties] Properties to set + */ + function DestroyPort(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * DestroyPort messageIdentifier. + * @member {number} messageIdentifier + * @memberof DestroyPort + * @instance + */ + DestroyPort.prototype.messageIdentifier = 0; + + /** + * DestroyPort portId. + * @member {number} portId + * @memberof DestroyPort + * @instance + */ + DestroyPort.prototype.portId = 0; + + /** + * Creates a new DestroyPort instance using the specified properties. + * @function create + * @memberof DestroyPort + * @static + * @param {IDestroyPort=} [properties] Properties to set + * @returns {DestroyPort} DestroyPort instance + */ + DestroyPort.create = function create(properties) { + return new DestroyPort(properties); + }; + + /** + * Encodes the specified DestroyPort message. Does not implicitly {@link DestroyPort.verify|verify} messages. + * @function encode + * @memberof DestroyPort + * @static + * @param {IDestroyPort} message DestroyPort message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + DestroyPort.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); + return writer; + }; + + /** + * Encodes the specified DestroyPort message, length delimited. Does not implicitly {@link DestroyPort.verify|verify} messages. + * @function encodeDelimited + * @memberof DestroyPort + * @static + * @param {IDestroyPort} message DestroyPort message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + DestroyPort.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a DestroyPort message from the specified reader or buffer. + * @function decode + * @memberof DestroyPort + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {DestroyPort} DestroyPort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + DestroyPort.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.DestroyPort(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.portId = reader.fixed32(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a DestroyPort message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof DestroyPort + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {DestroyPort} DestroyPort + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + DestroyPort.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a DestroyPort message. + * @function verify + * @memberof DestroyPort + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + DestroyPort.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portId != null && message.hasOwnProperty("portId")) + if (!$util.isInteger(message.portId)) + return "portId: integer expected"; + return null; + }; + + /** + * Creates a DestroyPort message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof DestroyPort + * @static + * @param {Object.} object Plain object + * @returns {DestroyPort} DestroyPort + */ + DestroyPort.fromObject = function fromObject(object) { + if (object instanceof $root.DestroyPort) + return object; + var message = new $root.DestroyPort(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portId != null) + message.portId = object.portId >>> 0; + return message; + }; + + /** + * Creates a plain object from a DestroyPort message. Also converts values to other types if specified. + * @function toObject + * @memberof DestroyPort + * @static + * @param {DestroyPort} message DestroyPort + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + DestroyPort.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.portId = 0; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portId != null && message.hasOwnProperty("portId")) + object.portId = message.portId; + return object; + }; + + /** + * Converts this DestroyPort to JSON. + * @function toJSON + * @memberof DestroyPort + * @instance + * @returns {Object.} JSON object + */ + DestroyPort.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return DestroyPort; +})(); + +$root.ModuleProcedure = (function() { + + /** + * Properties of a ModuleProcedure. + * @exports IModuleProcedure + * @interface IModuleProcedure + * @property {number|null} [procedureId] ModuleProcedure procedureId + * @property {string|null} [procedureName] ModuleProcedure procedureName + */ + + /** + * Constructs a new ModuleProcedure. + * @exports ModuleProcedure + * @classdesc Represents a ModuleProcedure. + * @implements IModuleProcedure + * @constructor + * @param {IModuleProcedure=} [properties] Properties to set + */ + function ModuleProcedure(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * ModuleProcedure procedureId. + * @member {number} procedureId + * @memberof ModuleProcedure + * @instance + */ + ModuleProcedure.prototype.procedureId = 0; + + /** + * ModuleProcedure procedureName. + * @member {string} procedureName + * @memberof ModuleProcedure + * @instance + */ + ModuleProcedure.prototype.procedureName = ""; + + /** + * Creates a new ModuleProcedure instance using the specified properties. + * @function create + * @memberof ModuleProcedure + * @static + * @param {IModuleProcedure=} [properties] Properties to set + * @returns {ModuleProcedure} ModuleProcedure instance + */ + ModuleProcedure.create = function create(properties) { + return new ModuleProcedure(properties); + }; + + /** + * Encodes the specified ModuleProcedure message. Does not implicitly {@link ModuleProcedure.verify|verify} messages. + * @function encode + * @memberof ModuleProcedure + * @static + * @param {IModuleProcedure} message ModuleProcedure message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ModuleProcedure.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.procedureId != null && Object.hasOwnProperty.call(message, "procedureId")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.procedureId); + if (message.procedureName != null && Object.hasOwnProperty.call(message, "procedureName")) + writer.uint32(/* id 2, wireType 2 =*/18).string(message.procedureName); + return writer; + }; + + /** + * Encodes the specified ModuleProcedure message, length delimited. Does not implicitly {@link ModuleProcedure.verify|verify} messages. + * @function encodeDelimited + * @memberof ModuleProcedure + * @static + * @param {IModuleProcedure} message ModuleProcedure message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ModuleProcedure.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a ModuleProcedure message from the specified reader or buffer. + * @function decode + * @memberof ModuleProcedure + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {ModuleProcedure} ModuleProcedure + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ModuleProcedure.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.ModuleProcedure(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.procedureId = reader.fixed32(); + break; + case 2: + message.procedureName = reader.string(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a ModuleProcedure message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof ModuleProcedure + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {ModuleProcedure} ModuleProcedure + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ModuleProcedure.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a ModuleProcedure message. + * @function verify + * @memberof ModuleProcedure + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ModuleProcedure.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.procedureId != null && message.hasOwnProperty("procedureId")) + if (!$util.isInteger(message.procedureId)) + return "procedureId: integer expected"; + if (message.procedureName != null && message.hasOwnProperty("procedureName")) + if (!$util.isString(message.procedureName)) + return "procedureName: string expected"; + return null; + }; + + /** + * Creates a ModuleProcedure message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof ModuleProcedure + * @static + * @param {Object.} object Plain object + * @returns {ModuleProcedure} ModuleProcedure + */ + ModuleProcedure.fromObject = function fromObject(object) { + if (object instanceof $root.ModuleProcedure) + return object; + var message = new $root.ModuleProcedure(); + if (object.procedureId != null) + message.procedureId = object.procedureId >>> 0; + if (object.procedureName != null) + message.procedureName = String(object.procedureName); + return message; + }; + + /** + * Creates a plain object from a ModuleProcedure message. Also converts values to other types if specified. + * @function toObject + * @memberof ModuleProcedure + * @static + * @param {ModuleProcedure} message ModuleProcedure + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ModuleProcedure.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.procedureId = 0; + object.procedureName = ""; + } + if (message.procedureId != null && message.hasOwnProperty("procedureId")) + object.procedureId = message.procedureId; + if (message.procedureName != null && message.hasOwnProperty("procedureName")) + object.procedureName = message.procedureName; + return object; + }; + + /** + * Converts this ModuleProcedure to JSON. + * @function toJSON + * @memberof ModuleProcedure + * @instance + * @returns {Object.} JSON object + */ + ModuleProcedure.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return ModuleProcedure; +})(); + +$root.Request = (function() { + + /** + * Properties of a Request. + * @exports IRequest + * @interface IRequest + * @property {number|null} [messageIdentifier] Request messageIdentifier + * @property {number|null} [portId] Request portId + * @property {number|null} [procedureId] Request procedureId + * @property {Uint8Array|null} [payload] Request payload + */ + + /** + * Constructs a new Request. + * @exports Request + * @classdesc Represents a Request. + * @implements IRequest + * @constructor + * @param {IRequest=} [properties] Properties to set + */ + function Request(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Request messageIdentifier. + * @member {number} messageIdentifier + * @memberof Request + * @instance + */ + Request.prototype.messageIdentifier = 0; + + /** + * Request portId. + * @member {number} portId + * @memberof Request + * @instance + */ + Request.prototype.portId = 0; + + /** + * Request procedureId. + * @member {number} procedureId + * @memberof Request + * @instance + */ + Request.prototype.procedureId = 0; + + /** + * Request payload. + * @member {Uint8Array} payload + * @memberof Request + * @instance + */ + Request.prototype.payload = $util.newBuffer([]); + + /** + * Creates a new Request instance using the specified properties. + * @function create + * @memberof Request + * @static + * @param {IRequest=} [properties] Properties to set + * @returns {Request} Request instance + */ + Request.create = function create(properties) { + return new Request(properties); + }; + + /** + * Encodes the specified Request message. Does not implicitly {@link Request.verify|verify} messages. + * @function encode + * @memberof Request + * @static + * @param {IRequest} message Request message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Request.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); + if (message.procedureId != null && Object.hasOwnProperty.call(message, "procedureId")) + writer.uint32(/* id 4, wireType 5 =*/37).fixed32(message.procedureId); + if (message.payload != null && Object.hasOwnProperty.call(message, "payload")) + writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.payload); + return writer; + }; + + /** + * Encodes the specified Request message, length delimited. Does not implicitly {@link Request.verify|verify} messages. + * @function encodeDelimited + * @memberof Request + * @static + * @param {IRequest} message Request message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Request.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Request message from the specified reader or buffer. + * @function decode + * @memberof Request + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {Request} Request + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Request.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Request(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.portId = reader.fixed32(); + break; + case 4: + message.procedureId = reader.fixed32(); + break; + case 6: + message.payload = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Request message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof Request + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {Request} Request + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Request.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Request message. + * @function verify + * @memberof Request + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Request.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portId != null && message.hasOwnProperty("portId")) + if (!$util.isInteger(message.portId)) + return "portId: integer expected"; + if (message.procedureId != null && message.hasOwnProperty("procedureId")) + if (!$util.isInteger(message.procedureId)) + return "procedureId: integer expected"; + if (message.payload != null && message.hasOwnProperty("payload")) + if (!(message.payload && typeof message.payload.length === "number" || $util.isString(message.payload))) + return "payload: buffer expected"; + return null; + }; + + /** + * Creates a Request message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Request + * @static + * @param {Object.} object Plain object + * @returns {Request} Request + */ + Request.fromObject = function fromObject(object) { + if (object instanceof $root.Request) + return object; + var message = new $root.Request(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portId != null) + message.portId = object.portId >>> 0; + if (object.procedureId != null) + message.procedureId = object.procedureId >>> 0; + if (object.payload != null) + if (typeof object.payload === "string") + $util.base64.decode(object.payload, message.payload = $util.newBuffer($util.base64.length(object.payload)), 0); + else if (object.payload.length) + message.payload = object.payload; + return message; + }; + + /** + * Creates a plain object from a Request message. Also converts values to other types if specified. + * @function toObject + * @memberof Request + * @static + * @param {Request} message Request + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Request.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.portId = 0; + object.procedureId = 0; + if (options.bytes === String) + object.payload = ""; + else { + object.payload = []; + if (options.bytes !== Array) + object.payload = $util.newBuffer(object.payload); + } + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portId != null && message.hasOwnProperty("portId")) + object.portId = message.portId; + if (message.procedureId != null && message.hasOwnProperty("procedureId")) + object.procedureId = message.procedureId; + if (message.payload != null && message.hasOwnProperty("payload")) + object.payload = options.bytes === String ? $util.base64.encode(message.payload, 0, message.payload.length) : options.bytes === Array ? Array.prototype.slice.call(message.payload) : message.payload; + return object; + }; + + /** + * Converts this Request to JSON. + * @function toJSON + * @memberof Request + * @instance + * @returns {Object.} JSON object + */ + Request.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Request; +})(); + +$root.RemoteError = (function() { + + /** + * Properties of a RemoteError. + * @exports IRemoteError + * @interface IRemoteError + * @property {number|null} [messageIdentifier] RemoteError messageIdentifier + * @property {number|null} [errorCode] RemoteError errorCode + * @property {string|null} [errorMessage] RemoteError errorMessage + */ + + /** + * Constructs a new RemoteError. + * @exports RemoteError + * @classdesc Represents a RemoteError. + * @implements IRemoteError + * @constructor + * @param {IRemoteError=} [properties] Properties to set + */ + function RemoteError(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * RemoteError messageIdentifier. + * @member {number} messageIdentifier + * @memberof RemoteError + * @instance + */ + RemoteError.prototype.messageIdentifier = 0; + + /** + * RemoteError errorCode. + * @member {number} errorCode + * @memberof RemoteError + * @instance + */ + RemoteError.prototype.errorCode = 0; + + /** + * RemoteError errorMessage. + * @member {string} errorMessage + * @memberof RemoteError + * @instance + */ + RemoteError.prototype.errorMessage = ""; + + /** + * Creates a new RemoteError instance using the specified properties. + * @function create + * @memberof RemoteError + * @static + * @param {IRemoteError=} [properties] Properties to set + * @returns {RemoteError} RemoteError instance + */ + RemoteError.create = function create(properties) { + return new RemoteError(properties); + }; + + /** + * Encodes the specified RemoteError message. Does not implicitly {@link RemoteError.verify|verify} messages. + * @function encode + * @memberof RemoteError + * @static + * @param {IRemoteError} message RemoteError message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RemoteError.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.errorCode != null && Object.hasOwnProperty.call(message, "errorCode")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.errorCode); + if (message.errorMessage != null && Object.hasOwnProperty.call(message, "errorMessage")) + writer.uint32(/* id 3, wireType 2 =*/26).string(message.errorMessage); + return writer; + }; + + /** + * Encodes the specified RemoteError message, length delimited. Does not implicitly {@link RemoteError.verify|verify} messages. + * @function encodeDelimited + * @memberof RemoteError + * @static + * @param {IRemoteError} message RemoteError message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + RemoteError.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a RemoteError message from the specified reader or buffer. + * @function decode + * @memberof RemoteError + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {RemoteError} RemoteError + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RemoteError.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RemoteError(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.errorCode = reader.fixed32(); + break; + case 3: + message.errorMessage = reader.string(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a RemoteError message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof RemoteError + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {RemoteError} RemoteError + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + RemoteError.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a RemoteError message. + * @function verify + * @memberof RemoteError + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + RemoteError.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.errorCode != null && message.hasOwnProperty("errorCode")) + if (!$util.isInteger(message.errorCode)) + return "errorCode: integer expected"; + if (message.errorMessage != null && message.hasOwnProperty("errorMessage")) + if (!$util.isString(message.errorMessage)) + return "errorMessage: string expected"; + return null; + }; + + /** + * Creates a RemoteError message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof RemoteError + * @static + * @param {Object.} object Plain object + * @returns {RemoteError} RemoteError + */ + RemoteError.fromObject = function fromObject(object) { + if (object instanceof $root.RemoteError) + return object; + var message = new $root.RemoteError(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.errorCode != null) + message.errorCode = object.errorCode >>> 0; + if (object.errorMessage != null) + message.errorMessage = String(object.errorMessage); + return message; + }; + + /** + * Creates a plain object from a RemoteError message. Also converts values to other types if specified. + * @function toObject + * @memberof RemoteError + * @static + * @param {RemoteError} message RemoteError + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + RemoteError.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.errorCode = 0; + object.errorMessage = ""; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.errorCode != null && message.hasOwnProperty("errorCode")) + object.errorCode = message.errorCode; + if (message.errorMessage != null && message.hasOwnProperty("errorMessage")) + object.errorMessage = message.errorMessage; + return object; + }; + + /** + * Converts this RemoteError to JSON. + * @function toJSON + * @memberof RemoteError + * @instance + * @returns {Object.} JSON object + */ + RemoteError.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return RemoteError; +})(); + +$root.Response = (function() { + + /** + * Properties of a Response. + * @exports IResponse + * @interface IResponse + * @property {number|null} [messageIdentifier] Response messageIdentifier + * @property {Uint8Array|null} [payload] Response payload + */ + + /** + * Constructs a new Response. + * @exports Response + * @classdesc Represents a Response. + * @implements IResponse + * @constructor + * @param {IResponse=} [properties] Properties to set + */ + function Response(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Response messageIdentifier. + * @member {number} messageIdentifier + * @memberof Response + * @instance + */ + Response.prototype.messageIdentifier = 0; + + /** + * Response payload. + * @member {Uint8Array} payload + * @memberof Response + * @instance + */ + Response.prototype.payload = $util.newBuffer([]); + + /** + * Creates a new Response instance using the specified properties. + * @function create + * @memberof Response + * @static + * @param {IResponse=} [properties] Properties to set + * @returns {Response} Response instance + */ + Response.create = function create(properties) { + return new Response(properties); + }; + + /** + * Encodes the specified Response message. Does not implicitly {@link Response.verify|verify} messages. + * @function encode + * @memberof Response + * @static + * @param {IResponse} message Response message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Response.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.payload != null && Object.hasOwnProperty.call(message, "payload")) + writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.payload); + return writer; + }; + + /** + * Encodes the specified Response message, length delimited. Does not implicitly {@link Response.verify|verify} messages. + * @function encodeDelimited + * @memberof Response + * @static + * @param {IResponse} message Response message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Response.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a Response message from the specified reader or buffer. + * @function decode + * @memberof Response + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {Response} Response + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Response.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Response(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 6: + message.payload = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a Response message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof Response + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {Response} Response + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Response.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a Response message. + * @function verify + * @memberof Response + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Response.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.payload != null && message.hasOwnProperty("payload")) + if (!(message.payload && typeof message.payload.length === "number" || $util.isString(message.payload))) + return "payload: buffer expected"; + return null; + }; + + /** + * Creates a Response message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof Response + * @static + * @param {Object.} object Plain object + * @returns {Response} Response + */ + Response.fromObject = function fromObject(object) { + if (object instanceof $root.Response) + return object; + var message = new $root.Response(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.payload != null) + if (typeof object.payload === "string") + $util.base64.decode(object.payload, message.payload = $util.newBuffer($util.base64.length(object.payload)), 0); + else if (object.payload.length) + message.payload = object.payload; + return message; + }; + + /** + * Creates a plain object from a Response message. Also converts values to other types if specified. + * @function toObject + * @memberof Response + * @static + * @param {Response} message Response + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Response.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + if (options.bytes === String) + object.payload = ""; + else { + object.payload = []; + if (options.bytes !== Array) + object.payload = $util.newBuffer(object.payload); + } + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.payload != null && message.hasOwnProperty("payload")) + object.payload = options.bytes === String ? $util.base64.encode(message.payload, 0, message.payload.length) : options.bytes === Array ? Array.prototype.slice.call(message.payload) : message.payload; + return object; + }; + + /** + * Converts this Response to JSON. + * @function toJSON + * @memberof Response + * @instance + * @returns {Object.} JSON object + */ + Response.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Response; +})(); + +$root.StreamMessage = (function() { + + /** + * Properties of a StreamMessage. + * @exports IStreamMessage + * @interface IStreamMessage + * @property {number|null} [messageIdentifier] StreamMessage messageIdentifier + * @property {number|null} [portId] StreamMessage portId + * @property {number|null} [sequenceId] StreamMessage sequenceId + * @property {Uint8Array|null} [payload] StreamMessage payload + * @property {boolean|null} [closed] StreamMessage closed + * @property {boolean|null} [ack] StreamMessage ack + */ + + /** + * Constructs a new StreamMessage. + * @exports StreamMessage + * @classdesc Represents a StreamMessage. + * @implements IStreamMessage + * @constructor + * @param {IStreamMessage=} [properties] Properties to set + */ + function StreamMessage(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * StreamMessage messageIdentifier. + * @member {number} messageIdentifier + * @memberof StreamMessage + * @instance + */ + StreamMessage.prototype.messageIdentifier = 0; + + /** + * StreamMessage portId. + * @member {number} portId + * @memberof StreamMessage + * @instance + */ + StreamMessage.prototype.portId = 0; + + /** + * StreamMessage sequenceId. + * @member {number} sequenceId + * @memberof StreamMessage + * @instance + */ + StreamMessage.prototype.sequenceId = 0; + + /** + * StreamMessage payload. + * @member {Uint8Array} payload + * @memberof StreamMessage + * @instance + */ + StreamMessage.prototype.payload = $util.newBuffer([]); + + /** + * StreamMessage closed. + * @member {boolean} closed + * @memberof StreamMessage + * @instance + */ + StreamMessage.prototype.closed = false; + + /** + * StreamMessage ack. + * @member {boolean} ack + * @memberof StreamMessage + * @instance + */ + StreamMessage.prototype.ack = false; + + /** + * Creates a new StreamMessage instance using the specified properties. + * @function create + * @memberof StreamMessage + * @static + * @param {IStreamMessage=} [properties] Properties to set + * @returns {StreamMessage} StreamMessage instance + */ + StreamMessage.create = function create(properties) { + return new StreamMessage(properties); + }; + + /** + * Encodes the specified StreamMessage message. Does not implicitly {@link StreamMessage.verify|verify} messages. + * @function encode + * @memberof StreamMessage + * @static + * @param {IStreamMessage} message StreamMessage message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + StreamMessage.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) + writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); + if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) + writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); + if (message.sequenceId != null && Object.hasOwnProperty.call(message, "sequenceId")) + writer.uint32(/* id 4, wireType 5 =*/37).fixed32(message.sequenceId); + if (message.payload != null && Object.hasOwnProperty.call(message, "payload")) + writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.payload); + if (message.closed != null && Object.hasOwnProperty.call(message, "closed")) + writer.uint32(/* id 7, wireType 0 =*/56).bool(message.closed); + if (message.ack != null && Object.hasOwnProperty.call(message, "ack")) + writer.uint32(/* id 8, wireType 0 =*/64).bool(message.ack); + return writer; + }; + + /** + * Encodes the specified StreamMessage message, length delimited. Does not implicitly {@link StreamMessage.verify|verify} messages. + * @function encodeDelimited + * @memberof StreamMessage + * @static + * @param {IStreamMessage} message StreamMessage message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + StreamMessage.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a StreamMessage message from the specified reader or buffer. + * @function decode + * @memberof StreamMessage + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {StreamMessage} StreamMessage + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + StreamMessage.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.StreamMessage(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32(); + break; + case 2: + message.portId = reader.fixed32(); + break; + case 4: + message.sequenceId = reader.fixed32(); + break; + case 6: + message.payload = reader.bytes(); + break; + case 7: + message.closed = reader.bool(); + break; + case 8: + message.ack = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a StreamMessage message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof StreamMessage + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {StreamMessage} StreamMessage + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + StreamMessage.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a StreamMessage message. + * @function verify + * @memberof StreamMessage + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + StreamMessage.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + if (!$util.isInteger(message.messageIdentifier)) + return "messageIdentifier: integer expected"; + if (message.portId != null && message.hasOwnProperty("portId")) + if (!$util.isInteger(message.portId)) + return "portId: integer expected"; + if (message.sequenceId != null && message.hasOwnProperty("sequenceId")) + if (!$util.isInteger(message.sequenceId)) + return "sequenceId: integer expected"; + if (message.payload != null && message.hasOwnProperty("payload")) + if (!(message.payload && typeof message.payload.length === "number" || $util.isString(message.payload))) + return "payload: buffer expected"; + if (message.closed != null && message.hasOwnProperty("closed")) + if (typeof message.closed !== "boolean") + return "closed: boolean expected"; + if (message.ack != null && message.hasOwnProperty("ack")) + if (typeof message.ack !== "boolean") + return "ack: boolean expected"; + return null; + }; + + /** + * Creates a StreamMessage message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof StreamMessage + * @static + * @param {Object.} object Plain object + * @returns {StreamMessage} StreamMessage + */ + StreamMessage.fromObject = function fromObject(object) { + if (object instanceof $root.StreamMessage) + return object; + var message = new $root.StreamMessage(); + if (object.messageIdentifier != null) + message.messageIdentifier = object.messageIdentifier >>> 0; + if (object.portId != null) + message.portId = object.portId >>> 0; + if (object.sequenceId != null) + message.sequenceId = object.sequenceId >>> 0; + if (object.payload != null) + if (typeof object.payload === "string") + $util.base64.decode(object.payload, message.payload = $util.newBuffer($util.base64.length(object.payload)), 0); + else if (object.payload.length) + message.payload = object.payload; + if (object.closed != null) + message.closed = Boolean(object.closed); + if (object.ack != null) + message.ack = Boolean(object.ack); + return message; + }; + + /** + * Creates a plain object from a StreamMessage message. Also converts values to other types if specified. + * @function toObject + * @memberof StreamMessage + * @static + * @param {StreamMessage} message StreamMessage + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + StreamMessage.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.messageIdentifier = 0; + object.portId = 0; + object.sequenceId = 0; + if (options.bytes === String) + object.payload = ""; + else { + object.payload = []; + if (options.bytes !== Array) + object.payload = $util.newBuffer(object.payload); + } + object.closed = false; + object.ack = false; + } + if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) + object.messageIdentifier = message.messageIdentifier; + if (message.portId != null && message.hasOwnProperty("portId")) + object.portId = message.portId; + if (message.sequenceId != null && message.hasOwnProperty("sequenceId")) + object.sequenceId = message.sequenceId; + if (message.payload != null && message.hasOwnProperty("payload")) + object.payload = options.bytes === String ? $util.base64.encode(message.payload, 0, message.payload.length) : options.bytes === Array ? Array.prototype.slice.call(message.payload) : message.payload; + if (message.closed != null && message.hasOwnProperty("closed")) + object.closed = message.closed; + if (message.ack != null && message.hasOwnProperty("ack")) + object.ack = message.ack; + return object; + }; + + /** + * Converts this StreamMessage to JSON. + * @function toJSON + * @memberof StreamMessage + * @instance + * @returns {Object.} JSON object + */ + StreamMessage.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return StreamMessage; +})(); + +module.exports = $root; diff --git a/src/protocol/wire-protocol.ts b/src/protocol/wire-protocol.ts deleted file mode 100644 index 1c69663..0000000 --- a/src/protocol/wire-protocol.ts +++ /dev/null @@ -1,251 +0,0 @@ -// THIS FILE IS AUTOGENERATED -import * as e from '../encdec/encoding' -import * as d from '../encdec/decoding' -export type fixed32 = number - -function _readArray($: d.Decoder, reader: ($: d.Decoder) => T): Array { - const len = d.readUint32($); const ret: T[] = []; - for(let i = 0; i < len; i++) ret.push(reader($)); - return ret; -} -function _readString($: d.Decoder) { - return d.readVarString($); -} -function _readBytes($: d.Decoder): Uint8Array { - return d.readVarUint8Array($); -} -function _writeArray($: e.Encoder, writer: ($: e.Encoder, value: T) => void, array: T[]) { - e.writeUint32($, array.length); - for(let element of array) writer($, element); -} -function _writeString($: e.Encoder, value: string) { - e.writeVarString($, value); -} -function _writeBytes($: e.Encoder, value: Uint8Array) { - e.writeVarUint8Array($, value); -} -export type RpcMessageHeader = { - messageIdentifier: fixed32 -} - -export function writeRpcMessageHeader($: e.Encoder, value: RpcMessageHeader) { - e.writeUint32($, value["messageIdentifier"]); -} - -export function readRpcMessageHeader($: d.Decoder): RpcMessageHeader { - return { - messageIdentifier: d.readUint32($), - } -} - -export const enum RpcMessageTypes { - EMPTY = 0, - REQUEST = 1, - RESPONSE = 2, - STREAM_MESSAGE = 3, - STREAM_ACK = 4, - CREATE_PORT = 5, - CREATE_PORT_RESPONSE = 6, - REQUEST_MODULE = 7, - REQUEST_MODULE_RESPONSE = 8, - REMOTE_ERROR_RESPONSE = 9, - DESTROY_PORT = 10, - SERVER_READY = 11, -} - -export type CreatePort = { - messageIdentifier: fixed32 - portName: string -} - -export function writeCreatePort($: e.Encoder, value: CreatePort) { - e.writeUint32($, value["messageIdentifier"]); - _writeString($, value["portName"]); -} - -export function readCreatePort($: d.Decoder): CreatePort { - return { - messageIdentifier: d.readUint32($), - portName: _readString($), - } -} - -export type CreatePortResponse = { - messageIdentifier: fixed32 - portId: fixed32 -} - -export function writeCreatePortResponse($: e.Encoder, value: CreatePortResponse) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["portId"]); -} - -export function readCreatePortResponse($: d.Decoder): CreatePortResponse { - return { - messageIdentifier: d.readUint32($), - portId: d.readUint32($), - } -} - -export type RequestModule = { - messageIdentifier: fixed32 - portId: fixed32 - moduleName: string -} - -export function writeRequestModule($: e.Encoder, value: RequestModule) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["portId"]); - _writeString($, value["moduleName"]); -} - -export function readRequestModule($: d.Decoder): RequestModule { - return { - messageIdentifier: d.readUint32($), - portId: d.readUint32($), - moduleName: _readString($), - } -} - -export type RequestModuleResponse = { - messageIdentifier: fixed32 - portId: fixed32 - procedures: Array -} - -export function writeRequestModuleResponse($: e.Encoder, value: RequestModuleResponse) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["portId"]); - _writeArray($, ($, elem) => writeModuleProcedure($, elem), value["procedures"]); -} - -export function readRequestModuleResponse($: d.Decoder): RequestModuleResponse { - return { - messageIdentifier: d.readUint32($), - portId: d.readUint32($), - procedures: _readArray($, ($) => readModuleProcedure($)), - } -} - -export type DestroyPort = { - messageIdentifier: fixed32 - portId: fixed32 -} - -export function writeDestroyPort($: e.Encoder, value: DestroyPort) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["portId"]); -} - -export function readDestroyPort($: d.Decoder): DestroyPort { - return { - messageIdentifier: d.readUint32($), - portId: d.readUint32($), - } -} - -export type ModuleProcedure = { - procedureId: fixed32 - procedureName: string -} - -export function writeModuleProcedure($: e.Encoder, value: ModuleProcedure) { - e.writeUint32($, value["procedureId"]); - _writeString($, value["procedureName"]); -} - -export function readModuleProcedure($: d.Decoder): ModuleProcedure { - return { - procedureId: d.readUint32($), - procedureName: _readString($), - } -} - -export type Request = { - messageIdentifier: fixed32 - portId: fixed32 - procedureId: fixed32 - payload: Uint8Array -} - -export function writeRequest($: e.Encoder, value: Request) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["portId"]); - e.writeUint32($, value["procedureId"]); - _writeBytes($, value["payload"]); -} - -export function readRequest($: d.Decoder): Request { - return { - messageIdentifier: d.readUint32($), - portId: d.readUint32($), - procedureId: d.readUint32($), - payload: _readBytes($), - } -} - -export type RemoteError = { - messageIdentifier: fixed32 - errorCode: fixed32 - errorMessage: string -} - -export function writeRemoteError($: e.Encoder, value: RemoteError) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["errorCode"]); - _writeString($, value["errorMessage"]); -} - -export function readRemoteError($: d.Decoder): RemoteError { - return { - messageIdentifier: d.readUint32($), - errorCode: d.readUint32($), - errorMessage: _readString($), - } -} - -export type Response = { - messageIdentifier: fixed32 - payload: Uint8Array -} - -export function writeResponse($: e.Encoder, value: Response) { - e.writeUint32($, value["messageIdentifier"]); - _writeBytes($, value["payload"]); -} - -export function readResponse($: d.Decoder): Response { - return { - messageIdentifier: d.readUint32($), - payload: _readBytes($), - } -} - -export type StreamMessage = { - messageIdentifier: fixed32 - portId: fixed32 - sequenceId: fixed32 - payload: Uint8Array - closed: boolean - ack: boolean -} - -export function writeStreamMessage($: e.Encoder, value: StreamMessage) { - e.writeUint32($, value["messageIdentifier"]); - e.writeUint32($, value["portId"]); - e.writeUint32($, value["sequenceId"]); - _writeBytes($, value["payload"]); - e.writeUint8($, value["closed"] ? 1 : 0); - e.writeUint8($, value["ack"] ? 1 : 0); -} - -export function readStreamMessage($: d.Decoder): StreamMessage { - return { - messageIdentifier: d.readUint32($), - portId: d.readUint32($), - sequenceId: d.readUint32($), - payload: _readBytes($), - closed: d.readUint8($) != 0, - ack: d.readUint8($) != 0, - } -} diff --git a/src/server.ts b/src/server.ts index 0263556..935b925 100644 --- a/src/server.ts +++ b/src/server.ts @@ -8,27 +8,23 @@ import { Transport, } from "./types" import mitt from "mitt" +import { Writer, Reader } from "protobufjs" import { AsyncProcedureResultServer, RpcPortEvents, ServerModuleDeclaration } from "." import { AckDispatcher, createAckHelper } from "./ack-helper" import { calculateMessageIdentifier, closeStreamMessage, parseProtocolMessage } from "./protocol/helpers" import { CreatePort, + CreatePortResponse, DestroyPort, - ModuleProcedure, + RemoteError, Request, RequestModule, + RequestModuleResponse, Response, RpcMessageHeader, RpcMessageTypes, StreamMessage, - writeCreatePortResponse, - writeRemoteError, - writeRequestModuleResponse, - writeResponse, - writeRpcMessageHeader, -} from "./protocol/wire-protocol" -import { createEncoder, toUint8Array } from "./encdec/encoding" -import { createDecoder } from "./encdec/decoding" +} from "./protocol/pbjs" let lastPortId = 0 @@ -46,11 +42,14 @@ export type CreateRpcServerOptions = { } function getServerReadyMessage() { - const bb = createEncoder() - writeRpcMessageHeader(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.SERVER_READY, 0), - }) - return toUint8Array(bb) + const bb = new Writer() + RpcMessageHeader.encode( + { + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_SERVER_READY, 0), + }, + bb + ) + return bb.finish() } const transportStartMessageSerialized = getServerReadyMessage() @@ -168,12 +167,18 @@ export async function handleCreatePort( await options.initializePort(port, transport) - const bb = createEncoder() - writeCreatePortResponse(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.CREATE_PORT_RESPONSE, messageNumber), - portId: port.portId, - }) - transport.sendMessage(toUint8Array(bb)) + const bb = new Writer() + CreatePortResponse.encode( + { + messageIdentifier: calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE, + messageNumber + ), + portId: port.portId, + }, + bb + ) + transport.sendMessage(bb.finish()) return port } @@ -193,13 +198,19 @@ export async function handleRequestModule( const loadedModule = await port.loadModule(requestModule.moduleName) - const bb = createEncoder() - writeRequestModuleResponse(bb, { - procedures: loadedModule.procedures, - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REQUEST_MODULE_RESPONSE, messageNumber), - portId: port.portId, - }) - transport.sendMessage(toUint8Array(bb)) + const bb = new Writer() + RequestModuleResponse.encode( + { + procedures: loadedModule.procedures, + messageIdentifier: calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE, + messageNumber + ), + portId: port.portId, + }, + bb + ) + transport.sendMessage(bb.finish()) } // @internal @@ -221,58 +232,68 @@ export async function handleRequest( ackDispatcher: AckDispatcher, request: Request, messageNumber: number, - state: RpcServerState + state: RpcServerState, + transport: Transport ) { - const port = getPortFromState(request.portId, ackDispatcher.transport, state) + const port = getPortFromState(request.portId, transport, state) if (!port) { - const bb = createEncoder() - writeRemoteError(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REMOTE_ERROR_RESPONSE, messageNumber), - errorCode: 0, - errorMessage: "invalid portId", - }) - ackDispatcher.transport.sendMessage(toUint8Array(bb)) + const bb = new Writer() + RemoteError.encode( + { + messageIdentifier: calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE, + messageNumber + ), + errorCode: 0, + errorMessage: "invalid portId", + }, + bb + ) + transport.sendMessage(bb.finish()) return } const result = await port.callProcedure(request.procedureId, request.payload) - const response: Response = { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RESPONSE, messageNumber), + const response = Response.create({ + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_RESPONSE, messageNumber), payload: Uint8Array.from([]), - } + }) if (result instanceof Uint8Array) { response.payload = result - const bb = createEncoder() - writeResponse(bb, response) - ackDispatcher.transport.sendMessage(toUint8Array(bb)) + const bb = new Writer() + Response.encode(response, bb) + transport.sendMessage(bb.finish()) } else if (result && Symbol.asyncIterator in result) { const iter: AsyncGenerator = await (result as any)[Symbol.asyncIterator]() let sequenceNumber = -1 - const reusedStreamMessage: StreamMessage = { + const reusedStreamMessage: StreamMessage = StreamMessage.create({ closed: false, ack: false, sequenceId: 0, messageIdentifier: 0, payload: Uint8Array.of(), portId: request.portId, - } + }) for await (const elem of iter) { sequenceNumber++ reusedStreamMessage.closed = false reusedStreamMessage.ack = false reusedStreamMessage.sequenceId = sequenceNumber - reusedStreamMessage.messageIdentifier = calculateMessageIdentifier(RpcMessageTypes.STREAM_MESSAGE, messageNumber) + reusedStreamMessage.messageIdentifier = calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE, + messageNumber + ) reusedStreamMessage.payload = elem reusedStreamMessage.portId = request.portId // we use Promise.race to react to the transport close events const ret = await Promise.race([ ackDispatcher.sendWithAck(reusedStreamMessage), new Promise((_, reject) => - ackDispatcher.transport.on("close", () => reject(new Error("Transport closed while sending stream"))) + transport.on("close", () => reject(new Error("Transport closed while sending stream"))) ), ]) @@ -283,11 +304,11 @@ export async function handleRequest( return } } - ackDispatcher.transport.sendMessage(closeStreamMessage(messageNumber, sequenceNumber, request.portId)) + transport.sendMessage(closeStreamMessage(messageNumber, sequenceNumber, request.portId)) } else { - const bb = createEncoder() - writeResponse(bb, response) - ackDispatcher.transport.sendMessage(toUint8Array(bb)) + const bb = new Writer() + Response.encode(response, bb) + transport.sendMessage(bb.finish()) } } @@ -333,17 +354,20 @@ export function createRpcServer(options: CreateRpcServerOptions): RpcServer { transport: Transport, ackHelper: AckDispatcher ) { - if (messageType == RpcMessageTypes.REQUEST) { - await handleRequest(ackHelper, parsedMessage, messageNumber, state) - } else if (messageType == RpcMessageTypes.REQUEST_MODULE) { + if (messageType == RpcMessageTypes.RpcMessageTypes_REQUEST) { + await handleRequest(ackHelper, parsedMessage, messageNumber, state, transport) + } else if (messageType == RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE) { await handleRequestModule(transport, parsedMessage, messageNumber, state) - } else if (messageType == RpcMessageTypes.CREATE_PORT) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_CREATE_PORT) { const port = await handleCreatePort(transport, parsedMessage, messageNumber, options, state) port.on("close", () => events.emit("portClosed", { port })) - } else if (messageType == RpcMessageTypes.DESTROY_PORT) { + } else if (messageType == RpcMessageTypes.RpcMessageTypes_DESTROY_PORT) { await handleDestroyPort(transport, parsedMessage, messageNumber, state) - } else if (messageType == RpcMessageTypes.STREAM_ACK) { - // noop + } else if ( + messageType == RpcMessageTypes.RpcMessageTypes_STREAM_ACK || + messageType == RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE + ) { + await ackHelper.receiveAck(parsedMessage, messageNumber) } else { transport.emit( "error", @@ -358,23 +382,33 @@ export function createRpcServer(options: CreateRpcServerOptions): RpcServer { state.transports.add(newTransport) const ackHelper = createAckHelper(newTransport) newTransport.on("message", async (message) => { - const reader = createDecoder(message) - const parsedMessage = parseProtocolMessage(reader) - if (parsedMessage) { - const [messageType, message, messageNumber] = parsedMessage - try { - await handleMessage(messageType, message, messageNumber, newTransport, ackHelper) - } catch (err: any) { - const bb = createEncoder() - writeRemoteError(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.REMOTE_ERROR_RESPONSE, messageNumber), - errorMessage: err.message || "Error processing the request", - errorCode: 0, - }) - newTransport.sendMessage(toUint8Array(bb)) + try { + const reader = Reader.create(message) + const parsedMessage = parseProtocolMessage(reader) + if (parsedMessage) { + const [messageType, message, messageNumber] = parsedMessage + try { + await handleMessage(messageType, message, messageNumber, newTransport, ackHelper) + } catch (err: any) { + const bb = new Writer() + RemoteError.encode( + { + messageIdentifier: calculateMessageIdentifier( + RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE, + messageNumber + ), + errorMessage: err.message || "Error processing the request", + errorCode: 0, + }, + bb + ) + newTransport.sendMessage(bb.finish()) + } + } else { + newTransport.emit("error", new Error(`Unknown message ${message}`)) } - } else { - newTransport.emit("error", new Error(`Unknown message ${message}`)) + } catch (err: any) { + newTransport.emit("error", err) } }) diff --git a/src/transports/Memory.ts b/src/transports/Memory.ts index 6ef371b..5e16ab5 100644 --- a/src/transports/Memory.ts +++ b/src/transports/Memory.ts @@ -6,13 +6,17 @@ export function MemoryTransport() { const serverEd = mitt() function configureMemoryTransport(receiver: Emitter, sender: Emitter): Transport { + let isClosed = false return { ...sender, sendMessage(message) { receiver.emit("message", new Uint8Array(message)) }, close() { - sender.emit("close", {}) + if (!isClosed) { + isClosed = true + sender.emit("close", {}) + } }, } } @@ -29,6 +33,7 @@ export function MemoryTransport() { }) server.on("close", () => client.close()) + client.on("close", () => server.close()) return { client, diff --git a/test/close-transport.spec.ts b/test/close-transport.spec.ts index 7fe993e..20f2bfc 100644 --- a/test/close-transport.spec.ts +++ b/test/close-transport.spec.ts @@ -1,7 +1,6 @@ import { RpcClient } from "../src" -import { createEncoder, toUint8Array } from "../src/encdec/encoding" import { calculateMessageIdentifier } from "../src/protocol/helpers" -import { RpcMessageTypes, writeRpcMessageHeader } from "../src/protocol/wire-protocol" +import { RpcMessageHeader, RpcMessageTypes } from "../src/protocol/pbjs" import { createSimpleTestEnvironment } from "./helpers" async function testPort(rpcClient: RpcClient, portName: string) { @@ -92,18 +91,18 @@ describe("Error in transport finalizes streams", () => { }) describe("Close transport closes streams (client side)", () => { - let infiniteStreamClosed = false + let infiniteStreamClosed = 0 const testEnv = createSimpleTestEnvironment({ async initializePort(port) { port.registerModule("echo", async (port) => ({ async *infinite() { try { - infiniteStreamClosed = false + infiniteStreamClosed = 1 while (true) { yield Uint8Array.from([1]) } } finally { - infiniteStreamClosed = true + infiniteStreamClosed = 2 } }, })) @@ -115,11 +114,12 @@ describe("Close transport closes streams (client side)", () => { const { infinite } = await testPort(rpcClient, "port1") - expect(infiniteStreamClosed).toEqual(false) + expect(infiniteStreamClosed).toEqual(0) let count = 0 await expect(async () => { for await (const _ of await infinite()) { + expect(infiniteStreamClosed).toEqual(1) if (count++ == 10) { transportClient.close() } @@ -127,7 +127,7 @@ describe("Close transport closes streams (client side)", () => { }).rejects.toThrow("RPC Transport closed") // the server AsyncGenerators must be closed after the transport is closed to avoid leaks - expect(infiniteStreamClosed).toEqual(true) + expect(infiniteStreamClosed).toEqual(2) }) }) @@ -190,7 +190,7 @@ async function setupForFailures() { function logEvent(evt: string) { events.push(evt) - process.stderr.write(evt + '\n') + process.stderr.write(evt + "\n") } transportServer.on("close", () => logEvent("transport: close")) @@ -217,11 +217,13 @@ describe("Unknown packets in the network close the transport", () => { const { events, transportServer } = await setupForFailures() // sending invalid packages should raise an error - const bb = createEncoder() - writeRpcMessageHeader(bb, { - messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.CREATE_PORT_RESPONSE, 0), - }) - transportServer.emit("message", toUint8Array(bb)) + + transportServer.emit( + "message", + RpcMessageHeader.encode({ + messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE, 0), + }).finish() + ) expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) }) @@ -229,17 +231,26 @@ describe("Unknown packets in the network close the transport", () => { const { events, transportServer } = await setupForFailures() // sending invalid packages should raise an error - const bb = createEncoder() - writeRpcMessageHeader(bb, { - messageIdentifier: calculateMessageIdentifier(0xfff, 0), - }) - transportServer.emit("message", toUint8Array(bb)) + transportServer.emit( + "message", + RpcMessageHeader.encode({ + messageIdentifier: calculateMessageIdentifier(0xfff, 0), + }).finish() + ) expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) }) it("disconnects the transport under unknown messages", async () => { const { events, transportServer } = await setupForFailures() + // sending random things should not break anything + transportServer.emit("message", Uint8Array.from([128, 109])) + expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) + }) + + it("disconnects the transport under unknown messages 2", async () => { + const { events, transportServer } = await setupForFailures() + // sending random things should not break anything transportServer.emit("message", Uint8Array.from([8, 109])) expect(events).toEqual(["rpc: transportError", "rpc: transportClosed", "transport: close", "transport: error"]) diff --git a/test/helpers.ts b/test/helpers.ts index dc20838..d60b71e 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -3,7 +3,7 @@ import { log } from "./logger" import { inspect } from "util" import { MemoryTransport } from "../src/transports/Memory" import { parseProtocolMessage } from "../src/protocol/helpers" -import { createDecoder } from "../src/encdec/decoding" +import { Reader } from "protobufjs" // async Array.from(generator*) with support for max elements export async function takeAsync(iter: AsyncGenerator, max?: number) { @@ -23,7 +23,7 @@ export function instrumentTransport(memoryTransport: ReturnType Creating memory transport") function serialize(data: Uint8Array) { - const ret = parseProtocolMessage(createDecoder(data)) + const ret = parseProtocolMessage(Reader.create(data)) if (!ret) return inspect(data) return ret[1] } @@ -50,6 +50,7 @@ export function instrumentTransport(memoryTransport: ReturnType { log(" (server error): " + data) }) + server.on("message", (data) => { try { log(" (wire client->server): " + JSON.stringify(serialize(data))) @@ -75,6 +76,10 @@ export function createSimpleTestEnvironment(options: CreateRpcServerOptions) { memoryTransport.client.on("close", () => (clientClosed = true)) memoryTransport.server.on("close", () => (serverClosed = true)) + rpcServer.on("transportError", (data) => { + log(" (server transportError): " + inspect(data)) + }) + if (serverClosed) throw new Error("This server is already closed. Use a new testing environment") log("> Creating RPC Client") setImmediate(() => rpcServer.attachTransport(memoryTransport.server)) diff --git a/test/stream-from-dispatcher.spec.ts b/test/stream-from-dispatcher.spec.ts index 08cd7be..30d07d7 100644 --- a/test/stream-from-dispatcher.spec.ts +++ b/test/stream-from-dispatcher.spec.ts @@ -1,10 +1,10 @@ import { streamFromDispatcher } from "../src/client" -import { createDecoder } from "../src/encdec/decoding" +import { Reader } from "protobufjs" import { messageNumberHandler } from "../src/message-number-handler" import { closeStreamMessage, streamMessage } from "../src/protocol/helpers" -import { readStreamMessage } from "../src/protocol/wire-protocol" import { MemoryTransport } from "../src/transports/Memory" import { instrumentTransport, takeAsync } from "./helpers" +import { StreamMessage } from "../src/protocol/pbjs" describe("streamFromDispatcher", () => { it("a CloseMessage from the server closes the iterator in the client", async () => { @@ -15,7 +15,7 @@ describe("streamFromDispatcher", () => { const removeListenerSpy = jest.spyOn(dispatcher, "removeListener") const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array()))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array())), MESSAGE_NUMBER ) @@ -36,7 +36,7 @@ describe("streamFromDispatcher", () => { const addListenerSpy = jest.spyOn(dispatcher, "addListener") const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array()))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array())), MESSAGE_NUMBER ) @@ -58,7 +58,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array()))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, new Uint8Array())), MESSAGE_NUMBER ) @@ -78,7 +78,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, 0, 0, PAYLOAD))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, 0, 0, PAYLOAD)), MESSAGE_NUMBER ) @@ -98,7 +98,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD)), MESSAGE_NUMBER ) @@ -116,7 +116,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, PAYLOAD)), MESSAGE_NUMBER ) transport.server.sendMessage(closeStreamMessage(MESSAGE_NUMBER, seq++, 0)) @@ -131,7 +131,7 @@ describe("streamFromDispatcher", () => { const dispatcher = messageNumberHandler(transport.client) const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1])))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1]))), MESSAGE_NUMBER ) @@ -153,7 +153,7 @@ describe("streamFromDispatcher", () => { const removeListenerSpy = jest.spyOn(dispatcher, "removeListener") const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1])))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1]))), MESSAGE_NUMBER ) @@ -180,7 +180,7 @@ describe("streamFromDispatcher", () => { const removeListenerSpy = jest.spyOn(dispatcher, "removeListener") const stream = streamFromDispatcher( dispatcher, - readStreamMessage(createDecoder(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1])))), + StreamMessage.decode(streamMessage(MESSAGE_NUMBER, seq++, 0, Uint8Array.from([1]))), MESSAGE_NUMBER ) From a9d4e1eeb18cc6c60be07f42e8b07311bce98a95 Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:10:52 -0300 Subject: [PATCH 04/11] before ts-proto --- src/server.ts | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/server.ts b/src/server.ts index 935b925..8763027 100644 --- a/src/server.ts +++ b/src/server.ts @@ -41,15 +41,18 @@ export type CreateRpcServerOptions = { initializePort: (serverPort: RpcServerPort, transport: Transport) => Promise } +// only use this writer in synchronous operations. It exists to prevent allocations +const unsafeSyncWriter = new Writer() + function getServerReadyMessage() { - const bb = new Writer() + unsafeSyncWriter.reset() RpcMessageHeader.encode( { messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_SERVER_READY, 0), }, - bb + unsafeSyncWriter ) - return bb.finish() + return unsafeSyncWriter.finish() } const transportStartMessageSerialized = getServerReadyMessage() @@ -167,7 +170,7 @@ export async function handleCreatePort( await options.initializePort(port, transport) - const bb = new Writer() + unsafeSyncWriter.reset() CreatePortResponse.encode( { messageIdentifier: calculateMessageIdentifier( @@ -176,9 +179,9 @@ export async function handleCreatePort( ), portId: port.portId, }, - bb + unsafeSyncWriter ) - transport.sendMessage(bb.finish()) + transport.sendMessage(unsafeSyncWriter.finish()) return port } @@ -198,7 +201,7 @@ export async function handleRequestModule( const loadedModule = await port.loadModule(requestModule.moduleName) - const bb = new Writer() + unsafeSyncWriter.reset() RequestModuleResponse.encode( { procedures: loadedModule.procedures, @@ -208,9 +211,9 @@ export async function handleRequestModule( ), portId: port.portId, }, - bb + unsafeSyncWriter ) - transport.sendMessage(bb.finish()) + transport.sendMessage(unsafeSyncWriter.finish()) } // @internal @@ -238,7 +241,7 @@ export async function handleRequest( const port = getPortFromState(request.portId, transport, state) if (!port) { - const bb = new Writer() + unsafeSyncWriter.reset() RemoteError.encode( { messageIdentifier: calculateMessageIdentifier( @@ -248,9 +251,9 @@ export async function handleRequest( errorCode: 0, errorMessage: "invalid portId", }, - bb + unsafeSyncWriter ) - transport.sendMessage(bb.finish()) + transport.sendMessage(unsafeSyncWriter.finish()) return } @@ -262,9 +265,9 @@ export async function handleRequest( if (result instanceof Uint8Array) { response.payload = result - const bb = new Writer() - Response.encode(response, bb) - transport.sendMessage(bb.finish()) + unsafeSyncWriter.reset() + Response.encode(response, unsafeSyncWriter) + transport.sendMessage(unsafeSyncWriter.finish()) } else if (result && Symbol.asyncIterator in result) { const iter: AsyncGenerator = await (result as any)[Symbol.asyncIterator]() let sequenceNumber = -1 @@ -306,9 +309,9 @@ export async function handleRequest( } transport.sendMessage(closeStreamMessage(messageNumber, sequenceNumber, request.portId)) } else { - const bb = new Writer() - Response.encode(response, bb) - transport.sendMessage(bb.finish()) + unsafeSyncWriter.reset() + Response.encode(response, unsafeSyncWriter) + transport.sendMessage(unsafeSyncWriter.finish()) } } @@ -390,7 +393,7 @@ export function createRpcServer(options: CreateRpcServerOptions): RpcServer { try { await handleMessage(messageType, message, messageNumber, newTransport, ackHelper) } catch (err: any) { - const bb = new Writer() + unsafeSyncWriter.reset() RemoteError.encode( { messageIdentifier: calculateMessageIdentifier( @@ -400,9 +403,9 @@ export function createRpcServer(options: CreateRpcServerOptions): RpcServer { errorMessage: err.message || "Error processing the request", errorCode: 0, }, - bb + unsafeSyncWriter ) - newTransport.sendMessage(bb.finish()) + newTransport.sendMessage(unsafeSyncWriter.finish()) } } else { newTransport.emit("error", new Error(`Unknown message ${message}`)) From 24d3590460b5606f5b15c0f999f5be0cafd14a40 Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:11:05 -0300 Subject: [PATCH 05/11] ts-proto --- .vscode/configurationCache.log | 1 + .vscode/dryrun.log | 16 + .vscode/targets.log | 325 ++++ Makefile | 18 +- package-lock.json | 143 +- package.json | 4 +- src/ack-helper.ts | 4 +- src/client.ts | 4 +- src/codegen.ts | 61 +- src/message-number-handler.ts | 4 +- src/protocol/helpers.ts | 4 +- src/protocol/index.ts | 939 ++++++++++ src/protocol/pbjs.d.ts | 993 ----------- src/protocol/pbjs.js | 2580 --------------------------- src/server.ts | 8 +- test/bench.ts | 45 +- test/close-transport.spec.ts | 2 +- test/codegen-client.spec.ts | 63 +- test/codegen-server.spec.ts | 59 +- test/codegen/client.ts | 228 +++ test/helpers.ts | 2 +- test/stream-from-dispatcher.spec.ts | 3 +- 22 files changed, 1752 insertions(+), 3754 deletions(-) create mode 100644 .vscode/configurationCache.log create mode 100644 .vscode/dryrun.log create mode 100644 .vscode/targets.log create mode 100644 src/protocol/index.ts delete mode 100644 src/protocol/pbjs.d.ts delete mode 100644 src/protocol/pbjs.js create mode 100644 test/codegen/client.ts diff --git a/.vscode/configurationCache.log b/.vscode/configurationCache.log new file mode 100644 index 0000000..45bdb03 --- /dev/null +++ b/.vscode/configurationCache.log @@ -0,0 +1 @@ +{"buildTargets":["build","cheap-perf","install","install_compiler","test","test-watch"],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}} \ No newline at end of file diff --git a/.vscode/dryrun.log b/.vscode/dryrun.log new file mode 100644 index 0000000..bc2c2d7 --- /dev/null +++ b/.vscode/dryrun.log @@ -0,0 +1,16 @@ +make --dry-run --always-make --keep-going --print-directory +make: Entering directory '/Users/user/code/rpc' + +# remove local folder +rm -rf protoc3 || true +# Make sure you grab the latest version +curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-osx-x86_64.zip +# Unzip +unzip protoc-3.19.1-osx-x86_64.zip -d protoc3 +# delete the files + +rm protoc-3.19.1-osx-x86_64.zip +# move protoc to /usr/local/bin/ +chmod +x protoc3/bin/protoc +make: Leaving directory '/Users/user/code/rpc' + diff --git a/.vscode/targets.log b/.vscode/targets.log new file mode 100644 index 0000000..6bdb509 --- /dev/null +++ b/.vscode/targets.log @@ -0,0 +1,325 @@ +make all --print-data-base --no-builtin-variables --no-builtin-rules --question +make: *** No rule to make target 'all'. Stop. + +# GNU Make 4.3 +# Built for arm-apple-darwin21.1.0 +# Copyright (C) 1988-2020 Free Software Foundation, Inc. +# License GPLv3+: GNU GPL version 3 or later +# This is free software: you are free to change and redistribute it. +# There is NO WARRANTY, to the extent permitted by law. + +# Make data base, printed on Wed May 11 06:42:57 2022 + +# Variables + +# environment +LC_ALL = C +# makefile (from 'Makefile', line 12) +PROTOBUF_ZIP = protoc-$(PROTOBUF_VERSION)-osx-x86_64.zip +# environment +TMPDIR = /var/folders/rq/86b2x9jx0_9btt86hnrp_7qm0000gn/T/ +# environment +XPC_SERVICE_NAME = application.com.microsoft.VSCode.17573896.17573902 +# environment +VSCODE_IPC_HOOK_EXTHOST = /var/folders/rq/86b2x9jx0_9btt86hnrp_7qm0000gn/T/vscode-ipc-c77f692a-850b-413d-8238-a2e3d7bac622.sock +# environment +VSCODE_CWD = / +# environment +GPG_TTY = not a tty +# environment +NVM_DIR = /Users/user/.nvm +# default +MAKE_COMMAND := make +# environment +GOPATH = /Users/user/go +# environment +__CFBundleIdentifier = com.microsoft.VSCode +# automatic +@D = $(patsubst %/,%,$(dir $@)) +# environment +VSCODE_HANDLES_UNCAUGHT_ERRORS = true +# default +.VARIABLES := +# environment +COMMAND_MODE = unix2003 +# environment +PWD = /Users/user/code/rpc +# automatic +%D = $(patsubst %/,%,$(dir $%)) +# environment +LSCOLORS = Gxfxcxdxbxegedabagacad +# environment +OLDPWD = /Users/user/code/rpc +# automatic +^D = $(patsubst %/,%,$(dir $^)) +# environment +VSCODE_LOG_STACK = false +# automatic +%F = $(notdir $%) +# environment +VSCODE_CODE_CACHE_PATH = /Users/user/Library/Application Support/Code/CachedData/57fd6d0195bb9b9d1b49f6da5db789060795de47 +# environment +MZ_ADDONS = +# environment +LANG = C +# default +.LOADED := +# default +.INCLUDE_DIRS = /opt/homebrew/Cellar/make/4.3/include /usr/local/include +# environment +__CF_USER_TEXT_ENCODING = 0x1F5:0x0:0x0 +# makefile +MAKEFLAGS = pqrR +# makefile +CURDIR := /Users/user/code/rpc +# makefile (from 'Makefile', line 3) +UNAME := Darwin +# environment +VSCODE_PIPE_LOGGING = true +# environment +APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL = true +# automatic +*D = $(patsubst %/,%,$(dir $*)) +# environment +MFLAGS = -pqrR +# environment +SSH_AUTH_SOCK = /Users/user/.gnupg/S.gpg-agent.ssh +# default +.SHELLFLAGS := -c +# automatic ++D = $(patsubst %/,%,$(dir $+)) +# environment +GPG_KEY = 0x78AC067F75AC1B64 +# makefile (from 'Makefile', line 1) +MAKEFILE_LIST := Makefile +# automatic +@F = $(notdir $@) +# environment +ZSH = /Users/user/.oh-my-zsh +# environment +VSCODE_VERBOSE_LOGGING = true +# environment +VSCODE_PID = 39542 +# automatic +?D = $(patsubst %/,%,$(dir $?)) +# environment +FZF_DEFAULT_COMMAND = rg --files --hidden --glob '!**/.git/*' --glob '!**/node_modules/*' +# makefile (from 'Makefile', line 1) +PROTOBUF_VERSION = 3.19.1 +# automatic +*F = $(notdir $*) +# makefile (from 'Makefile', line 2) +PROTOC = protoc +# automatic +> ./src/protocol/index_pb.js @cp -r src/protocol dist/protocol ./node_modules/.bin/tsc -p tsconfig.json rm -rf node_modules/@microsoft/api-extractor/node_modules/typescript || true diff --git a/package-lock.json b/package-lock.json index 7a8dc7c..32e33e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,10 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@types/google-protobuf": "^3.15.5", "camelcase": "^6.3.0", - "google-protobuf": "^3.19.1", "mitt": "^3.0.0", "pascalcase": "^2.0.0", - "protobufjs": "^6.11.2" + "ts-proto": "^1.112.1" }, "devDependencies": { "@microsoft/api-extractor": "^7.17.0", @@ -1156,11 +1154,6 @@ "@babel/types": "^7.3.0" } }, - "node_modules/@types/google-protobuf": { - "version": "3.15.5", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", - "integrity": "sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==" - }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1215,6 +1208,11 @@ "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", "dev": true }, + "node_modules/@types/object-hash": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz", + "integrity": "sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA==" + }, "node_modules/@types/prettier": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", @@ -1810,6 +1808,11 @@ "node": ">=10" } }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==" + }, "node_modules/debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -2244,7 +2247,8 @@ "node_modules/google-protobuf": { "version": "3.19.1", "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.19.1.tgz", - "integrity": "sha512-Isv1RlNC+IzZzilcxnlVSf+JvuhxmY7DaxYCBy+zPS9XVuJRtlTTIXR9hnZ1YL1MMusJn/7eSy2swCzZIomQSg==" + "integrity": "sha512-Isv1RlNC+IzZzilcxnlVSf+JvuhxmY7DaxYCBy+zPS9XVuJRtlTTIXR9hnZ1YL1MMusJn/7eSy2swCzZIomQSg==", + "dev": true }, "node_modules/graceful-fs": { "version": "4.2.8", @@ -3315,8 +3319,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.get": { "version": "4.4.2", @@ -3515,6 +3518,14 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "node_modules/object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3696,6 +3707,20 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-format": { "version": "27.4.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", @@ -4287,6 +4312,40 @@ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, + "node_modules/ts-poet": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-4.11.0.tgz", + "integrity": "sha512-OaXnCKsRs0yrc0O7LFhnq/US2DB4Wd313cS+qjG2XMksZ74pF/jvMHkJdURXJiAo4kSahL2N4e8JOdwUjOMNdw==", + "dependencies": { + "lodash": "^4.17.15", + "prettier": "^2.5.1" + } + }, + "node_modules/ts-proto": { + "version": "1.112.1", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.112.1.tgz", + "integrity": "sha512-pMqPsgehCR5lNHYrSCfaC7Vx5RXLxTk0MQFvC69+9E4x6yvAed3orCLAWZ1VvPug02bBK5J5vV8JJLS3+FnnUA==", + "dependencies": { + "@types/object-hash": "^1.3.0", + "dataloader": "^1.4.0", + "object-hash": "^1.3.1", + "protobufjs": "^6.8.8", + "ts-poet": "^4.11.0", + "ts-proto-descriptors": "1.6.0" + }, + "bin": { + "protoc-gen-ts_proto": "protoc-gen-ts_proto" + } + }, + "node_modules/ts-proto-descriptors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.6.0.tgz", + "integrity": "sha512-Vrhue2Ti99us/o76mGy28nF3W/Uanl1/8detyJw2yyRwiBC5yxy+hEZqQ/ZX2PbZ1vyCpJ51A9L4PnCCnkBMTQ==", + "dependencies": { + "long": "^4.0.0", + "protobufjs": "^6.8.8" + } + }, "node_modules/ts-protoc-gen": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/ts-protoc-gen/-/ts-protoc-gen-0.15.0.tgz", @@ -5557,11 +5616,6 @@ "@babel/types": "^7.3.0" } }, - "@types/google-protobuf": { - "version": "3.15.5", - "resolved": "https://registry.npmjs.org/@types/google-protobuf/-/google-protobuf-3.15.5.tgz", - "integrity": "sha512-6bgv24B+A2bo9AfzReeg5StdiijKzwwnRflA8RLd1V4Yv995LeTmo0z69/MPbBDFSiZWdZHQygLo/ccXhMEDgw==" - }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -5616,6 +5670,11 @@ "integrity": "sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ==", "dev": true }, + "@types/object-hash": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz", + "integrity": "sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA==" + }, "@types/prettier": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", @@ -6090,6 +6149,11 @@ "whatwg-url": "^8.0.0" } }, + "dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==" + }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", @@ -6404,7 +6468,8 @@ "google-protobuf": { "version": "3.19.1", "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.19.1.tgz", - "integrity": "sha512-Isv1RlNC+IzZzilcxnlVSf+JvuhxmY7DaxYCBy+zPS9XVuJRtlTTIXR9hnZ1YL1MMusJn/7eSy2swCzZIomQSg==" + "integrity": "sha512-Isv1RlNC+IzZzilcxnlVSf+JvuhxmY7DaxYCBy+zPS9XVuJRtlTTIXR9hnZ1YL1MMusJn/7eSy2swCzZIomQSg==", + "dev": true }, "graceful-fs": { "version": "4.2.8", @@ -7236,8 +7301,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.get": { "version": "4.4.2", @@ -7405,6 +7469,11 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, + "object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -7538,6 +7607,11 @@ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "prettier": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==" + }, "pretty-format": { "version": "27.4.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", @@ -7961,6 +8035,37 @@ } } }, + "ts-poet": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-4.11.0.tgz", + "integrity": "sha512-OaXnCKsRs0yrc0O7LFhnq/US2DB4Wd313cS+qjG2XMksZ74pF/jvMHkJdURXJiAo4kSahL2N4e8JOdwUjOMNdw==", + "requires": { + "lodash": "^4.17.15", + "prettier": "^2.5.1" + } + }, + "ts-proto": { + "version": "1.112.1", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-1.112.1.tgz", + "integrity": "sha512-pMqPsgehCR5lNHYrSCfaC7Vx5RXLxTk0MQFvC69+9E4x6yvAed3orCLAWZ1VvPug02bBK5J5vV8JJLS3+FnnUA==", + "requires": { + "@types/object-hash": "^1.3.0", + "dataloader": "^1.4.0", + "object-hash": "^1.3.1", + "protobufjs": "^6.8.8", + "ts-poet": "^4.11.0", + "ts-proto-descriptors": "1.6.0" + } + }, + "ts-proto-descriptors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-1.6.0.tgz", + "integrity": "sha512-Vrhue2Ti99us/o76mGy28nF3W/Uanl1/8detyJw2yyRwiBC5yxy+hEZqQ/ZX2PbZ1vyCpJ51A9L4PnCCnkBMTQ==", + "requires": { + "long": "^4.0.0", + "protobufjs": "^6.8.8" + } + }, "ts-protoc-gen": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/ts-protoc-gen/-/ts-protoc-gen-0.15.0.tgz", diff --git a/package.json b/package.json index 271a5a8..cfc3c6f 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,9 @@ "dist" ], "dependencies": { - "@types/google-protobuf": "^3.15.5", "camelcase": "^6.3.0", - "google-protobuf": "^3.19.1", "mitt": "^3.0.0", "pascalcase": "^2.0.0", - "protobufjs": "^6.11.2" + "ts-proto": "^1.112.1" } } diff --git a/src/ack-helper.ts b/src/ack-helper.ts index e809fba..ed95e78 100644 --- a/src/ack-helper.ts +++ b/src/ack-helper.ts @@ -1,7 +1,7 @@ -import { Writer } from "protobufjs" +import { Writer } from "protobufjs/minimal" import { Transport } from "./types" import { parseMessageIdentifier } from "./protocol/helpers" -import { StreamMessage } from "./protocol/pbjs" +import { StreamMessage } from "./protocol" export type AckDispatcher = { sendWithAck(data: StreamMessage): Promise diff --git a/src/client.ts b/src/client.ts index 5fbde1b..94a5832 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,7 @@ import { CallableProcedureClient, ClientModuleDefinition, RpcClient, RpcClientPort, RpcPortEvents } from "." import { Transport } from "./types" import mitt from "mitt" -import { Writer } from "protobufjs" +import { Writer } from "protobufjs/minimal" import { CreatePort, CreatePortResponse, @@ -13,7 +13,7 @@ import { Response, RpcMessageTypes, StreamMessage, -} from "./protocol/pbjs" +} from "./protocol" import { MessageDispatcher, messageNumberHandler } from "./message-number-handler" import { pushableChannel } from "./push-channel" import { diff --git a/src/codegen.ts b/src/codegen.ts index 2daa0b9..5c8df7e 100644 --- a/src/codegen.ts +++ b/src/codegen.ts @@ -1,88 +1,85 @@ -import { Message } from "google-protobuf" +import { Writer, Reader } from "protobufjs/minimal" -export type Constructor = { new (): C; deserializeBinary(data: Uint8Array): C } +export interface Message { + encode(message: T, writer?: Writer): Writer + decode(input: Reader | Uint8Array, length?: number): T + fromJSON(object: any): T + toJSON(message: T): unknown +} -export function clientProcedureUnary( +export function clientProcedureUnary( port: unknown | Promise, name: string, - requestType: Constructor, - requestResponseConstructor: Constructor + requestType: Message, + requestResponseConstructor: Message ) { - const fn: (arg: Ctor1) => Promise = async (arg: any): Promise => { + const fn = async (arg: Ctor1): Promise => { const remoteModule: Record Promise> = (await port) as any - if (!(arg instanceof requestType)) throw new Error("Argument passed to RPC Method " + name + " type mismatch.") if (!(name in remoteModule)) throw new Error("Method " + name + " not implemented in server port") - const result = await remoteModule[name](arg.serializeBinary()) + const result = await remoteModule[name](requestType.encode(arg).finish()) if (!result) { throw new Error("Server sent an empty or null response to method call " + name) } - return requestResponseConstructor.deserializeBinary(result) + return requestResponseConstructor.decode(result) } return fn } -export function clientProcedureStream( +export function clientProcedureStream( port: unknown | Promise, name: string, - requestType: Constructor, - requestResponseConstructor: Constructor + requestType: Message, + requestResponseConstructor: Message ) { - const fn: (arg: Ctor1) => AsyncGenerator = async function* (arg: any) { + const fn = async function* (arg: Ctor1): AsyncGenerator { const remoteModule: Record Promise> = (await port) as any - if (!(arg instanceof requestType)) throw new Error("Argument passed to RPC Method " + name + " type mismatch.") if (!(name in remoteModule)) throw new Error("Method " + name + " not implemented in server port") - const result = await remoteModule[name](arg.serializeBinary()) + const result = await remoteModule[name](requestType.encode(arg).finish()) if (!result) { throw new Error("Server sent an empty or null response to method call " + name) } for await (const bytes of await result) { - yield requestResponseConstructor.deserializeBinary(bytes) + yield requestResponseConstructor.decode(bytes) } } return fn } -export function serverProcedureUnary( +export function serverProcedureUnary( fn: (arg: Ctor1) => Promise, name: string, - ctor1: Constructor, - ctor2: Constructor + ctor1: Message, + ctor2: Message ): (arg: Uint8Array) => Promise { return async function (argBinary) { - const arg = ctor1.deserializeBinary(argBinary) + const arg = ctor1.decode(argBinary) const result = await fn(arg) if (!result) throw new Error("Empty or null responses are not allowed. Procedure: " + name) - if (!(result instanceof ctor2)) - throw new Error("Result of procedure " + name + " did not match the expected constructor") - - return result.serializeBinary() + return ctor2.encode(result).finish() } } -export function serverProcedureStream( +export function serverProcedureStream( fn: (arg: Ctor1) => Promise> | AsyncGenerator, name: string, - ctor1: Constructor, - ctor2: Constructor + ctor1: Message, + ctor2: Message ): (arg: Uint8Array) => AsyncGenerator { return async function* (argBinary) { - const arg = ctor1.deserializeBinary(argBinary) + const arg = ctor1.decode(argBinary) const result = await fn(arg) if (!result) throw new Error("Empty or null responses are not allowed. Procedure: " + name) for await (const elem of result) { - if (!(elem instanceof ctor2)) - throw new Error("Yielded result of procedure " + name + " did not match the expected constructor") - - yield elem.serializeBinary() + yield ctor2.encode(elem).finish() } } } diff --git a/src/message-number-handler.ts b/src/message-number-handler.ts index ebdb658..a8387e6 100644 --- a/src/message-number-handler.ts +++ b/src/message-number-handler.ts @@ -1,7 +1,7 @@ import { Transport } from "." -import { Writer,Reader } from "protobufjs" +import { Writer,Reader } from "protobufjs/minimal" import { parseMessageIdentifier } from "./protocol/helpers" -import { RpcMessageHeader } from "./protocol/pbjs" +import { RpcMessageHeader } from "./protocol" let globalMessageNumber = 0 export type SendableMessage = { diff --git a/src/protocol/helpers.ts b/src/protocol/helpers.ts index 8863e3d..d3a1548 100644 --- a/src/protocol/helpers.ts +++ b/src/protocol/helpers.ts @@ -1,4 +1,4 @@ -import { Writer, Reader } from "protobufjs" +import { Writer, Reader } from "protobufjs/minimal" import { RpcMessageTypes, RpcMessageHeader, @@ -11,7 +11,7 @@ import { CreatePort, RequestModule, DestroyPort, -} from "./pbjs" +} from "./index" export function closeStreamMessage(messageNumber: number, sequenceId: number, portId: number): Uint8Array { const bb = new Writer() diff --git a/src/protocol/index.ts b/src/protocol/index.ts new file mode 100644 index 0000000..a3084a3 --- /dev/null +++ b/src/protocol/index.ts @@ -0,0 +1,939 @@ +/* eslint-disable */ +import Long from "long" +import * as _m0 from "protobufjs/minimal" + +export const protobufPackage = "" + +/** THIS FILE IS AUTOGENERATED */ + +export enum RpcMessageTypes { + RpcMessageTypes_EMPTY = 0, + RpcMessageTypes_REQUEST = 1, + RpcMessageTypes_RESPONSE = 2, + RpcMessageTypes_STREAM_MESSAGE = 3, + RpcMessageTypes_STREAM_ACK = 4, + RpcMessageTypes_CREATE_PORT = 5, + RpcMessageTypes_CREATE_PORT_RESPONSE = 6, + RpcMessageTypes_REQUEST_MODULE = 7, + RpcMessageTypes_REQUEST_MODULE_RESPONSE = 8, + RpcMessageTypes_REMOTE_ERROR_RESPONSE = 9, + RpcMessageTypes_DESTROY_PORT = 10, + RpcMessageTypes_SERVER_READY = 11, + UNRECOGNIZED = -1, +} + +export function rpcMessageTypesFromJSON(object: any): RpcMessageTypes { + switch (object) { + case 0: + case "RpcMessageTypes_EMPTY": + return RpcMessageTypes.RpcMessageTypes_EMPTY + case 1: + case "RpcMessageTypes_REQUEST": + return RpcMessageTypes.RpcMessageTypes_REQUEST + case 2: + case "RpcMessageTypes_RESPONSE": + return RpcMessageTypes.RpcMessageTypes_RESPONSE + case 3: + case "RpcMessageTypes_STREAM_MESSAGE": + return RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE + case 4: + case "RpcMessageTypes_STREAM_ACK": + return RpcMessageTypes.RpcMessageTypes_STREAM_ACK + case 5: + case "RpcMessageTypes_CREATE_PORT": + return RpcMessageTypes.RpcMessageTypes_CREATE_PORT + case 6: + case "RpcMessageTypes_CREATE_PORT_RESPONSE": + return RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE + case 7: + case "RpcMessageTypes_REQUEST_MODULE": + return RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE + case 8: + case "RpcMessageTypes_REQUEST_MODULE_RESPONSE": + return RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE + case 9: + case "RpcMessageTypes_REMOTE_ERROR_RESPONSE": + return RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE + case 10: + case "RpcMessageTypes_DESTROY_PORT": + return RpcMessageTypes.RpcMessageTypes_DESTROY_PORT + case 11: + case "RpcMessageTypes_SERVER_READY": + return RpcMessageTypes.RpcMessageTypes_SERVER_READY + case -1: + case "UNRECOGNIZED": + default: + return RpcMessageTypes.UNRECOGNIZED + } +} + +export function rpcMessageTypesToJSON(object: RpcMessageTypes): string { + switch (object) { + case RpcMessageTypes.RpcMessageTypes_EMPTY: + return "RpcMessageTypes_EMPTY" + case RpcMessageTypes.RpcMessageTypes_REQUEST: + return "RpcMessageTypes_REQUEST" + case RpcMessageTypes.RpcMessageTypes_RESPONSE: + return "RpcMessageTypes_RESPONSE" + case RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE: + return "RpcMessageTypes_STREAM_MESSAGE" + case RpcMessageTypes.RpcMessageTypes_STREAM_ACK: + return "RpcMessageTypes_STREAM_ACK" + case RpcMessageTypes.RpcMessageTypes_CREATE_PORT: + return "RpcMessageTypes_CREATE_PORT" + case RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE: + return "RpcMessageTypes_CREATE_PORT_RESPONSE" + case RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE: + return "RpcMessageTypes_REQUEST_MODULE" + case RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE: + return "RpcMessageTypes_REQUEST_MODULE_RESPONSE" + case RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE: + return "RpcMessageTypes_REMOTE_ERROR_RESPONSE" + case RpcMessageTypes.RpcMessageTypes_DESTROY_PORT: + return "RpcMessageTypes_DESTROY_PORT" + case RpcMessageTypes.RpcMessageTypes_SERVER_READY: + return "RpcMessageTypes_SERVER_READY" + default: + return "UNKNOWN" + } +} + +export interface RpcMessageHeader { + messageIdentifier: number +} + +export interface CreatePort { + messageIdentifier: number + portName: string +} + +export interface CreatePortResponse { + messageIdentifier: number + portId: number +} + +export interface RequestModule { + messageIdentifier: number + portId: number + moduleName: string +} + +export interface RequestModuleResponse { + messageIdentifier: number + portId: number + procedures: ModuleProcedure[] +} + +export interface DestroyPort { + messageIdentifier: number + portId: number +} + +export interface ModuleProcedure { + procedureId: number + procedureName: string +} + +export interface Request { + messageIdentifier: number + portId: number + procedureId: number + payload: Uint8Array +} + +export interface RemoteError { + messageIdentifier: number + errorCode: number + errorMessage: string +} + +export interface Response { + messageIdentifier: number + payload: Uint8Array +} + +export interface StreamMessage { + messageIdentifier: number + portId: number + sequenceId: number + payload: Uint8Array + closed: boolean + ack: boolean +} + +function createBaseRpcMessageHeader(): RpcMessageHeader { + return { messageIdentifier: 0 } +} + +export const RpcMessageHeader = { + encode(message: RpcMessageHeader, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): RpcMessageHeader { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseRpcMessageHeader() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): RpcMessageHeader { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + } + }, + + toJSON(message: RpcMessageHeader): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + return obj + }, + + fromPartial, I>>(object: I): RpcMessageHeader { + const message = createBaseRpcMessageHeader() + message.messageIdentifier = object.messageIdentifier ?? 0 + return message + }, +} + +function createBaseCreatePort(): CreatePort { + return { messageIdentifier: 0, portName: "" } +} + +export const CreatePort = { + encode(message: CreatePort, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portName !== "") { + writer.uint32(34).string(message.portName) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): CreatePort { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseCreatePort() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 4: + message.portName = reader.string() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): CreatePort { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portName: isSet(object.portName) ? String(object.portName) : "", + } + }, + + toJSON(message: CreatePort): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portName !== undefined && (obj.portName = message.portName) + return obj + }, + + fromPartial, I>>(object: I): CreatePort { + const message = createBaseCreatePort() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portName = object.portName ?? "" + return message + }, +} + +function createBaseCreatePortResponse(): CreatePortResponse { + return { messageIdentifier: 0, portId: 0 } +} + +export const CreatePortResponse = { + encode(message: CreatePortResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portId !== 0) { + writer.uint32(21).fixed32(message.portId) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): CreatePortResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseCreatePortResponse() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.portId = reader.fixed32() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): CreatePortResponse { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portId: isSet(object.portId) ? Number(object.portId) : 0, + } + }, + + toJSON(message: CreatePortResponse): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portId !== undefined && (obj.portId = Math.round(message.portId)) + return obj + }, + + fromPartial, I>>(object: I): CreatePortResponse { + const message = createBaseCreatePortResponse() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portId = object.portId ?? 0 + return message + }, +} + +function createBaseRequestModule(): RequestModule { + return { messageIdentifier: 0, portId: 0, moduleName: "" } +} + +export const RequestModule = { + encode(message: RequestModule, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portId !== 0) { + writer.uint32(21).fixed32(message.portId) + } + if (message.moduleName !== "") { + writer.uint32(34).string(message.moduleName) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): RequestModule { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseRequestModule() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.portId = reader.fixed32() + break + case 4: + message.moduleName = reader.string() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): RequestModule { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portId: isSet(object.portId) ? Number(object.portId) : 0, + moduleName: isSet(object.moduleName) ? String(object.moduleName) : "", + } + }, + + toJSON(message: RequestModule): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portId !== undefined && (obj.portId = Math.round(message.portId)) + message.moduleName !== undefined && (obj.moduleName = message.moduleName) + return obj + }, + + fromPartial, I>>(object: I): RequestModule { + const message = createBaseRequestModule() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portId = object.portId ?? 0 + message.moduleName = object.moduleName ?? "" + return message + }, +} + +function createBaseRequestModuleResponse(): RequestModuleResponse { + return { messageIdentifier: 0, portId: 0, procedures: [] } +} + +export const RequestModuleResponse = { + encode(message: RequestModuleResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portId !== 0) { + writer.uint32(21).fixed32(message.portId) + } + for (const v of message.procedures) { + ModuleProcedure.encode(v!, writer.uint32(42).fork()).ldelim() + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): RequestModuleResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseRequestModuleResponse() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.portId = reader.fixed32() + break + case 5: + message.procedures.push(ModuleProcedure.decode(reader, reader.uint32())) + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): RequestModuleResponse { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portId: isSet(object.portId) ? Number(object.portId) : 0, + procedures: Array.isArray(object?.procedures) + ? object.procedures.map((e: any) => ModuleProcedure.fromJSON(e)) + : [], + } + }, + + toJSON(message: RequestModuleResponse): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portId !== undefined && (obj.portId = Math.round(message.portId)) + if (message.procedures) { + obj.procedures = message.procedures.map((e) => (e ? ModuleProcedure.toJSON(e) : undefined)) + } else { + obj.procedures = [] + } + return obj + }, + + fromPartial, I>>(object: I): RequestModuleResponse { + const message = createBaseRequestModuleResponse() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portId = object.portId ?? 0 + message.procedures = object.procedures?.map((e) => ModuleProcedure.fromPartial(e)) || [] + return message + }, +} + +function createBaseDestroyPort(): DestroyPort { + return { messageIdentifier: 0, portId: 0 } +} + +export const DestroyPort = { + encode(message: DestroyPort, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portId !== 0) { + writer.uint32(21).fixed32(message.portId) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): DestroyPort { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseDestroyPort() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.portId = reader.fixed32() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): DestroyPort { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portId: isSet(object.portId) ? Number(object.portId) : 0, + } + }, + + toJSON(message: DestroyPort): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portId !== undefined && (obj.portId = Math.round(message.portId)) + return obj + }, + + fromPartial, I>>(object: I): DestroyPort { + const message = createBaseDestroyPort() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portId = object.portId ?? 0 + return message + }, +} + +function createBaseModuleProcedure(): ModuleProcedure { + return { procedureId: 0, procedureName: "" } +} + +export const ModuleProcedure = { + encode(message: ModuleProcedure, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.procedureId !== 0) { + writer.uint32(13).fixed32(message.procedureId) + } + if (message.procedureName !== "") { + writer.uint32(18).string(message.procedureName) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): ModuleProcedure { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseModuleProcedure() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.procedureId = reader.fixed32() + break + case 2: + message.procedureName = reader.string() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): ModuleProcedure { + return { + procedureId: isSet(object.procedureId) ? Number(object.procedureId) : 0, + procedureName: isSet(object.procedureName) ? String(object.procedureName) : "", + } + }, + + toJSON(message: ModuleProcedure): unknown { + const obj: any = {} + message.procedureId !== undefined && (obj.procedureId = Math.round(message.procedureId)) + message.procedureName !== undefined && (obj.procedureName = message.procedureName) + return obj + }, + + fromPartial, I>>(object: I): ModuleProcedure { + const message = createBaseModuleProcedure() + message.procedureId = object.procedureId ?? 0 + message.procedureName = object.procedureName ?? "" + return message + }, +} + +function createBaseRequest(): Request { + return { messageIdentifier: 0, portId: 0, procedureId: 0, payload: new Uint8Array() } +} + +export const Request = { + encode(message: Request, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portId !== 0) { + writer.uint32(21).fixed32(message.portId) + } + if (message.procedureId !== 0) { + writer.uint32(37).fixed32(message.procedureId) + } + if (message.payload.length !== 0) { + writer.uint32(50).bytes(message.payload) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Request { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseRequest() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.portId = reader.fixed32() + break + case 4: + message.procedureId = reader.fixed32() + break + case 6: + message.payload = reader.bytes() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): Request { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portId: isSet(object.portId) ? Number(object.portId) : 0, + procedureId: isSet(object.procedureId) ? Number(object.procedureId) : 0, + payload: isSet(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), + } + }, + + toJSON(message: Request): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portId !== undefined && (obj.portId = Math.round(message.portId)) + message.procedureId !== undefined && (obj.procedureId = Math.round(message.procedureId)) + message.payload !== undefined && + (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())) + return obj + }, + + fromPartial, I>>(object: I): Request { + const message = createBaseRequest() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portId = object.portId ?? 0 + message.procedureId = object.procedureId ?? 0 + message.payload = object.payload ?? new Uint8Array() + return message + }, +} + +function createBaseRemoteError(): RemoteError { + return { messageIdentifier: 0, errorCode: 0, errorMessage: "" } +} + +export const RemoteError = { + encode(message: RemoteError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.errorCode !== 0) { + writer.uint32(21).fixed32(message.errorCode) + } + if (message.errorMessage !== "") { + writer.uint32(26).string(message.errorMessage) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): RemoteError { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseRemoteError() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.errorCode = reader.fixed32() + break + case 3: + message.errorMessage = reader.string() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): RemoteError { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + errorCode: isSet(object.errorCode) ? Number(object.errorCode) : 0, + errorMessage: isSet(object.errorMessage) ? String(object.errorMessage) : "", + } + }, + + toJSON(message: RemoteError): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.errorCode !== undefined && (obj.errorCode = Math.round(message.errorCode)) + message.errorMessage !== undefined && (obj.errorMessage = message.errorMessage) + return obj + }, + + fromPartial, I>>(object: I): RemoteError { + const message = createBaseRemoteError() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.errorCode = object.errorCode ?? 0 + message.errorMessage = object.errorMessage ?? "" + return message + }, +} + +function createBaseResponse(): Response { + return { messageIdentifier: 0, payload: new Uint8Array() } +} + +export const Response = { + encode(message: Response, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.payload.length !== 0) { + writer.uint32(50).bytes(message.payload) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Response { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseResponse() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 6: + message.payload = reader.bytes() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): Response { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + payload: isSet(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), + } + }, + + toJSON(message: Response): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.payload !== undefined && + (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())) + return obj + }, + + fromPartial, I>>(object: I): Response { + const message = createBaseResponse() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.payload = object.payload ?? new Uint8Array() + return message + }, +} + +function createBaseStreamMessage(): StreamMessage { + return { messageIdentifier: 0, portId: 0, sequenceId: 0, payload: new Uint8Array(), closed: false, ack: false } +} + +export const StreamMessage = { + encode(message: StreamMessage, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.messageIdentifier !== 0) { + writer.uint32(13).fixed32(message.messageIdentifier) + } + if (message.portId !== 0) { + writer.uint32(21).fixed32(message.portId) + } + if (message.sequenceId !== 0) { + writer.uint32(37).fixed32(message.sequenceId) + } + if (message.payload.length !== 0) { + writer.uint32(50).bytes(message.payload) + } + if (message.closed === true) { + writer.uint32(56).bool(message.closed) + } + if (message.ack === true) { + writer.uint32(64).bool(message.ack) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): StreamMessage { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseStreamMessage() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.messageIdentifier = reader.fixed32() + break + case 2: + message.portId = reader.fixed32() + break + case 4: + message.sequenceId = reader.fixed32() + break + case 6: + message.payload = reader.bytes() + break + case 7: + message.closed = reader.bool() + break + case 8: + message.ack = reader.bool() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): StreamMessage { + return { + messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, + portId: isSet(object.portId) ? Number(object.portId) : 0, + sequenceId: isSet(object.sequenceId) ? Number(object.sequenceId) : 0, + payload: isSet(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), + closed: isSet(object.closed) ? Boolean(object.closed) : false, + ack: isSet(object.ack) ? Boolean(object.ack) : false, + } + }, + + toJSON(message: StreamMessage): unknown { + const obj: any = {} + message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) + message.portId !== undefined && (obj.portId = Math.round(message.portId)) + message.sequenceId !== undefined && (obj.sequenceId = Math.round(message.sequenceId)) + message.payload !== undefined && + (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())) + message.closed !== undefined && (obj.closed = message.closed) + message.ack !== undefined && (obj.ack = message.ack) + return obj + }, + + fromPartial, I>>(object: I): StreamMessage { + const message = createBaseStreamMessage() + message.messageIdentifier = object.messageIdentifier ?? 0 + message.portId = object.portId ?? 0 + message.sequenceId = object.sequenceId ?? 0 + message.payload = object.payload ?? new Uint8Array() + message.closed = object.closed ?? false + message.ack = object.ack ?? false + return message + }, +} + +declare var self: any | undefined +declare var window: any | undefined +declare var global: any | undefined +var globalThis: any = (() => { + if (typeof globalThis !== "undefined") return globalThis + if (typeof self !== "undefined") return self + if (typeof window !== "undefined") return window + if (typeof global !== "undefined") return global + throw "Unable to locate global object" +})() + +const atob: (b64: string) => string = + globalThis.atob || ((b64) => globalThis.Buffer.from(b64, "base64").toString("binary")) +function bytesFromBase64(b64: string): Uint8Array { + const bin = atob(b64) + const arr = new Uint8Array(bin.length) + for (let i = 0; i < bin.length; ++i) { + arr[i] = bin.charCodeAt(i) + } + return arr +} + +const btoa: (bin: string) => string = + globalThis.btoa || ((bin) => globalThis.Buffer.from(bin, "binary").toString("base64")) +function base64FromBytes(arr: Uint8Array): string { + const bin: string[] = [] + arr.forEach((byte) => { + bin.push(String.fromCharCode(byte)) + }) + return btoa(bin.join("")) +} + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined + +export type DeepPartial = T extends Builtin + ? T + : T extends Array + ? Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : T extends {} + ? { [K in keyof T]?: DeepPartial } + : Partial + +type KeysOfUnion = T extends T ? keyof T : never +export type Exact = P extends Builtin + ? P + : P & { [K in keyof P]: Exact } & Record>, never> + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any + _m0.configure() +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined +} diff --git a/src/protocol/pbjs.d.ts b/src/protocol/pbjs.d.ts deleted file mode 100644 index 2ab40cd..0000000 --- a/src/protocol/pbjs.d.ts +++ /dev/null @@ -1,993 +0,0 @@ -import * as $protobuf from "protobufjs"; -/** Properties of a RpcMessageHeader. */ -export interface IRpcMessageHeader { - - /** RpcMessageHeader messageIdentifier */ - messageIdentifier?: (number|null); -} - -/** Represents a RpcMessageHeader. */ -export class RpcMessageHeader implements IRpcMessageHeader { - - /** - * Constructs a new RpcMessageHeader. - * @param [properties] Properties to set - */ - constructor(properties?: IRpcMessageHeader); - - /** RpcMessageHeader messageIdentifier. */ - public messageIdentifier: number; - - /** - * Creates a new RpcMessageHeader instance using the specified properties. - * @param [properties] Properties to set - * @returns RpcMessageHeader instance - */ - public static create(properties?: IRpcMessageHeader): RpcMessageHeader; - - /** - * Encodes the specified RpcMessageHeader message. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. - * @param message RpcMessageHeader message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IRpcMessageHeader, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified RpcMessageHeader message, length delimited. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. - * @param message RpcMessageHeader message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IRpcMessageHeader, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a RpcMessageHeader message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns RpcMessageHeader - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RpcMessageHeader; - - /** - * Decodes a RpcMessageHeader message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns RpcMessageHeader - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RpcMessageHeader; - - /** - * Verifies a RpcMessageHeader message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a RpcMessageHeader message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns RpcMessageHeader - */ - public static fromObject(object: { [k: string]: any }): RpcMessageHeader; - - /** - * Creates a plain object from a RpcMessageHeader message. Also converts values to other types if specified. - * @param message RpcMessageHeader - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RpcMessageHeader, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this RpcMessageHeader to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** RpcMessageTypes enum. */ -export enum RpcMessageTypes { - RpcMessageTypes_EMPTY = 0, - RpcMessageTypes_REQUEST = 1, - RpcMessageTypes_RESPONSE = 2, - RpcMessageTypes_STREAM_MESSAGE = 3, - RpcMessageTypes_STREAM_ACK = 4, - RpcMessageTypes_CREATE_PORT = 5, - RpcMessageTypes_CREATE_PORT_RESPONSE = 6, - RpcMessageTypes_REQUEST_MODULE = 7, - RpcMessageTypes_REQUEST_MODULE_RESPONSE = 8, - RpcMessageTypes_REMOTE_ERROR_RESPONSE = 9, - RpcMessageTypes_DESTROY_PORT = 10, - RpcMessageTypes_SERVER_READY = 11 -} - -/** Represents a CreatePort. */ -export class CreatePort implements ICreatePort { - - /** - * Constructs a new CreatePort. - * @param [properties] Properties to set - */ - constructor(properties?: ICreatePort); - - /** CreatePort messageIdentifier. */ - public messageIdentifier: number; - - /** CreatePort portName. */ - public portName: string; - - /** - * Creates a new CreatePort instance using the specified properties. - * @param [properties] Properties to set - * @returns CreatePort instance - */ - public static create(properties?: ICreatePort): CreatePort; - - /** - * Encodes the specified CreatePort message. Does not implicitly {@link CreatePort.verify|verify} messages. - * @param message CreatePort message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: ICreatePort, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified CreatePort message, length delimited. Does not implicitly {@link CreatePort.verify|verify} messages. - * @param message CreatePort message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: ICreatePort, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a CreatePort message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns CreatePort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): CreatePort; - - /** - * Decodes a CreatePort message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns CreatePort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): CreatePort; - - /** - * Verifies a CreatePort message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a CreatePort message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns CreatePort - */ - public static fromObject(object: { [k: string]: any }): CreatePort; - - /** - * Creates a plain object from a CreatePort message. Also converts values to other types if specified. - * @param message CreatePort - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: CreatePort, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this CreatePort to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a CreatePortResponse. */ -export class CreatePortResponse implements ICreatePortResponse { - - /** - * Constructs a new CreatePortResponse. - * @param [properties] Properties to set - */ - constructor(properties?: ICreatePortResponse); - - /** CreatePortResponse messageIdentifier. */ - public messageIdentifier: number; - - /** CreatePortResponse portId. */ - public portId: number; - - /** - * Creates a new CreatePortResponse instance using the specified properties. - * @param [properties] Properties to set - * @returns CreatePortResponse instance - */ - public static create(properties?: ICreatePortResponse): CreatePortResponse; - - /** - * Encodes the specified CreatePortResponse message. Does not implicitly {@link CreatePortResponse.verify|verify} messages. - * @param message CreatePortResponse message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: ICreatePortResponse, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified CreatePortResponse message, length delimited. Does not implicitly {@link CreatePortResponse.verify|verify} messages. - * @param message CreatePortResponse message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: ICreatePortResponse, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a CreatePortResponse message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns CreatePortResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): CreatePortResponse; - - /** - * Decodes a CreatePortResponse message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns CreatePortResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): CreatePortResponse; - - /** - * Verifies a CreatePortResponse message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a CreatePortResponse message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns CreatePortResponse - */ - public static fromObject(object: { [k: string]: any }): CreatePortResponse; - - /** - * Creates a plain object from a CreatePortResponse message. Also converts values to other types if specified. - * @param message CreatePortResponse - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: CreatePortResponse, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this CreatePortResponse to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a RequestModule. */ -export class RequestModule implements IRequestModule { - - /** - * Constructs a new RequestModule. - * @param [properties] Properties to set - */ - constructor(properties?: IRequestModule); - - /** RequestModule messageIdentifier. */ - public messageIdentifier: number; - - /** RequestModule portId. */ - public portId: number; - - /** RequestModule moduleName. */ - public moduleName: string; - - /** - * Creates a new RequestModule instance using the specified properties. - * @param [properties] Properties to set - * @returns RequestModule instance - */ - public static create(properties?: IRequestModule): RequestModule; - - /** - * Encodes the specified RequestModule message. Does not implicitly {@link RequestModule.verify|verify} messages. - * @param message RequestModule message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IRequestModule, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified RequestModule message, length delimited. Does not implicitly {@link RequestModule.verify|verify} messages. - * @param message RequestModule message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IRequestModule, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a RequestModule message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns RequestModule - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RequestModule; - - /** - * Decodes a RequestModule message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns RequestModule - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RequestModule; - - /** - * Verifies a RequestModule message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a RequestModule message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns RequestModule - */ - public static fromObject(object: { [k: string]: any }): RequestModule; - - /** - * Creates a plain object from a RequestModule message. Also converts values to other types if specified. - * @param message RequestModule - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RequestModule, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this RequestModule to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a RequestModuleResponse. */ -export class RequestModuleResponse implements IRequestModuleResponse { - - /** - * Constructs a new RequestModuleResponse. - * @param [properties] Properties to set - */ - constructor(properties?: IRequestModuleResponse); - - /** RequestModuleResponse messageIdentifier. */ - public messageIdentifier: number; - - /** RequestModuleResponse portId. */ - public portId: number; - - /** RequestModuleResponse procedures. */ - public procedures: IModuleProcedure[]; - - /** - * Creates a new RequestModuleResponse instance using the specified properties. - * @param [properties] Properties to set - * @returns RequestModuleResponse instance - */ - public static create(properties?: IRequestModuleResponse): RequestModuleResponse; - - /** - * Encodes the specified RequestModuleResponse message. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. - * @param message RequestModuleResponse message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IRequestModuleResponse, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified RequestModuleResponse message, length delimited. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. - * @param message RequestModuleResponse message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IRequestModuleResponse, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a RequestModuleResponse message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns RequestModuleResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RequestModuleResponse; - - /** - * Decodes a RequestModuleResponse message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns RequestModuleResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RequestModuleResponse; - - /** - * Verifies a RequestModuleResponse message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a RequestModuleResponse message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns RequestModuleResponse - */ - public static fromObject(object: { [k: string]: any }): RequestModuleResponse; - - /** - * Creates a plain object from a RequestModuleResponse message. Also converts values to other types if specified. - * @param message RequestModuleResponse - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RequestModuleResponse, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this RequestModuleResponse to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a DestroyPort. */ -export class DestroyPort implements IDestroyPort { - - /** - * Constructs a new DestroyPort. - * @param [properties] Properties to set - */ - constructor(properties?: IDestroyPort); - - /** DestroyPort messageIdentifier. */ - public messageIdentifier: number; - - /** DestroyPort portId. */ - public portId: number; - - /** - * Creates a new DestroyPort instance using the specified properties. - * @param [properties] Properties to set - * @returns DestroyPort instance - */ - public static create(properties?: IDestroyPort): DestroyPort; - - /** - * Encodes the specified DestroyPort message. Does not implicitly {@link DestroyPort.verify|verify} messages. - * @param message DestroyPort message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IDestroyPort, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified DestroyPort message, length delimited. Does not implicitly {@link DestroyPort.verify|verify} messages. - * @param message DestroyPort message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IDestroyPort, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a DestroyPort message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns DestroyPort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): DestroyPort; - - /** - * Decodes a DestroyPort message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns DestroyPort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): DestroyPort; - - /** - * Verifies a DestroyPort message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a DestroyPort message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns DestroyPort - */ - public static fromObject(object: { [k: string]: any }): DestroyPort; - - /** - * Creates a plain object from a DestroyPort message. Also converts values to other types if specified. - * @param message DestroyPort - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: DestroyPort, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this DestroyPort to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a ModuleProcedure. */ -export class ModuleProcedure implements IModuleProcedure { - - /** - * Constructs a new ModuleProcedure. - * @param [properties] Properties to set - */ - constructor(properties?: IModuleProcedure); - - /** ModuleProcedure procedureId. */ - public procedureId: number; - - /** ModuleProcedure procedureName. */ - public procedureName: string; - - /** - * Creates a new ModuleProcedure instance using the specified properties. - * @param [properties] Properties to set - * @returns ModuleProcedure instance - */ - public static create(properties?: IModuleProcedure): ModuleProcedure; - - /** - * Encodes the specified ModuleProcedure message. Does not implicitly {@link ModuleProcedure.verify|verify} messages. - * @param message ModuleProcedure message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IModuleProcedure, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified ModuleProcedure message, length delimited. Does not implicitly {@link ModuleProcedure.verify|verify} messages. - * @param message ModuleProcedure message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IModuleProcedure, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a ModuleProcedure message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns ModuleProcedure - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): ModuleProcedure; - - /** - * Decodes a ModuleProcedure message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns ModuleProcedure - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): ModuleProcedure; - - /** - * Verifies a ModuleProcedure message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a ModuleProcedure message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns ModuleProcedure - */ - public static fromObject(object: { [k: string]: any }): ModuleProcedure; - - /** - * Creates a plain object from a ModuleProcedure message. Also converts values to other types if specified. - * @param message ModuleProcedure - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: ModuleProcedure, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this ModuleProcedure to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a Request. */ -export class Request implements IRequest { - - /** - * Constructs a new Request. - * @param [properties] Properties to set - */ - constructor(properties?: IRequest); - - /** Request messageIdentifier. */ - public messageIdentifier: number; - - /** Request portId. */ - public portId: number; - - /** Request procedureId. */ - public procedureId: number; - - /** Request payload. */ - public payload: Uint8Array; - - /** - * Creates a new Request instance using the specified properties. - * @param [properties] Properties to set - * @returns Request instance - */ - public static create(properties?: IRequest): Request; - - /** - * Encodes the specified Request message. Does not implicitly {@link Request.verify|verify} messages. - * @param message Request message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IRequest, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified Request message, length delimited. Does not implicitly {@link Request.verify|verify} messages. - * @param message Request message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IRequest, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a Request message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns Request - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Request; - - /** - * Decodes a Request message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns Request - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Request; - - /** - * Verifies a Request message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a Request message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns Request - */ - public static fromObject(object: { [k: string]: any }): Request; - - /** - * Creates a plain object from a Request message. Also converts values to other types if specified. - * @param message Request - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: Request, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this Request to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a RemoteError. */ -export class RemoteError implements IRemoteError { - - /** - * Constructs a new RemoteError. - * @param [properties] Properties to set - */ - constructor(properties?: IRemoteError); - - /** RemoteError messageIdentifier. */ - public messageIdentifier: number; - - /** RemoteError errorCode. */ - public errorCode: number; - - /** RemoteError errorMessage. */ - public errorMessage: string; - - /** - * Creates a new RemoteError instance using the specified properties. - * @param [properties] Properties to set - * @returns RemoteError instance - */ - public static create(properties?: IRemoteError): RemoteError; - - /** - * Encodes the specified RemoteError message. Does not implicitly {@link RemoteError.verify|verify} messages. - * @param message RemoteError message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IRemoteError, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified RemoteError message, length delimited. Does not implicitly {@link RemoteError.verify|verify} messages. - * @param message RemoteError message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IRemoteError, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a RemoteError message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns RemoteError - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): RemoteError; - - /** - * Decodes a RemoteError message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns RemoteError - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): RemoteError; - - /** - * Verifies a RemoteError message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a RemoteError message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns RemoteError - */ - public static fromObject(object: { [k: string]: any }): RemoteError; - - /** - * Creates a plain object from a RemoteError message. Also converts values to other types if specified. - * @param message RemoteError - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: RemoteError, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this RemoteError to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a Response. */ -export class Response implements IResponse { - - /** - * Constructs a new Response. - * @param [properties] Properties to set - */ - constructor(properties?: IResponse); - - /** Response messageIdentifier. */ - public messageIdentifier: number; - - /** Response payload. */ - public payload: Uint8Array; - - /** - * Creates a new Response instance using the specified properties. - * @param [properties] Properties to set - * @returns Response instance - */ - public static create(properties?: IResponse): Response; - - /** - * Encodes the specified Response message. Does not implicitly {@link Response.verify|verify} messages. - * @param message Response message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IResponse, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified Response message, length delimited. Does not implicitly {@link Response.verify|verify} messages. - * @param message Response message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IResponse, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a Response message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns Response - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): Response; - - /** - * Decodes a Response message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns Response - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): Response; - - /** - * Verifies a Response message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a Response message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns Response - */ - public static fromObject(object: { [k: string]: any }): Response; - - /** - * Creates a plain object from a Response message. Also converts values to other types if specified. - * @param message Response - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: Response, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this Response to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} - -/** Represents a StreamMessage. */ -export class StreamMessage implements IStreamMessage { - - /** - * Constructs a new StreamMessage. - * @param [properties] Properties to set - */ - constructor(properties?: IStreamMessage); - - /** StreamMessage messageIdentifier. */ - public messageIdentifier: number; - - /** StreamMessage portId. */ - public portId: number; - - /** StreamMessage sequenceId. */ - public sequenceId: number; - - /** StreamMessage payload. */ - public payload: Uint8Array; - - /** StreamMessage closed. */ - public closed: boolean; - - /** StreamMessage ack. */ - public ack: boolean; - - /** - * Creates a new StreamMessage instance using the specified properties. - * @param [properties] Properties to set - * @returns StreamMessage instance - */ - public static create(properties?: IStreamMessage): StreamMessage; - - /** - * Encodes the specified StreamMessage message. Does not implicitly {@link StreamMessage.verify|verify} messages. - * @param message StreamMessage message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encode(message: IStreamMessage, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Encodes the specified StreamMessage message, length delimited. Does not implicitly {@link StreamMessage.verify|verify} messages. - * @param message StreamMessage message or plain object to encode - * @param [writer] Writer to encode to - * @returns Writer - */ - public static encodeDelimited(message: IStreamMessage, writer?: $protobuf.Writer): $protobuf.Writer; - - /** - * Decodes a StreamMessage message from the specified reader or buffer. - * @param reader Reader or buffer to decode from - * @param [length] Message length if known beforehand - * @returns StreamMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): StreamMessage; - - /** - * Decodes a StreamMessage message from the specified reader or buffer, length delimited. - * @param reader Reader or buffer to decode from - * @returns StreamMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): StreamMessage; - - /** - * Verifies a StreamMessage message. - * @param message Plain object to verify - * @returns `null` if valid, otherwise the reason why it is not - */ - public static verify(message: { [k: string]: any }): (string|null); - - /** - * Creates a StreamMessage message from a plain object. Also converts values to their respective internal types. - * @param object Plain object - * @returns StreamMessage - */ - public static fromObject(object: { [k: string]: any }): StreamMessage; - - /** - * Creates a plain object from a StreamMessage message. Also converts values to other types if specified. - * @param message StreamMessage - * @param [options] Conversion options - * @returns Plain object - */ - public static toObject(message: StreamMessage, options?: $protobuf.IConversionOptions): { [k: string]: any }; - - /** - * Converts this StreamMessage to JSON. - * @returns JSON object - */ - public toJSON(): { [k: string]: any }; -} diff --git a/src/protocol/pbjs.js b/src/protocol/pbjs.js deleted file mode 100644 index 81eb007..0000000 --- a/src/protocol/pbjs.js +++ /dev/null @@ -1,2580 +0,0 @@ -/*eslint-disable block-scoped-var, id-length, no-control-regex, no-magic-numbers, no-prototype-builtins, no-redeclare, no-shadow, no-var, sort-vars*/ -"use strict"; - -var $protobuf = require("protobufjs/minimal"); - -// Common aliases -var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util; - -// Exported root namespace -var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {}); - -$root.RpcMessageHeader = (function() { - - /** - * Properties of a RpcMessageHeader. - * @exports IRpcMessageHeader - * @interface IRpcMessageHeader - * @property {number|null} [messageIdentifier] RpcMessageHeader messageIdentifier - */ - - /** - * Constructs a new RpcMessageHeader. - * @exports RpcMessageHeader - * @classdesc Represents a RpcMessageHeader. - * @implements IRpcMessageHeader - * @constructor - * @param {IRpcMessageHeader=} [properties] Properties to set - */ - function RpcMessageHeader(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * RpcMessageHeader messageIdentifier. - * @member {number} messageIdentifier - * @memberof RpcMessageHeader - * @instance - */ - RpcMessageHeader.prototype.messageIdentifier = 0; - - /** - * Creates a new RpcMessageHeader instance using the specified properties. - * @function create - * @memberof RpcMessageHeader - * @static - * @param {IRpcMessageHeader=} [properties] Properties to set - * @returns {RpcMessageHeader} RpcMessageHeader instance - */ - RpcMessageHeader.create = function create(properties) { - return new RpcMessageHeader(properties); - }; - - /** - * Encodes the specified RpcMessageHeader message. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. - * @function encode - * @memberof RpcMessageHeader - * @static - * @param {IRpcMessageHeader} message RpcMessageHeader message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RpcMessageHeader.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - return writer; - }; - - /** - * Encodes the specified RpcMessageHeader message, length delimited. Does not implicitly {@link RpcMessageHeader.verify|verify} messages. - * @function encodeDelimited - * @memberof RpcMessageHeader - * @static - * @param {IRpcMessageHeader} message RpcMessageHeader message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RpcMessageHeader.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a RpcMessageHeader message from the specified reader or buffer. - * @function decode - * @memberof RpcMessageHeader - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RpcMessageHeader} RpcMessageHeader - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RpcMessageHeader.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RpcMessageHeader(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a RpcMessageHeader message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RpcMessageHeader - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RpcMessageHeader} RpcMessageHeader - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RpcMessageHeader.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a RpcMessageHeader message. - * @function verify - * @memberof RpcMessageHeader - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - RpcMessageHeader.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - return null; - }; - - /** - * Creates a RpcMessageHeader message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RpcMessageHeader - * @static - * @param {Object.} object Plain object - * @returns {RpcMessageHeader} RpcMessageHeader - */ - RpcMessageHeader.fromObject = function fromObject(object) { - if (object instanceof $root.RpcMessageHeader) - return object; - var message = new $root.RpcMessageHeader(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - return message; - }; - - /** - * Creates a plain object from a RpcMessageHeader message. Also converts values to other types if specified. - * @function toObject - * @memberof RpcMessageHeader - * @static - * @param {RpcMessageHeader} message RpcMessageHeader - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - RpcMessageHeader.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) - object.messageIdentifier = 0; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - return object; - }; - - /** - * Converts this RpcMessageHeader to JSON. - * @function toJSON - * @memberof RpcMessageHeader - * @instance - * @returns {Object.} JSON object - */ - RpcMessageHeader.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return RpcMessageHeader; -})(); - -/** - * RpcMessageTypes enum. - * @exports RpcMessageTypes - * @enum {number} - * @property {number} RpcMessageTypes_EMPTY=0 RpcMessageTypes_EMPTY value - * @property {number} RpcMessageTypes_REQUEST=1 RpcMessageTypes_REQUEST value - * @property {number} RpcMessageTypes_RESPONSE=2 RpcMessageTypes_RESPONSE value - * @property {number} RpcMessageTypes_STREAM_MESSAGE=3 RpcMessageTypes_STREAM_MESSAGE value - * @property {number} RpcMessageTypes_STREAM_ACK=4 RpcMessageTypes_STREAM_ACK value - * @property {number} RpcMessageTypes_CREATE_PORT=5 RpcMessageTypes_CREATE_PORT value - * @property {number} RpcMessageTypes_CREATE_PORT_RESPONSE=6 RpcMessageTypes_CREATE_PORT_RESPONSE value - * @property {number} RpcMessageTypes_REQUEST_MODULE=7 RpcMessageTypes_REQUEST_MODULE value - * @property {number} RpcMessageTypes_REQUEST_MODULE_RESPONSE=8 RpcMessageTypes_REQUEST_MODULE_RESPONSE value - * @property {number} RpcMessageTypes_REMOTE_ERROR_RESPONSE=9 RpcMessageTypes_REMOTE_ERROR_RESPONSE value - * @property {number} RpcMessageTypes_DESTROY_PORT=10 RpcMessageTypes_DESTROY_PORT value - * @property {number} RpcMessageTypes_SERVER_READY=11 RpcMessageTypes_SERVER_READY value - */ -$root.RpcMessageTypes = (function() { - var valuesById = {}, values = Object.create(valuesById); - values[valuesById[0] = "RpcMessageTypes_EMPTY"] = 0; - values[valuesById[1] = "RpcMessageTypes_REQUEST"] = 1; - values[valuesById[2] = "RpcMessageTypes_RESPONSE"] = 2; - values[valuesById[3] = "RpcMessageTypes_STREAM_MESSAGE"] = 3; - values[valuesById[4] = "RpcMessageTypes_STREAM_ACK"] = 4; - values[valuesById[5] = "RpcMessageTypes_CREATE_PORT"] = 5; - values[valuesById[6] = "RpcMessageTypes_CREATE_PORT_RESPONSE"] = 6; - values[valuesById[7] = "RpcMessageTypes_REQUEST_MODULE"] = 7; - values[valuesById[8] = "RpcMessageTypes_REQUEST_MODULE_RESPONSE"] = 8; - values[valuesById[9] = "RpcMessageTypes_REMOTE_ERROR_RESPONSE"] = 9; - values[valuesById[10] = "RpcMessageTypes_DESTROY_PORT"] = 10; - values[valuesById[11] = "RpcMessageTypes_SERVER_READY"] = 11; - return values; -})(); - -$root.CreatePort = (function() { - - /** - * Properties of a CreatePort. - * @exports ICreatePort - * @interface ICreatePort - * @property {number|null} [messageIdentifier] CreatePort messageIdentifier - * @property {string|null} [portName] CreatePort portName - */ - - /** - * Constructs a new CreatePort. - * @exports CreatePort - * @classdesc Represents a CreatePort. - * @implements ICreatePort - * @constructor - * @param {ICreatePort=} [properties] Properties to set - */ - function CreatePort(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * CreatePort messageIdentifier. - * @member {number} messageIdentifier - * @memberof CreatePort - * @instance - */ - CreatePort.prototype.messageIdentifier = 0; - - /** - * CreatePort portName. - * @member {string} portName - * @memberof CreatePort - * @instance - */ - CreatePort.prototype.portName = ""; - - /** - * Creates a new CreatePort instance using the specified properties. - * @function create - * @memberof CreatePort - * @static - * @param {ICreatePort=} [properties] Properties to set - * @returns {CreatePort} CreatePort instance - */ - CreatePort.create = function create(properties) { - return new CreatePort(properties); - }; - - /** - * Encodes the specified CreatePort message. Does not implicitly {@link CreatePort.verify|verify} messages. - * @function encode - * @memberof CreatePort - * @static - * @param {ICreatePort} message CreatePort message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - CreatePort.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portName != null && Object.hasOwnProperty.call(message, "portName")) - writer.uint32(/* id 4, wireType 2 =*/34).string(message.portName); - return writer; - }; - - /** - * Encodes the specified CreatePort message, length delimited. Does not implicitly {@link CreatePort.verify|verify} messages. - * @function encodeDelimited - * @memberof CreatePort - * @static - * @param {ICreatePort} message CreatePort message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - CreatePort.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a CreatePort message from the specified reader or buffer. - * @function decode - * @memberof CreatePort - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {CreatePort} CreatePort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - CreatePort.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.CreatePort(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 4: - message.portName = reader.string(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a CreatePort message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof CreatePort - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {CreatePort} CreatePort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - CreatePort.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a CreatePort message. - * @function verify - * @memberof CreatePort - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - CreatePort.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portName != null && message.hasOwnProperty("portName")) - if (!$util.isString(message.portName)) - return "portName: string expected"; - return null; - }; - - /** - * Creates a CreatePort message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof CreatePort - * @static - * @param {Object.} object Plain object - * @returns {CreatePort} CreatePort - */ - CreatePort.fromObject = function fromObject(object) { - if (object instanceof $root.CreatePort) - return object; - var message = new $root.CreatePort(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portName != null) - message.portName = String(object.portName); - return message; - }; - - /** - * Creates a plain object from a CreatePort message. Also converts values to other types if specified. - * @function toObject - * @memberof CreatePort - * @static - * @param {CreatePort} message CreatePort - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - CreatePort.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.portName = ""; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portName != null && message.hasOwnProperty("portName")) - object.portName = message.portName; - return object; - }; - - /** - * Converts this CreatePort to JSON. - * @function toJSON - * @memberof CreatePort - * @instance - * @returns {Object.} JSON object - */ - CreatePort.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return CreatePort; -})(); - -$root.CreatePortResponse = (function() { - - /** - * Properties of a CreatePortResponse. - * @exports ICreatePortResponse - * @interface ICreatePortResponse - * @property {number|null} [messageIdentifier] CreatePortResponse messageIdentifier - * @property {number|null} [portId] CreatePortResponse portId - */ - - /** - * Constructs a new CreatePortResponse. - * @exports CreatePortResponse - * @classdesc Represents a CreatePortResponse. - * @implements ICreatePortResponse - * @constructor - * @param {ICreatePortResponse=} [properties] Properties to set - */ - function CreatePortResponse(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * CreatePortResponse messageIdentifier. - * @member {number} messageIdentifier - * @memberof CreatePortResponse - * @instance - */ - CreatePortResponse.prototype.messageIdentifier = 0; - - /** - * CreatePortResponse portId. - * @member {number} portId - * @memberof CreatePortResponse - * @instance - */ - CreatePortResponse.prototype.portId = 0; - - /** - * Creates a new CreatePortResponse instance using the specified properties. - * @function create - * @memberof CreatePortResponse - * @static - * @param {ICreatePortResponse=} [properties] Properties to set - * @returns {CreatePortResponse} CreatePortResponse instance - */ - CreatePortResponse.create = function create(properties) { - return new CreatePortResponse(properties); - }; - - /** - * Encodes the specified CreatePortResponse message. Does not implicitly {@link CreatePortResponse.verify|verify} messages. - * @function encode - * @memberof CreatePortResponse - * @static - * @param {ICreatePortResponse} message CreatePortResponse message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - CreatePortResponse.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); - return writer; - }; - - /** - * Encodes the specified CreatePortResponse message, length delimited. Does not implicitly {@link CreatePortResponse.verify|verify} messages. - * @function encodeDelimited - * @memberof CreatePortResponse - * @static - * @param {ICreatePortResponse} message CreatePortResponse message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - CreatePortResponse.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a CreatePortResponse message from the specified reader or buffer. - * @function decode - * @memberof CreatePortResponse - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {CreatePortResponse} CreatePortResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - CreatePortResponse.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.CreatePortResponse(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.portId = reader.fixed32(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a CreatePortResponse message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof CreatePortResponse - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {CreatePortResponse} CreatePortResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - CreatePortResponse.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a CreatePortResponse message. - * @function verify - * @memberof CreatePortResponse - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - CreatePortResponse.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portId != null && message.hasOwnProperty("portId")) - if (!$util.isInteger(message.portId)) - return "portId: integer expected"; - return null; - }; - - /** - * Creates a CreatePortResponse message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof CreatePortResponse - * @static - * @param {Object.} object Plain object - * @returns {CreatePortResponse} CreatePortResponse - */ - CreatePortResponse.fromObject = function fromObject(object) { - if (object instanceof $root.CreatePortResponse) - return object; - var message = new $root.CreatePortResponse(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portId != null) - message.portId = object.portId >>> 0; - return message; - }; - - /** - * Creates a plain object from a CreatePortResponse message. Also converts values to other types if specified. - * @function toObject - * @memberof CreatePortResponse - * @static - * @param {CreatePortResponse} message CreatePortResponse - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - CreatePortResponse.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.portId = 0; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portId != null && message.hasOwnProperty("portId")) - object.portId = message.portId; - return object; - }; - - /** - * Converts this CreatePortResponse to JSON. - * @function toJSON - * @memberof CreatePortResponse - * @instance - * @returns {Object.} JSON object - */ - CreatePortResponse.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return CreatePortResponse; -})(); - -$root.RequestModule = (function() { - - /** - * Properties of a RequestModule. - * @exports IRequestModule - * @interface IRequestModule - * @property {number|null} [messageIdentifier] RequestModule messageIdentifier - * @property {number|null} [portId] RequestModule portId - * @property {string|null} [moduleName] RequestModule moduleName - */ - - /** - * Constructs a new RequestModule. - * @exports RequestModule - * @classdesc Represents a RequestModule. - * @implements IRequestModule - * @constructor - * @param {IRequestModule=} [properties] Properties to set - */ - function RequestModule(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * RequestModule messageIdentifier. - * @member {number} messageIdentifier - * @memberof RequestModule - * @instance - */ - RequestModule.prototype.messageIdentifier = 0; - - /** - * RequestModule portId. - * @member {number} portId - * @memberof RequestModule - * @instance - */ - RequestModule.prototype.portId = 0; - - /** - * RequestModule moduleName. - * @member {string} moduleName - * @memberof RequestModule - * @instance - */ - RequestModule.prototype.moduleName = ""; - - /** - * Creates a new RequestModule instance using the specified properties. - * @function create - * @memberof RequestModule - * @static - * @param {IRequestModule=} [properties] Properties to set - * @returns {RequestModule} RequestModule instance - */ - RequestModule.create = function create(properties) { - return new RequestModule(properties); - }; - - /** - * Encodes the specified RequestModule message. Does not implicitly {@link RequestModule.verify|verify} messages. - * @function encode - * @memberof RequestModule - * @static - * @param {IRequestModule} message RequestModule message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RequestModule.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); - if (message.moduleName != null && Object.hasOwnProperty.call(message, "moduleName")) - writer.uint32(/* id 4, wireType 2 =*/34).string(message.moduleName); - return writer; - }; - - /** - * Encodes the specified RequestModule message, length delimited. Does not implicitly {@link RequestModule.verify|verify} messages. - * @function encodeDelimited - * @memberof RequestModule - * @static - * @param {IRequestModule} message RequestModule message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RequestModule.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a RequestModule message from the specified reader or buffer. - * @function decode - * @memberof RequestModule - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RequestModule} RequestModule - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RequestModule.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RequestModule(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.portId = reader.fixed32(); - break; - case 4: - message.moduleName = reader.string(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a RequestModule message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RequestModule - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RequestModule} RequestModule - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RequestModule.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a RequestModule message. - * @function verify - * @memberof RequestModule - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - RequestModule.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portId != null && message.hasOwnProperty("portId")) - if (!$util.isInteger(message.portId)) - return "portId: integer expected"; - if (message.moduleName != null && message.hasOwnProperty("moduleName")) - if (!$util.isString(message.moduleName)) - return "moduleName: string expected"; - return null; - }; - - /** - * Creates a RequestModule message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RequestModule - * @static - * @param {Object.} object Plain object - * @returns {RequestModule} RequestModule - */ - RequestModule.fromObject = function fromObject(object) { - if (object instanceof $root.RequestModule) - return object; - var message = new $root.RequestModule(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portId != null) - message.portId = object.portId >>> 0; - if (object.moduleName != null) - message.moduleName = String(object.moduleName); - return message; - }; - - /** - * Creates a plain object from a RequestModule message. Also converts values to other types if specified. - * @function toObject - * @memberof RequestModule - * @static - * @param {RequestModule} message RequestModule - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - RequestModule.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.portId = 0; - object.moduleName = ""; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portId != null && message.hasOwnProperty("portId")) - object.portId = message.portId; - if (message.moduleName != null && message.hasOwnProperty("moduleName")) - object.moduleName = message.moduleName; - return object; - }; - - /** - * Converts this RequestModule to JSON. - * @function toJSON - * @memberof RequestModule - * @instance - * @returns {Object.} JSON object - */ - RequestModule.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return RequestModule; -})(); - -$root.RequestModuleResponse = (function() { - - /** - * Properties of a RequestModuleResponse. - * @exports IRequestModuleResponse - * @interface IRequestModuleResponse - * @property {number|null} [messageIdentifier] RequestModuleResponse messageIdentifier - * @property {number|null} [portId] RequestModuleResponse portId - * @property {Array.|null} [procedures] RequestModuleResponse procedures - */ - - /** - * Constructs a new RequestModuleResponse. - * @exports RequestModuleResponse - * @classdesc Represents a RequestModuleResponse. - * @implements IRequestModuleResponse - * @constructor - * @param {IRequestModuleResponse=} [properties] Properties to set - */ - function RequestModuleResponse(properties) { - this.procedures = []; - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * RequestModuleResponse messageIdentifier. - * @member {number} messageIdentifier - * @memberof RequestModuleResponse - * @instance - */ - RequestModuleResponse.prototype.messageIdentifier = 0; - - /** - * RequestModuleResponse portId. - * @member {number} portId - * @memberof RequestModuleResponse - * @instance - */ - RequestModuleResponse.prototype.portId = 0; - - /** - * RequestModuleResponse procedures. - * @member {Array.} procedures - * @memberof RequestModuleResponse - * @instance - */ - RequestModuleResponse.prototype.procedures = $util.emptyArray; - - /** - * Creates a new RequestModuleResponse instance using the specified properties. - * @function create - * @memberof RequestModuleResponse - * @static - * @param {IRequestModuleResponse=} [properties] Properties to set - * @returns {RequestModuleResponse} RequestModuleResponse instance - */ - RequestModuleResponse.create = function create(properties) { - return new RequestModuleResponse(properties); - }; - - /** - * Encodes the specified RequestModuleResponse message. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. - * @function encode - * @memberof RequestModuleResponse - * @static - * @param {IRequestModuleResponse} message RequestModuleResponse message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RequestModuleResponse.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); - if (message.procedures != null && message.procedures.length) - for (var i = 0; i < message.procedures.length; ++i) - $root.ModuleProcedure.encode(message.procedures[i], writer.uint32(/* id 5, wireType 2 =*/42).fork()).ldelim(); - return writer; - }; - - /** - * Encodes the specified RequestModuleResponse message, length delimited. Does not implicitly {@link RequestModuleResponse.verify|verify} messages. - * @function encodeDelimited - * @memberof RequestModuleResponse - * @static - * @param {IRequestModuleResponse} message RequestModuleResponse message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RequestModuleResponse.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a RequestModuleResponse message from the specified reader or buffer. - * @function decode - * @memberof RequestModuleResponse - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RequestModuleResponse} RequestModuleResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RequestModuleResponse.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RequestModuleResponse(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.portId = reader.fixed32(); - break; - case 5: - if (!(message.procedures && message.procedures.length)) - message.procedures = []; - message.procedures.push($root.ModuleProcedure.decode(reader, reader.uint32())); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a RequestModuleResponse message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RequestModuleResponse - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RequestModuleResponse} RequestModuleResponse - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RequestModuleResponse.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a RequestModuleResponse message. - * @function verify - * @memberof RequestModuleResponse - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - RequestModuleResponse.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portId != null && message.hasOwnProperty("portId")) - if (!$util.isInteger(message.portId)) - return "portId: integer expected"; - if (message.procedures != null && message.hasOwnProperty("procedures")) { - if (!Array.isArray(message.procedures)) - return "procedures: array expected"; - for (var i = 0; i < message.procedures.length; ++i) { - var error = $root.ModuleProcedure.verify(message.procedures[i]); - if (error) - return "procedures." + error; - } - } - return null; - }; - - /** - * Creates a RequestModuleResponse message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RequestModuleResponse - * @static - * @param {Object.} object Plain object - * @returns {RequestModuleResponse} RequestModuleResponse - */ - RequestModuleResponse.fromObject = function fromObject(object) { - if (object instanceof $root.RequestModuleResponse) - return object; - var message = new $root.RequestModuleResponse(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portId != null) - message.portId = object.portId >>> 0; - if (object.procedures) { - if (!Array.isArray(object.procedures)) - throw TypeError(".RequestModuleResponse.procedures: array expected"); - message.procedures = []; - for (var i = 0; i < object.procedures.length; ++i) { - if (typeof object.procedures[i] !== "object") - throw TypeError(".RequestModuleResponse.procedures: object expected"); - message.procedures[i] = $root.ModuleProcedure.fromObject(object.procedures[i]); - } - } - return message; - }; - - /** - * Creates a plain object from a RequestModuleResponse message. Also converts values to other types if specified. - * @function toObject - * @memberof RequestModuleResponse - * @static - * @param {RequestModuleResponse} message RequestModuleResponse - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - RequestModuleResponse.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.arrays || options.defaults) - object.procedures = []; - if (options.defaults) { - object.messageIdentifier = 0; - object.portId = 0; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portId != null && message.hasOwnProperty("portId")) - object.portId = message.portId; - if (message.procedures && message.procedures.length) { - object.procedures = []; - for (var j = 0; j < message.procedures.length; ++j) - object.procedures[j] = $root.ModuleProcedure.toObject(message.procedures[j], options); - } - return object; - }; - - /** - * Converts this RequestModuleResponse to JSON. - * @function toJSON - * @memberof RequestModuleResponse - * @instance - * @returns {Object.} JSON object - */ - RequestModuleResponse.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return RequestModuleResponse; -})(); - -$root.DestroyPort = (function() { - - /** - * Properties of a DestroyPort. - * @exports IDestroyPort - * @interface IDestroyPort - * @property {number|null} [messageIdentifier] DestroyPort messageIdentifier - * @property {number|null} [portId] DestroyPort portId - */ - - /** - * Constructs a new DestroyPort. - * @exports DestroyPort - * @classdesc Represents a DestroyPort. - * @implements IDestroyPort - * @constructor - * @param {IDestroyPort=} [properties] Properties to set - */ - function DestroyPort(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * DestroyPort messageIdentifier. - * @member {number} messageIdentifier - * @memberof DestroyPort - * @instance - */ - DestroyPort.prototype.messageIdentifier = 0; - - /** - * DestroyPort portId. - * @member {number} portId - * @memberof DestroyPort - * @instance - */ - DestroyPort.prototype.portId = 0; - - /** - * Creates a new DestroyPort instance using the specified properties. - * @function create - * @memberof DestroyPort - * @static - * @param {IDestroyPort=} [properties] Properties to set - * @returns {DestroyPort} DestroyPort instance - */ - DestroyPort.create = function create(properties) { - return new DestroyPort(properties); - }; - - /** - * Encodes the specified DestroyPort message. Does not implicitly {@link DestroyPort.verify|verify} messages. - * @function encode - * @memberof DestroyPort - * @static - * @param {IDestroyPort} message DestroyPort message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - DestroyPort.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); - return writer; - }; - - /** - * Encodes the specified DestroyPort message, length delimited. Does not implicitly {@link DestroyPort.verify|verify} messages. - * @function encodeDelimited - * @memberof DestroyPort - * @static - * @param {IDestroyPort} message DestroyPort message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - DestroyPort.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a DestroyPort message from the specified reader or buffer. - * @function decode - * @memberof DestroyPort - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {DestroyPort} DestroyPort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - DestroyPort.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.DestroyPort(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.portId = reader.fixed32(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a DestroyPort message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof DestroyPort - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {DestroyPort} DestroyPort - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - DestroyPort.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a DestroyPort message. - * @function verify - * @memberof DestroyPort - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - DestroyPort.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portId != null && message.hasOwnProperty("portId")) - if (!$util.isInteger(message.portId)) - return "portId: integer expected"; - return null; - }; - - /** - * Creates a DestroyPort message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof DestroyPort - * @static - * @param {Object.} object Plain object - * @returns {DestroyPort} DestroyPort - */ - DestroyPort.fromObject = function fromObject(object) { - if (object instanceof $root.DestroyPort) - return object; - var message = new $root.DestroyPort(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portId != null) - message.portId = object.portId >>> 0; - return message; - }; - - /** - * Creates a plain object from a DestroyPort message. Also converts values to other types if specified. - * @function toObject - * @memberof DestroyPort - * @static - * @param {DestroyPort} message DestroyPort - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - DestroyPort.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.portId = 0; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portId != null && message.hasOwnProperty("portId")) - object.portId = message.portId; - return object; - }; - - /** - * Converts this DestroyPort to JSON. - * @function toJSON - * @memberof DestroyPort - * @instance - * @returns {Object.} JSON object - */ - DestroyPort.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return DestroyPort; -})(); - -$root.ModuleProcedure = (function() { - - /** - * Properties of a ModuleProcedure. - * @exports IModuleProcedure - * @interface IModuleProcedure - * @property {number|null} [procedureId] ModuleProcedure procedureId - * @property {string|null} [procedureName] ModuleProcedure procedureName - */ - - /** - * Constructs a new ModuleProcedure. - * @exports ModuleProcedure - * @classdesc Represents a ModuleProcedure. - * @implements IModuleProcedure - * @constructor - * @param {IModuleProcedure=} [properties] Properties to set - */ - function ModuleProcedure(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * ModuleProcedure procedureId. - * @member {number} procedureId - * @memberof ModuleProcedure - * @instance - */ - ModuleProcedure.prototype.procedureId = 0; - - /** - * ModuleProcedure procedureName. - * @member {string} procedureName - * @memberof ModuleProcedure - * @instance - */ - ModuleProcedure.prototype.procedureName = ""; - - /** - * Creates a new ModuleProcedure instance using the specified properties. - * @function create - * @memberof ModuleProcedure - * @static - * @param {IModuleProcedure=} [properties] Properties to set - * @returns {ModuleProcedure} ModuleProcedure instance - */ - ModuleProcedure.create = function create(properties) { - return new ModuleProcedure(properties); - }; - - /** - * Encodes the specified ModuleProcedure message. Does not implicitly {@link ModuleProcedure.verify|verify} messages. - * @function encode - * @memberof ModuleProcedure - * @static - * @param {IModuleProcedure} message ModuleProcedure message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ModuleProcedure.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.procedureId != null && Object.hasOwnProperty.call(message, "procedureId")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.procedureId); - if (message.procedureName != null && Object.hasOwnProperty.call(message, "procedureName")) - writer.uint32(/* id 2, wireType 2 =*/18).string(message.procedureName); - return writer; - }; - - /** - * Encodes the specified ModuleProcedure message, length delimited. Does not implicitly {@link ModuleProcedure.verify|verify} messages. - * @function encodeDelimited - * @memberof ModuleProcedure - * @static - * @param {IModuleProcedure} message ModuleProcedure message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - ModuleProcedure.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a ModuleProcedure message from the specified reader or buffer. - * @function decode - * @memberof ModuleProcedure - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {ModuleProcedure} ModuleProcedure - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ModuleProcedure.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.ModuleProcedure(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.procedureId = reader.fixed32(); - break; - case 2: - message.procedureName = reader.string(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a ModuleProcedure message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof ModuleProcedure - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {ModuleProcedure} ModuleProcedure - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - ModuleProcedure.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a ModuleProcedure message. - * @function verify - * @memberof ModuleProcedure - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - ModuleProcedure.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.procedureId != null && message.hasOwnProperty("procedureId")) - if (!$util.isInteger(message.procedureId)) - return "procedureId: integer expected"; - if (message.procedureName != null && message.hasOwnProperty("procedureName")) - if (!$util.isString(message.procedureName)) - return "procedureName: string expected"; - return null; - }; - - /** - * Creates a ModuleProcedure message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof ModuleProcedure - * @static - * @param {Object.} object Plain object - * @returns {ModuleProcedure} ModuleProcedure - */ - ModuleProcedure.fromObject = function fromObject(object) { - if (object instanceof $root.ModuleProcedure) - return object; - var message = new $root.ModuleProcedure(); - if (object.procedureId != null) - message.procedureId = object.procedureId >>> 0; - if (object.procedureName != null) - message.procedureName = String(object.procedureName); - return message; - }; - - /** - * Creates a plain object from a ModuleProcedure message. Also converts values to other types if specified. - * @function toObject - * @memberof ModuleProcedure - * @static - * @param {ModuleProcedure} message ModuleProcedure - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - ModuleProcedure.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.procedureId = 0; - object.procedureName = ""; - } - if (message.procedureId != null && message.hasOwnProperty("procedureId")) - object.procedureId = message.procedureId; - if (message.procedureName != null && message.hasOwnProperty("procedureName")) - object.procedureName = message.procedureName; - return object; - }; - - /** - * Converts this ModuleProcedure to JSON. - * @function toJSON - * @memberof ModuleProcedure - * @instance - * @returns {Object.} JSON object - */ - ModuleProcedure.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return ModuleProcedure; -})(); - -$root.Request = (function() { - - /** - * Properties of a Request. - * @exports IRequest - * @interface IRequest - * @property {number|null} [messageIdentifier] Request messageIdentifier - * @property {number|null} [portId] Request portId - * @property {number|null} [procedureId] Request procedureId - * @property {Uint8Array|null} [payload] Request payload - */ - - /** - * Constructs a new Request. - * @exports Request - * @classdesc Represents a Request. - * @implements IRequest - * @constructor - * @param {IRequest=} [properties] Properties to set - */ - function Request(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * Request messageIdentifier. - * @member {number} messageIdentifier - * @memberof Request - * @instance - */ - Request.prototype.messageIdentifier = 0; - - /** - * Request portId. - * @member {number} portId - * @memberof Request - * @instance - */ - Request.prototype.portId = 0; - - /** - * Request procedureId. - * @member {number} procedureId - * @memberof Request - * @instance - */ - Request.prototype.procedureId = 0; - - /** - * Request payload. - * @member {Uint8Array} payload - * @memberof Request - * @instance - */ - Request.prototype.payload = $util.newBuffer([]); - - /** - * Creates a new Request instance using the specified properties. - * @function create - * @memberof Request - * @static - * @param {IRequest=} [properties] Properties to set - * @returns {Request} Request instance - */ - Request.create = function create(properties) { - return new Request(properties); - }; - - /** - * Encodes the specified Request message. Does not implicitly {@link Request.verify|verify} messages. - * @function encode - * @memberof Request - * @static - * @param {IRequest} message Request message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - Request.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); - if (message.procedureId != null && Object.hasOwnProperty.call(message, "procedureId")) - writer.uint32(/* id 4, wireType 5 =*/37).fixed32(message.procedureId); - if (message.payload != null && Object.hasOwnProperty.call(message, "payload")) - writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.payload); - return writer; - }; - - /** - * Encodes the specified Request message, length delimited. Does not implicitly {@link Request.verify|verify} messages. - * @function encodeDelimited - * @memberof Request - * @static - * @param {IRequest} message Request message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - Request.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a Request message from the specified reader or buffer. - * @function decode - * @memberof Request - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {Request} Request - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - Request.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Request(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.portId = reader.fixed32(); - break; - case 4: - message.procedureId = reader.fixed32(); - break; - case 6: - message.payload = reader.bytes(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a Request message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof Request - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {Request} Request - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - Request.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a Request message. - * @function verify - * @memberof Request - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - Request.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portId != null && message.hasOwnProperty("portId")) - if (!$util.isInteger(message.portId)) - return "portId: integer expected"; - if (message.procedureId != null && message.hasOwnProperty("procedureId")) - if (!$util.isInteger(message.procedureId)) - return "procedureId: integer expected"; - if (message.payload != null && message.hasOwnProperty("payload")) - if (!(message.payload && typeof message.payload.length === "number" || $util.isString(message.payload))) - return "payload: buffer expected"; - return null; - }; - - /** - * Creates a Request message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof Request - * @static - * @param {Object.} object Plain object - * @returns {Request} Request - */ - Request.fromObject = function fromObject(object) { - if (object instanceof $root.Request) - return object; - var message = new $root.Request(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portId != null) - message.portId = object.portId >>> 0; - if (object.procedureId != null) - message.procedureId = object.procedureId >>> 0; - if (object.payload != null) - if (typeof object.payload === "string") - $util.base64.decode(object.payload, message.payload = $util.newBuffer($util.base64.length(object.payload)), 0); - else if (object.payload.length) - message.payload = object.payload; - return message; - }; - - /** - * Creates a plain object from a Request message. Also converts values to other types if specified. - * @function toObject - * @memberof Request - * @static - * @param {Request} message Request - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - Request.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.portId = 0; - object.procedureId = 0; - if (options.bytes === String) - object.payload = ""; - else { - object.payload = []; - if (options.bytes !== Array) - object.payload = $util.newBuffer(object.payload); - } - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portId != null && message.hasOwnProperty("portId")) - object.portId = message.portId; - if (message.procedureId != null && message.hasOwnProperty("procedureId")) - object.procedureId = message.procedureId; - if (message.payload != null && message.hasOwnProperty("payload")) - object.payload = options.bytes === String ? $util.base64.encode(message.payload, 0, message.payload.length) : options.bytes === Array ? Array.prototype.slice.call(message.payload) : message.payload; - return object; - }; - - /** - * Converts this Request to JSON. - * @function toJSON - * @memberof Request - * @instance - * @returns {Object.} JSON object - */ - Request.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return Request; -})(); - -$root.RemoteError = (function() { - - /** - * Properties of a RemoteError. - * @exports IRemoteError - * @interface IRemoteError - * @property {number|null} [messageIdentifier] RemoteError messageIdentifier - * @property {number|null} [errorCode] RemoteError errorCode - * @property {string|null} [errorMessage] RemoteError errorMessage - */ - - /** - * Constructs a new RemoteError. - * @exports RemoteError - * @classdesc Represents a RemoteError. - * @implements IRemoteError - * @constructor - * @param {IRemoteError=} [properties] Properties to set - */ - function RemoteError(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * RemoteError messageIdentifier. - * @member {number} messageIdentifier - * @memberof RemoteError - * @instance - */ - RemoteError.prototype.messageIdentifier = 0; - - /** - * RemoteError errorCode. - * @member {number} errorCode - * @memberof RemoteError - * @instance - */ - RemoteError.prototype.errorCode = 0; - - /** - * RemoteError errorMessage. - * @member {string} errorMessage - * @memberof RemoteError - * @instance - */ - RemoteError.prototype.errorMessage = ""; - - /** - * Creates a new RemoteError instance using the specified properties. - * @function create - * @memberof RemoteError - * @static - * @param {IRemoteError=} [properties] Properties to set - * @returns {RemoteError} RemoteError instance - */ - RemoteError.create = function create(properties) { - return new RemoteError(properties); - }; - - /** - * Encodes the specified RemoteError message. Does not implicitly {@link RemoteError.verify|verify} messages. - * @function encode - * @memberof RemoteError - * @static - * @param {IRemoteError} message RemoteError message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RemoteError.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.errorCode != null && Object.hasOwnProperty.call(message, "errorCode")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.errorCode); - if (message.errorMessage != null && Object.hasOwnProperty.call(message, "errorMessage")) - writer.uint32(/* id 3, wireType 2 =*/26).string(message.errorMessage); - return writer; - }; - - /** - * Encodes the specified RemoteError message, length delimited. Does not implicitly {@link RemoteError.verify|verify} messages. - * @function encodeDelimited - * @memberof RemoteError - * @static - * @param {IRemoteError} message RemoteError message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - RemoteError.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a RemoteError message from the specified reader or buffer. - * @function decode - * @memberof RemoteError - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {RemoteError} RemoteError - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RemoteError.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.RemoteError(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.errorCode = reader.fixed32(); - break; - case 3: - message.errorMessage = reader.string(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a RemoteError message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof RemoteError - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {RemoteError} RemoteError - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - RemoteError.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a RemoteError message. - * @function verify - * @memberof RemoteError - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - RemoteError.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.errorCode != null && message.hasOwnProperty("errorCode")) - if (!$util.isInteger(message.errorCode)) - return "errorCode: integer expected"; - if (message.errorMessage != null && message.hasOwnProperty("errorMessage")) - if (!$util.isString(message.errorMessage)) - return "errorMessage: string expected"; - return null; - }; - - /** - * Creates a RemoteError message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof RemoteError - * @static - * @param {Object.} object Plain object - * @returns {RemoteError} RemoteError - */ - RemoteError.fromObject = function fromObject(object) { - if (object instanceof $root.RemoteError) - return object; - var message = new $root.RemoteError(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.errorCode != null) - message.errorCode = object.errorCode >>> 0; - if (object.errorMessage != null) - message.errorMessage = String(object.errorMessage); - return message; - }; - - /** - * Creates a plain object from a RemoteError message. Also converts values to other types if specified. - * @function toObject - * @memberof RemoteError - * @static - * @param {RemoteError} message RemoteError - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - RemoteError.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.errorCode = 0; - object.errorMessage = ""; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.errorCode != null && message.hasOwnProperty("errorCode")) - object.errorCode = message.errorCode; - if (message.errorMessage != null && message.hasOwnProperty("errorMessage")) - object.errorMessage = message.errorMessage; - return object; - }; - - /** - * Converts this RemoteError to JSON. - * @function toJSON - * @memberof RemoteError - * @instance - * @returns {Object.} JSON object - */ - RemoteError.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return RemoteError; -})(); - -$root.Response = (function() { - - /** - * Properties of a Response. - * @exports IResponse - * @interface IResponse - * @property {number|null} [messageIdentifier] Response messageIdentifier - * @property {Uint8Array|null} [payload] Response payload - */ - - /** - * Constructs a new Response. - * @exports Response - * @classdesc Represents a Response. - * @implements IResponse - * @constructor - * @param {IResponse=} [properties] Properties to set - */ - function Response(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * Response messageIdentifier. - * @member {number} messageIdentifier - * @memberof Response - * @instance - */ - Response.prototype.messageIdentifier = 0; - - /** - * Response payload. - * @member {Uint8Array} payload - * @memberof Response - * @instance - */ - Response.prototype.payload = $util.newBuffer([]); - - /** - * Creates a new Response instance using the specified properties. - * @function create - * @memberof Response - * @static - * @param {IResponse=} [properties] Properties to set - * @returns {Response} Response instance - */ - Response.create = function create(properties) { - return new Response(properties); - }; - - /** - * Encodes the specified Response message. Does not implicitly {@link Response.verify|verify} messages. - * @function encode - * @memberof Response - * @static - * @param {IResponse} message Response message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - Response.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.payload != null && Object.hasOwnProperty.call(message, "payload")) - writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.payload); - return writer; - }; - - /** - * Encodes the specified Response message, length delimited. Does not implicitly {@link Response.verify|verify} messages. - * @function encodeDelimited - * @memberof Response - * @static - * @param {IResponse} message Response message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - Response.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a Response message from the specified reader or buffer. - * @function decode - * @memberof Response - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {Response} Response - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - Response.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.Response(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 6: - message.payload = reader.bytes(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a Response message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof Response - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {Response} Response - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - Response.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a Response message. - * @function verify - * @memberof Response - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - Response.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.payload != null && message.hasOwnProperty("payload")) - if (!(message.payload && typeof message.payload.length === "number" || $util.isString(message.payload))) - return "payload: buffer expected"; - return null; - }; - - /** - * Creates a Response message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof Response - * @static - * @param {Object.} object Plain object - * @returns {Response} Response - */ - Response.fromObject = function fromObject(object) { - if (object instanceof $root.Response) - return object; - var message = new $root.Response(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.payload != null) - if (typeof object.payload === "string") - $util.base64.decode(object.payload, message.payload = $util.newBuffer($util.base64.length(object.payload)), 0); - else if (object.payload.length) - message.payload = object.payload; - return message; - }; - - /** - * Creates a plain object from a Response message. Also converts values to other types if specified. - * @function toObject - * @memberof Response - * @static - * @param {Response} message Response - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - Response.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - if (options.bytes === String) - object.payload = ""; - else { - object.payload = []; - if (options.bytes !== Array) - object.payload = $util.newBuffer(object.payload); - } - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.payload != null && message.hasOwnProperty("payload")) - object.payload = options.bytes === String ? $util.base64.encode(message.payload, 0, message.payload.length) : options.bytes === Array ? Array.prototype.slice.call(message.payload) : message.payload; - return object; - }; - - /** - * Converts this Response to JSON. - * @function toJSON - * @memberof Response - * @instance - * @returns {Object.} JSON object - */ - Response.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return Response; -})(); - -$root.StreamMessage = (function() { - - /** - * Properties of a StreamMessage. - * @exports IStreamMessage - * @interface IStreamMessage - * @property {number|null} [messageIdentifier] StreamMessage messageIdentifier - * @property {number|null} [portId] StreamMessage portId - * @property {number|null} [sequenceId] StreamMessage sequenceId - * @property {Uint8Array|null} [payload] StreamMessage payload - * @property {boolean|null} [closed] StreamMessage closed - * @property {boolean|null} [ack] StreamMessage ack - */ - - /** - * Constructs a new StreamMessage. - * @exports StreamMessage - * @classdesc Represents a StreamMessage. - * @implements IStreamMessage - * @constructor - * @param {IStreamMessage=} [properties] Properties to set - */ - function StreamMessage(properties) { - if (properties) - for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) - if (properties[keys[i]] != null) - this[keys[i]] = properties[keys[i]]; - } - - /** - * StreamMessage messageIdentifier. - * @member {number} messageIdentifier - * @memberof StreamMessage - * @instance - */ - StreamMessage.prototype.messageIdentifier = 0; - - /** - * StreamMessage portId. - * @member {number} portId - * @memberof StreamMessage - * @instance - */ - StreamMessage.prototype.portId = 0; - - /** - * StreamMessage sequenceId. - * @member {number} sequenceId - * @memberof StreamMessage - * @instance - */ - StreamMessage.prototype.sequenceId = 0; - - /** - * StreamMessage payload. - * @member {Uint8Array} payload - * @memberof StreamMessage - * @instance - */ - StreamMessage.prototype.payload = $util.newBuffer([]); - - /** - * StreamMessage closed. - * @member {boolean} closed - * @memberof StreamMessage - * @instance - */ - StreamMessage.prototype.closed = false; - - /** - * StreamMessage ack. - * @member {boolean} ack - * @memberof StreamMessage - * @instance - */ - StreamMessage.prototype.ack = false; - - /** - * Creates a new StreamMessage instance using the specified properties. - * @function create - * @memberof StreamMessage - * @static - * @param {IStreamMessage=} [properties] Properties to set - * @returns {StreamMessage} StreamMessage instance - */ - StreamMessage.create = function create(properties) { - return new StreamMessage(properties); - }; - - /** - * Encodes the specified StreamMessage message. Does not implicitly {@link StreamMessage.verify|verify} messages. - * @function encode - * @memberof StreamMessage - * @static - * @param {IStreamMessage} message StreamMessage message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - StreamMessage.encode = function encode(message, writer) { - if (!writer) - writer = $Writer.create(); - if (message.messageIdentifier != null && Object.hasOwnProperty.call(message, "messageIdentifier")) - writer.uint32(/* id 1, wireType 5 =*/13).fixed32(message.messageIdentifier); - if (message.portId != null && Object.hasOwnProperty.call(message, "portId")) - writer.uint32(/* id 2, wireType 5 =*/21).fixed32(message.portId); - if (message.sequenceId != null && Object.hasOwnProperty.call(message, "sequenceId")) - writer.uint32(/* id 4, wireType 5 =*/37).fixed32(message.sequenceId); - if (message.payload != null && Object.hasOwnProperty.call(message, "payload")) - writer.uint32(/* id 6, wireType 2 =*/50).bytes(message.payload); - if (message.closed != null && Object.hasOwnProperty.call(message, "closed")) - writer.uint32(/* id 7, wireType 0 =*/56).bool(message.closed); - if (message.ack != null && Object.hasOwnProperty.call(message, "ack")) - writer.uint32(/* id 8, wireType 0 =*/64).bool(message.ack); - return writer; - }; - - /** - * Encodes the specified StreamMessage message, length delimited. Does not implicitly {@link StreamMessage.verify|verify} messages. - * @function encodeDelimited - * @memberof StreamMessage - * @static - * @param {IStreamMessage} message StreamMessage message or plain object to encode - * @param {$protobuf.Writer} [writer] Writer to encode to - * @returns {$protobuf.Writer} Writer - */ - StreamMessage.encodeDelimited = function encodeDelimited(message, writer) { - return this.encode(message, writer).ldelim(); - }; - - /** - * Decodes a StreamMessage message from the specified reader or buffer. - * @function decode - * @memberof StreamMessage - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @param {number} [length] Message length if known beforehand - * @returns {StreamMessage} StreamMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - StreamMessage.decode = function decode(reader, length) { - if (!(reader instanceof $Reader)) - reader = $Reader.create(reader); - var end = length === undefined ? reader.len : reader.pos + length, message = new $root.StreamMessage(); - while (reader.pos < end) { - var tag = reader.uint32(); - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32(); - break; - case 2: - message.portId = reader.fixed32(); - break; - case 4: - message.sequenceId = reader.fixed32(); - break; - case 6: - message.payload = reader.bytes(); - break; - case 7: - message.closed = reader.bool(); - break; - case 8: - message.ack = reader.bool(); - break; - default: - reader.skipType(tag & 7); - break; - } - } - return message; - }; - - /** - * Decodes a StreamMessage message from the specified reader or buffer, length delimited. - * @function decodeDelimited - * @memberof StreamMessage - * @static - * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from - * @returns {StreamMessage} StreamMessage - * @throws {Error} If the payload is not a reader or valid buffer - * @throws {$protobuf.util.ProtocolError} If required fields are missing - */ - StreamMessage.decodeDelimited = function decodeDelimited(reader) { - if (!(reader instanceof $Reader)) - reader = new $Reader(reader); - return this.decode(reader, reader.uint32()); - }; - - /** - * Verifies a StreamMessage message. - * @function verify - * @memberof StreamMessage - * @static - * @param {Object.} message Plain object to verify - * @returns {string|null} `null` if valid, otherwise the reason why it is not - */ - StreamMessage.verify = function verify(message) { - if (typeof message !== "object" || message === null) - return "object expected"; - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - if (!$util.isInteger(message.messageIdentifier)) - return "messageIdentifier: integer expected"; - if (message.portId != null && message.hasOwnProperty("portId")) - if (!$util.isInteger(message.portId)) - return "portId: integer expected"; - if (message.sequenceId != null && message.hasOwnProperty("sequenceId")) - if (!$util.isInteger(message.sequenceId)) - return "sequenceId: integer expected"; - if (message.payload != null && message.hasOwnProperty("payload")) - if (!(message.payload && typeof message.payload.length === "number" || $util.isString(message.payload))) - return "payload: buffer expected"; - if (message.closed != null && message.hasOwnProperty("closed")) - if (typeof message.closed !== "boolean") - return "closed: boolean expected"; - if (message.ack != null && message.hasOwnProperty("ack")) - if (typeof message.ack !== "boolean") - return "ack: boolean expected"; - return null; - }; - - /** - * Creates a StreamMessage message from a plain object. Also converts values to their respective internal types. - * @function fromObject - * @memberof StreamMessage - * @static - * @param {Object.} object Plain object - * @returns {StreamMessage} StreamMessage - */ - StreamMessage.fromObject = function fromObject(object) { - if (object instanceof $root.StreamMessage) - return object; - var message = new $root.StreamMessage(); - if (object.messageIdentifier != null) - message.messageIdentifier = object.messageIdentifier >>> 0; - if (object.portId != null) - message.portId = object.portId >>> 0; - if (object.sequenceId != null) - message.sequenceId = object.sequenceId >>> 0; - if (object.payload != null) - if (typeof object.payload === "string") - $util.base64.decode(object.payload, message.payload = $util.newBuffer($util.base64.length(object.payload)), 0); - else if (object.payload.length) - message.payload = object.payload; - if (object.closed != null) - message.closed = Boolean(object.closed); - if (object.ack != null) - message.ack = Boolean(object.ack); - return message; - }; - - /** - * Creates a plain object from a StreamMessage message. Also converts values to other types if specified. - * @function toObject - * @memberof StreamMessage - * @static - * @param {StreamMessage} message StreamMessage - * @param {$protobuf.IConversionOptions} [options] Conversion options - * @returns {Object.} Plain object - */ - StreamMessage.toObject = function toObject(message, options) { - if (!options) - options = {}; - var object = {}; - if (options.defaults) { - object.messageIdentifier = 0; - object.portId = 0; - object.sequenceId = 0; - if (options.bytes === String) - object.payload = ""; - else { - object.payload = []; - if (options.bytes !== Array) - object.payload = $util.newBuffer(object.payload); - } - object.closed = false; - object.ack = false; - } - if (message.messageIdentifier != null && message.hasOwnProperty("messageIdentifier")) - object.messageIdentifier = message.messageIdentifier; - if (message.portId != null && message.hasOwnProperty("portId")) - object.portId = message.portId; - if (message.sequenceId != null && message.hasOwnProperty("sequenceId")) - object.sequenceId = message.sequenceId; - if (message.payload != null && message.hasOwnProperty("payload")) - object.payload = options.bytes === String ? $util.base64.encode(message.payload, 0, message.payload.length) : options.bytes === Array ? Array.prototype.slice.call(message.payload) : message.payload; - if (message.closed != null && message.hasOwnProperty("closed")) - object.closed = message.closed; - if (message.ack != null && message.hasOwnProperty("ack")) - object.ack = message.ack; - return object; - }; - - /** - * Converts this StreamMessage to JSON. - * @function toJSON - * @memberof StreamMessage - * @instance - * @returns {Object.} JSON object - */ - StreamMessage.prototype.toJSON = function toJSON() { - return this.constructor.toObject(this, $protobuf.util.toJSONOptions); - }; - - return StreamMessage; -})(); - -module.exports = $root; diff --git a/src/server.ts b/src/server.ts index 8763027..439ccd0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -8,7 +8,7 @@ import { Transport, } from "./types" import mitt from "mitt" -import { Writer, Reader } from "protobufjs" +import { Writer, Reader } from "protobufjs/minimal" import { AsyncProcedureResultServer, RpcPortEvents, ServerModuleDeclaration } from "." import { AckDispatcher, createAckHelper } from "./ack-helper" import { calculateMessageIdentifier, closeStreamMessage, parseProtocolMessage } from "./protocol/helpers" @@ -24,7 +24,7 @@ import { RpcMessageHeader, RpcMessageTypes, StreamMessage, -} from "./protocol/pbjs" +} from "./protocol" let lastPortId = 0 @@ -258,7 +258,7 @@ export async function handleRequest( } const result = await port.callProcedure(request.procedureId, request.payload) - const response = Response.create({ + const response = Response.fromJSON({ messageIdentifier: calculateMessageIdentifier(RpcMessageTypes.RpcMessageTypes_RESPONSE, messageNumber), payload: Uint8Array.from([]), }) @@ -272,7 +272,7 @@ export async function handleRequest( const iter: AsyncGenerator = await (result as any)[Symbol.asyncIterator]() let sequenceNumber = -1 - const reusedStreamMessage: StreamMessage = StreamMessage.create({ + const reusedStreamMessage: StreamMessage = StreamMessage.fromJSON({ closed: false, ack: false, sequenceId: 0, diff --git a/test/bench.ts b/test/bench.ts index 54e3443..280cdb1 100644 --- a/test/bench.ts +++ b/test/bench.ts @@ -1,6 +1,6 @@ import { Suite } from "benchmark" import * as helpers from "./helpers" -import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client_pb" +import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client" import { RpcClientPort, RpcServerPort } from "../src" import { clientProcedureStream, @@ -45,16 +45,16 @@ async function test() { async initializePort(port) { registerBookService(port, async () => ({ async GetBook(req) { - if (req.getIsbn() == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") + if (req.isbn == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") - const book = new Book() - book.setAuthor("menduz") - book.setIsbn(req.getIsbn()) - book.setTitle("Rpc onion layers") - return book + return { + author: "menduz", + isbn: req.isbn, + title: "Rpc onion layers", + } }, async *QueryBooks(req) { - if (req.getAuthorPrefix() == "fail_before_yield") throw new Error("fail_before_yield") + if (req.authorPrefix == "fail_before_yield") throw new Error("fail_before_yield") const books = [ { author: "mr menduz", isbn: 1234, title: "1001 reasons to write your own OS" }, @@ -64,16 +64,12 @@ async function test() { ] for (const book of books) { - if (book.author.includes(req.getAuthorPrefix())) { - const protoBook = new Book() - protoBook.setAuthor(book.author) - protoBook.setIsbn(book.isbn) - protoBook.setTitle(book.title) - yield protoBook + if (book.author.includes(req.authorPrefix)) { + yield book } } - if (req.getAuthorPrefix() == "fail_before_end") throw new Error("fail_before_end") + if (req.authorPrefix == "fail_before_end") throw new Error("fail_before_end") }, })) }, @@ -83,19 +79,14 @@ async function test() { const clientPort = await rpcClient.createPort("test1") const service = loadBookService(clientPort) - const req1 = new GetBookRequest() - const req2 = new QueryBooksRequest() - req1.setIsbn(1234) - req2.setAuthorPrefix("mr") - const suite = new Suite() suite .add("GetBook", { defer: true, async fn(deferred) { - const ret = await service.GetBook(req1) - if (ret.getIsbn() != 1234) deferred.reject(new Error("invalid number")) + const ret = await service.GetBook({ isbn: 1234 }) + if (ret.isbn != 1234) deferred.reject(new Error("invalid number")) deferred.resolve() }, }) @@ -104,7 +95,7 @@ async function test() { async fn(deferred) { const results = [] - for await (const book of service.QueryBooks(req2)) { + for await (const book of service.QueryBooks({ authorPrefix: "mr" })) { results.push(book) } @@ -112,11 +103,11 @@ async function test() { deferred.resolve() }, }) - .on("cycle", function(event) { - console.log(String(event.target)); + .on("cycle", function (event) { + console.log(String(event.target)) }) - .on("complete", function() { - console.log("Fastest is " + this.filter("fastest").map("name")); + .on("complete", function () { + console.log("Fastest is " + this.filter("fastest").map("name")) }) .run({ async: true }) } diff --git a/test/close-transport.spec.ts b/test/close-transport.spec.ts index 20f2bfc..defca3c 100644 --- a/test/close-transport.spec.ts +++ b/test/close-transport.spec.ts @@ -1,6 +1,6 @@ import { RpcClient } from "../src" import { calculateMessageIdentifier } from "../src/protocol/helpers" -import { RpcMessageHeader, RpcMessageTypes } from "../src/protocol/pbjs" +import { RpcMessageHeader, RpcMessageTypes } from "../src/protocol" import { createSimpleTestEnvironment } from "./helpers" async function testPort(rpcClient: RpcClient, portName: string) { diff --git a/test/codegen-client.spec.ts b/test/codegen-client.spec.ts index 62d3cf5..13d9407 100644 --- a/test/codegen-client.spec.ts +++ b/test/codegen-client.spec.ts @@ -1,6 +1,6 @@ import { RpcClientPort } from "../src" import { clientProcedureStream, clientProcedureUnary } from "../src/codegen" -import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client_pb" +import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client" import { createSimpleTestEnvironment, takeAsync } from "./helpers" /// service BookService { @@ -27,20 +27,20 @@ describe("codegen client", () => { async initializePort(port) { port.registerModule("BookService", async (port) => ({ async GetBook(arg: Uint8Array) { - const req = GetBookRequest.deserializeBinary(arg) + const req = GetBookRequest.decode(arg) - if (req.getIsbn() == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") + if (req.isbn == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") - const book = new Book() - book.setAuthor("menduz") - book.setIsbn(req.getIsbn()) - book.setTitle("Rpc onion layers") - return book.serializeBinary() + return Book.encode({ + author: "menduz", + isbn: req.isbn, + title: "Rpc onion layers", + }).finish() }, async *QueryBooks(arg: Uint8Array) { - const req = QueryBooksRequest.deserializeBinary(arg) + const req = QueryBooksRequest.decode(arg) - if (req.getAuthorPrefix() == "fail_before_yield") throw new Error("fail_before_yield") + if (req.authorPrefix == "fail_before_yield") throw new Error("fail_before_yield") const books = [ { author: "mr menduz", isbn: 1234, title: "1001 reasons to write your own OS" }, @@ -50,16 +50,12 @@ describe("codegen client", () => { ] for (const book of books) { - if (book.author.includes(req.getAuthorPrefix())) { - const protoBook = new Book() - protoBook.setAuthor(book.author) - protoBook.setIsbn(book.isbn) - protoBook.setTitle(book.title) - yield protoBook.serializeBinary() + if (book.author.includes(req.authorPrefix)) { + yield Book.encode(book).finish() } } - if (req.getAuthorPrefix() == "fail_before_end") throw new Error("fail_before_end") + if (req.authorPrefix == "fail_before_end") throw new Error("fail_before_end") }, })) }, @@ -75,23 +71,16 @@ describe("codegen client", () => { }) it("calls an unary method", async () => { - const req = new GetBookRequest() - req.setIsbn(1234) - const ret = await service.GetBook(req) - expect(ret).toBeInstanceOf(Book) - expect(ret.getIsbn()).toEqual(1234) - expect(ret.getAuthor()).toEqual("menduz") + const ret = await service.GetBook({ isbn: 1234 }) + expect(ret.isbn).toEqual(1234) + expect(ret.author).toEqual("menduz") }) it("calls a streaming method", async () => { - const req = new QueryBooksRequest() - req.setAuthorPrefix("mr") - const results: Book[] = [] - for await (const book of service.QueryBooks(req)) { - expect(book).toBeInstanceOf(Book) - expect(book.getAuthor()).toMatch(/^mr\s.+/) + for await (const book of service.QueryBooks({ authorPrefix: "mr" })) { + expect(book.author).toMatch(/^mr\s.+/) results.push(book) } @@ -99,20 +88,18 @@ describe("codegen client", () => { }) it("calls to unary fails throws error in client", async () => { - const req = new GetBookRequest() - req.setIsbn(FAIL_WITH_EXCEPTION_ISBN) - await expect(service.GetBook(req)).rejects.toThrowError("RemoteError: ErrorMessage") + await expect(service.GetBook({ isbn: FAIL_WITH_EXCEPTION_ISBN })).rejects.toThrowError("RemoteError: ErrorMessage") }) it("calls to streaming fails throws error in client, fail_before_yield", async () => { - const req = new QueryBooksRequest() - req.setAuthorPrefix("fail_before_yield") - await expect(service.QueryBooks(req).next()).rejects.toThrowError("RemoteError: fail_before_yield") + await expect(service.QueryBooks({ authorPrefix: "fail_before_yield" }).next()).rejects.toThrowError( + "RemoteError: fail_before_yield" + ) }) it("calls to streaming fails throws error in client, fail_before_end", async () => { - const req = new QueryBooksRequest() - req.setAuthorPrefix("fail_before_end") - await expect(() => takeAsync(service.QueryBooks(req))).rejects.toThrowError("RemoteError: fail_before_end") + await expect(() => takeAsync(service.QueryBooks({ authorPrefix: "fail_before_end" }))).rejects.toThrowError( + "RemoteError: fail_before_end" + ) }) }) diff --git a/test/codegen-server.spec.ts b/test/codegen-server.spec.ts index e837e07..54978ec 100644 --- a/test/codegen-server.spec.ts +++ b/test/codegen-server.spec.ts @@ -1,5 +1,5 @@ import { RpcServerPort } from "../src" -import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client_pb" +import { Book, GetBookRequest, QueryBooksRequest } from "./codegen/client" import { createSimpleTestEnvironment, takeAsync } from "./helpers" import * as codegen from "../src/codegen" import { loadBookService } from "./codegen-client.spec" @@ -32,16 +32,16 @@ describe("codegen client & server", () => { async initializePort(port) { registerBookService(port, async () => ({ async GetBook(req: GetBookRequest) { - if (req.getIsbn() == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") + if (req.isbn == FAIL_WITH_EXCEPTION_ISBN) throw new Error("ErrorMessage") - const book = new Book() - book.setAuthor("menduz") - book.setIsbn(req.getIsbn()) - book.setTitle("Rpc onion layers") - return book + return { + author: "menduz", + isbn: req.isbn, + title: "Rpc onion layers", + } }, async *QueryBooks(req: QueryBooksRequest) { - if (req.getAuthorPrefix() == "fail_before_yield") throw new Error("fail_before_yield") + if (req.authorPrefix == "fail_before_yield") throw new Error("fail_before_yield") const books = [ { author: "mr menduz", isbn: 1234, title: "1001 reasons to write your own OS" }, @@ -51,16 +51,12 @@ describe("codegen client & server", () => { ] for (const book of books) { - if (book.author.includes(req.getAuthorPrefix())) { - const protoBook = new Book() - protoBook.setAuthor(book.author) - protoBook.setIsbn(book.isbn) - protoBook.setTitle(book.title) - yield protoBook + if (book.author.includes(req.authorPrefix)) { + yield book } } - if (req.getAuthorPrefix() == "fail_before_end") throw new Error("fail_before_end") + if (req.authorPrefix == "fail_before_end") throw new Error("fail_before_end") }, })) }, @@ -76,23 +72,16 @@ describe("codegen client & server", () => { }) it("calls an unary method", async () => { - const req = new GetBookRequest() - req.setIsbn(1234) - const ret = await service.GetBook(req) - expect(ret).toBeInstanceOf(Book) - expect(ret.getIsbn()).toEqual(1234) - expect(ret.getAuthor()).toEqual("menduz") + const ret = await service.GetBook({ isbn: 1234 }) + expect(ret.isbn).toEqual(1234) + expect(ret.author).toEqual("menduz") }) it("calls a streaming method", async () => { - const req = new QueryBooksRequest() - req.setAuthorPrefix("mr") - const results: Book[] = [] - for await (const book of service.QueryBooks(req)) { - expect(book).toBeInstanceOf(Book) - expect(book.getAuthor()).toMatch(/^mr\s.+/) + for await (const book of service.QueryBooks({ authorPrefix: "mr" })) { + expect(book.author).toMatch(/^mr\s.+/) results.push(book) } @@ -100,20 +89,18 @@ describe("codegen client & server", () => { }) it("calls to unary fails throws error in client", async () => { - const req = new GetBookRequest() - req.setIsbn(FAIL_WITH_EXCEPTION_ISBN) - await expect(service.GetBook(req)).rejects.toThrowError("RemoteError: ErrorMessage") + await expect(service.GetBook({ isbn: FAIL_WITH_EXCEPTION_ISBN })).rejects.toThrowError("RemoteError: ErrorMessage") }) it("calls to streaming fails throws error in client, fail_before_yield", async () => { - const req = new QueryBooksRequest() - req.setAuthorPrefix("fail_before_yield") - await expect(service.QueryBooks(req).next()).rejects.toThrowError("RemoteError: fail_before_yield") + await expect(service.QueryBooks({ authorPrefix: "fail_before_yield" }).next()).rejects.toThrowError( + "RemoteError: fail_before_yield" + ) }) it("calls to streaming fails throws error in client, fail_before_end", async () => { - const req = new QueryBooksRequest() - req.setAuthorPrefix("fail_before_end") - await expect(() => takeAsync(service.QueryBooks(req))).rejects.toThrowError("RemoteError: fail_before_end") + await expect(() => takeAsync(service.QueryBooks({ authorPrefix: "fail_before_end" }))).rejects.toThrowError( + "RemoteError: fail_before_end" + ) }) }) diff --git a/test/codegen/client.ts b/test/codegen/client.ts new file mode 100644 index 0000000..52ed2fd --- /dev/null +++ b/test/codegen/client.ts @@ -0,0 +1,228 @@ +/* eslint-disable */ +import Long from "long" +import * as _m0 from "protobufjs/minimal" + +export const protobufPackage = "" + +export interface Book { + isbn: number + title: string + author: string +} + +export interface GetBookRequest { + isbn: number +} + +export interface QueryBooksRequest { + authorPrefix: string +} + +function createBaseBook(): Book { + return { isbn: 0, title: "", author: "" } +} + +export const Book = { + encode(message: Book, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.isbn !== 0) { + writer.uint32(8).int64(message.isbn) + } + if (message.title !== "") { + writer.uint32(18).string(message.title) + } + if (message.author !== "") { + writer.uint32(26).string(message.author) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): Book { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseBook() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.isbn = longToNumber(reader.int64() as Long) + break + case 2: + message.title = reader.string() + break + case 3: + message.author = reader.string() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): Book { + return { + isbn: isSet(object.isbn) ? Number(object.isbn) : 0, + title: isSet(object.title) ? String(object.title) : "", + author: isSet(object.author) ? String(object.author) : "", + } + }, + + toJSON(message: Book): unknown { + const obj: any = {} + message.isbn !== undefined && (obj.isbn = Math.round(message.isbn)) + message.title !== undefined && (obj.title = message.title) + message.author !== undefined && (obj.author = message.author) + return obj + }, + + fromPartial, I>>(object: I): Book { + const message = createBaseBook() + message.isbn = object.isbn ?? 0 + message.title = object.title ?? "" + message.author = object.author ?? "" + return message + }, +} + +function createBaseGetBookRequest(): GetBookRequest { + return { isbn: 0 } +} + +export const GetBookRequest = { + encode(message: GetBookRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.isbn !== 0) { + writer.uint32(8).int64(message.isbn) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): GetBookRequest { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseGetBookRequest() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.isbn = longToNumber(reader.int64() as Long) + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): GetBookRequest { + return { + isbn: isSet(object.isbn) ? Number(object.isbn) : 0, + } + }, + + toJSON(message: GetBookRequest): unknown { + const obj: any = {} + message.isbn !== undefined && (obj.isbn = Math.round(message.isbn)) + return obj + }, + + fromPartial, I>>(object: I): GetBookRequest { + const message = createBaseGetBookRequest() + message.isbn = object.isbn ?? 0 + return message + }, +} + +function createBaseQueryBooksRequest(): QueryBooksRequest { + return { authorPrefix: "" } +} + +export const QueryBooksRequest = { + encode(message: QueryBooksRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.authorPrefix !== "") { + writer.uint32(10).string(message.authorPrefix) + } + return writer + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): QueryBooksRequest { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseQueryBooksRequest() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: + message.authorPrefix = reader.string() + break + default: + reader.skipType(tag & 7) + break + } + } + return message + }, + + fromJSON(object: any): QueryBooksRequest { + return { + authorPrefix: isSet(object.authorPrefix) ? String(object.authorPrefix) : "", + } + }, + + toJSON(message: QueryBooksRequest): unknown { + const obj: any = {} + message.authorPrefix !== undefined && (obj.authorPrefix = message.authorPrefix) + return obj + }, + + fromPartial, I>>(object: I): QueryBooksRequest { + const message = createBaseQueryBooksRequest() + message.authorPrefix = object.authorPrefix ?? "" + return message + }, +} + +declare var self: any | undefined +declare var window: any | undefined +declare var global: any | undefined +var globalThis: any = (() => { + if (typeof globalThis !== "undefined") return globalThis + if (typeof self !== "undefined") return self + if (typeof window !== "undefined") return window + if (typeof global !== "undefined") return global + throw "Unable to locate global object" +})() + +type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined + +export type DeepPartial = T extends Builtin + ? T + : T extends Array + ? Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : T extends {} + ? { [K in keyof T]?: DeepPartial } + : Partial + +type KeysOfUnion = T extends T ? keyof T : never +export type Exact = P extends Builtin + ? P + : P & { [K in keyof P]: Exact } & Record>, never> + +function longToNumber(long: Long): number { + if (long.gt(Number.MAX_SAFE_INTEGER)) { + throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER") + } + return long.toNumber() +} + +if (_m0.util.Long !== Long) { + _m0.util.Long = Long as any + _m0.configure() +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined +} diff --git a/test/helpers.ts b/test/helpers.ts index d60b71e..b87afd0 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -3,7 +3,7 @@ import { log } from "./logger" import { inspect } from "util" import { MemoryTransport } from "../src/transports/Memory" import { parseProtocolMessage } from "../src/protocol/helpers" -import { Reader } from "protobufjs" +import { Reader } from "protobufjs/minimal" // async Array.from(generator*) with support for max elements export async function takeAsync(iter: AsyncGenerator, max?: number) { diff --git a/test/stream-from-dispatcher.spec.ts b/test/stream-from-dispatcher.spec.ts index 30d07d7..929bb07 100644 --- a/test/stream-from-dispatcher.spec.ts +++ b/test/stream-from-dispatcher.spec.ts @@ -1,10 +1,9 @@ import { streamFromDispatcher } from "../src/client" -import { Reader } from "protobufjs" import { messageNumberHandler } from "../src/message-number-handler" import { closeStreamMessage, streamMessage } from "../src/protocol/helpers" import { MemoryTransport } from "../src/transports/Memory" import { instrumentTransport, takeAsync } from "./helpers" -import { StreamMessage } from "../src/protocol/pbjs" +import { StreamMessage } from "../src/protocol" describe("streamFromDispatcher", () => { it("a CloseMessage from the server closes the iterator in the client", async () => { From ab6f10afa54b05f066d257ec1a90334b38e092f0 Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:12:36 -0300 Subject: [PATCH 06/11] remove logs --- .gitignore | 4 +- .vscode/configurationCache.log | 1 - .vscode/dryrun.log | 16 -- .vscode/targets.log | 325 --------------------------------- 4 files changed, 3 insertions(+), 343 deletions(-) delete mode 100644 .vscode/configurationCache.log delete mode 100644 .vscode/dryrun.log delete mode 100644 .vscode/targets.log diff --git a/.gitignore b/.gitignore index faa99b8..e75b159 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ coverage protoc3 src/protocol/*_pb.* test/codegen/*_pb.* -test/codegen/*_pb.* \ No newline at end of file +test/codegen/*_pb.* + +**/*.log \ No newline at end of file diff --git a/.vscode/configurationCache.log b/.vscode/configurationCache.log deleted file mode 100644 index 45bdb03..0000000 --- a/.vscode/configurationCache.log +++ /dev/null @@ -1 +0,0 @@ -{"buildTargets":["build","cheap-perf","install","install_compiler","test","test-watch"],"launchTargets":[],"customConfigurationProvider":{"workspaceBrowse":{"browsePath":[],"compilerArgs":[]},"fileIndex":[]}} \ No newline at end of file diff --git a/.vscode/dryrun.log b/.vscode/dryrun.log deleted file mode 100644 index bc2c2d7..0000000 --- a/.vscode/dryrun.log +++ /dev/null @@ -1,16 +0,0 @@ -make --dry-run --always-make --keep-going --print-directory -make: Entering directory '/Users/user/code/rpc' - -# remove local folder -rm -rf protoc3 || true -# Make sure you grab the latest version -curl -OL https://github.com/protocolbuffers/protobuf/releases/download/v3.19.1/protoc-3.19.1-osx-x86_64.zip -# Unzip -unzip protoc-3.19.1-osx-x86_64.zip -d protoc3 -# delete the files - -rm protoc-3.19.1-osx-x86_64.zip -# move protoc to /usr/local/bin/ -chmod +x protoc3/bin/protoc -make: Leaving directory '/Users/user/code/rpc' - diff --git a/.vscode/targets.log b/.vscode/targets.log deleted file mode 100644 index 6bdb509..0000000 --- a/.vscode/targets.log +++ /dev/null @@ -1,325 +0,0 @@ -make all --print-data-base --no-builtin-variables --no-builtin-rules --question -make: *** No rule to make target 'all'. Stop. - -# GNU Make 4.3 -# Built for arm-apple-darwin21.1.0 -# Copyright (C) 1988-2020 Free Software Foundation, Inc. -# License GPLv3+: GNU GPL version 3 or later -# This is free software: you are free to change and redistribute it. -# There is NO WARRANTY, to the extent permitted by law. - -# Make data base, printed on Wed May 11 06:42:57 2022 - -# Variables - -# environment -LC_ALL = C -# makefile (from 'Makefile', line 12) -PROTOBUF_ZIP = protoc-$(PROTOBUF_VERSION)-osx-x86_64.zip -# environment -TMPDIR = /var/folders/rq/86b2x9jx0_9btt86hnrp_7qm0000gn/T/ -# environment -XPC_SERVICE_NAME = application.com.microsoft.VSCode.17573896.17573902 -# environment -VSCODE_IPC_HOOK_EXTHOST = /var/folders/rq/86b2x9jx0_9btt86hnrp_7qm0000gn/T/vscode-ipc-c77f692a-850b-413d-8238-a2e3d7bac622.sock -# environment -VSCODE_CWD = / -# environment -GPG_TTY = not a tty -# environment -NVM_DIR = /Users/user/.nvm -# default -MAKE_COMMAND := make -# environment -GOPATH = /Users/user/go -# environment -__CFBundleIdentifier = com.microsoft.VSCode -# automatic -@D = $(patsubst %/,%,$(dir $@)) -# environment -VSCODE_HANDLES_UNCAUGHT_ERRORS = true -# default -.VARIABLES := -# environment -COMMAND_MODE = unix2003 -# environment -PWD = /Users/user/code/rpc -# automatic -%D = $(patsubst %/,%,$(dir $%)) -# environment -LSCOLORS = Gxfxcxdxbxegedabagacad -# environment -OLDPWD = /Users/user/code/rpc -# automatic -^D = $(patsubst %/,%,$(dir $^)) -# environment -VSCODE_LOG_STACK = false -# automatic -%F = $(notdir $%) -# environment -VSCODE_CODE_CACHE_PATH = /Users/user/Library/Application Support/Code/CachedData/57fd6d0195bb9b9d1b49f6da5db789060795de47 -# environment -MZ_ADDONS = -# environment -LANG = C -# default -.LOADED := -# default -.INCLUDE_DIRS = /opt/homebrew/Cellar/make/4.3/include /usr/local/include -# environment -__CF_USER_TEXT_ENCODING = 0x1F5:0x0:0x0 -# makefile -MAKEFLAGS = pqrR -# makefile -CURDIR := /Users/user/code/rpc -# makefile (from 'Makefile', line 3) -UNAME := Darwin -# environment -VSCODE_PIPE_LOGGING = true -# environment -APPLICATION_INSIGHTS_NO_DIAGNOSTIC_CHANNEL = true -# automatic -*D = $(patsubst %/,%,$(dir $*)) -# environment -MFLAGS = -pqrR -# environment -SSH_AUTH_SOCK = /Users/user/.gnupg/S.gpg-agent.ssh -# default -.SHELLFLAGS := -c -# automatic -+D = $(patsubst %/,%,$(dir $+)) -# environment -GPG_KEY = 0x78AC067F75AC1B64 -# makefile (from 'Makefile', line 1) -MAKEFILE_LIST := Makefile -# automatic -@F = $(notdir $@) -# environment -ZSH = /Users/user/.oh-my-zsh -# environment -VSCODE_VERBOSE_LOGGING = true -# environment -VSCODE_PID = 39542 -# automatic -?D = $(patsubst %/,%,$(dir $?)) -# environment -FZF_DEFAULT_COMMAND = rg --files --hidden --glob '!**/.git/*' --glob '!**/node_modules/*' -# makefile (from 'Makefile', line 1) -PROTOBUF_VERSION = 3.19.1 -# automatic -*F = $(notdir $*) -# makefile (from 'Makefile', line 2) -PROTOC = protoc -# automatic - Date: Wed, 11 May 2022 07:19:36 -0300 Subject: [PATCH 07/11] remove generated code --- .gitignore | 5 +- src/protocol/index.ts | 939 ----------------------------------------- test/codegen/client.ts | 228 ---------- 3 files changed, 4 insertions(+), 1168 deletions(-) delete mode 100644 src/protocol/index.ts delete mode 100644 test/codegen/client.ts diff --git a/.gitignore b/.gitignore index e75b159..de42666 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ src/protocol/*_pb.* test/codegen/*_pb.* test/codegen/*_pb.* -**/*.log \ No newline at end of file +**/*.log + +src/protocol/index.ts +test/codegen/client.ts \ No newline at end of file diff --git a/src/protocol/index.ts b/src/protocol/index.ts deleted file mode 100644 index a3084a3..0000000 --- a/src/protocol/index.ts +++ /dev/null @@ -1,939 +0,0 @@ -/* eslint-disable */ -import Long from "long" -import * as _m0 from "protobufjs/minimal" - -export const protobufPackage = "" - -/** THIS FILE IS AUTOGENERATED */ - -export enum RpcMessageTypes { - RpcMessageTypes_EMPTY = 0, - RpcMessageTypes_REQUEST = 1, - RpcMessageTypes_RESPONSE = 2, - RpcMessageTypes_STREAM_MESSAGE = 3, - RpcMessageTypes_STREAM_ACK = 4, - RpcMessageTypes_CREATE_PORT = 5, - RpcMessageTypes_CREATE_PORT_RESPONSE = 6, - RpcMessageTypes_REQUEST_MODULE = 7, - RpcMessageTypes_REQUEST_MODULE_RESPONSE = 8, - RpcMessageTypes_REMOTE_ERROR_RESPONSE = 9, - RpcMessageTypes_DESTROY_PORT = 10, - RpcMessageTypes_SERVER_READY = 11, - UNRECOGNIZED = -1, -} - -export function rpcMessageTypesFromJSON(object: any): RpcMessageTypes { - switch (object) { - case 0: - case "RpcMessageTypes_EMPTY": - return RpcMessageTypes.RpcMessageTypes_EMPTY - case 1: - case "RpcMessageTypes_REQUEST": - return RpcMessageTypes.RpcMessageTypes_REQUEST - case 2: - case "RpcMessageTypes_RESPONSE": - return RpcMessageTypes.RpcMessageTypes_RESPONSE - case 3: - case "RpcMessageTypes_STREAM_MESSAGE": - return RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE - case 4: - case "RpcMessageTypes_STREAM_ACK": - return RpcMessageTypes.RpcMessageTypes_STREAM_ACK - case 5: - case "RpcMessageTypes_CREATE_PORT": - return RpcMessageTypes.RpcMessageTypes_CREATE_PORT - case 6: - case "RpcMessageTypes_CREATE_PORT_RESPONSE": - return RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE - case 7: - case "RpcMessageTypes_REQUEST_MODULE": - return RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE - case 8: - case "RpcMessageTypes_REQUEST_MODULE_RESPONSE": - return RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE - case 9: - case "RpcMessageTypes_REMOTE_ERROR_RESPONSE": - return RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE - case 10: - case "RpcMessageTypes_DESTROY_PORT": - return RpcMessageTypes.RpcMessageTypes_DESTROY_PORT - case 11: - case "RpcMessageTypes_SERVER_READY": - return RpcMessageTypes.RpcMessageTypes_SERVER_READY - case -1: - case "UNRECOGNIZED": - default: - return RpcMessageTypes.UNRECOGNIZED - } -} - -export function rpcMessageTypesToJSON(object: RpcMessageTypes): string { - switch (object) { - case RpcMessageTypes.RpcMessageTypes_EMPTY: - return "RpcMessageTypes_EMPTY" - case RpcMessageTypes.RpcMessageTypes_REQUEST: - return "RpcMessageTypes_REQUEST" - case RpcMessageTypes.RpcMessageTypes_RESPONSE: - return "RpcMessageTypes_RESPONSE" - case RpcMessageTypes.RpcMessageTypes_STREAM_MESSAGE: - return "RpcMessageTypes_STREAM_MESSAGE" - case RpcMessageTypes.RpcMessageTypes_STREAM_ACK: - return "RpcMessageTypes_STREAM_ACK" - case RpcMessageTypes.RpcMessageTypes_CREATE_PORT: - return "RpcMessageTypes_CREATE_PORT" - case RpcMessageTypes.RpcMessageTypes_CREATE_PORT_RESPONSE: - return "RpcMessageTypes_CREATE_PORT_RESPONSE" - case RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE: - return "RpcMessageTypes_REQUEST_MODULE" - case RpcMessageTypes.RpcMessageTypes_REQUEST_MODULE_RESPONSE: - return "RpcMessageTypes_REQUEST_MODULE_RESPONSE" - case RpcMessageTypes.RpcMessageTypes_REMOTE_ERROR_RESPONSE: - return "RpcMessageTypes_REMOTE_ERROR_RESPONSE" - case RpcMessageTypes.RpcMessageTypes_DESTROY_PORT: - return "RpcMessageTypes_DESTROY_PORT" - case RpcMessageTypes.RpcMessageTypes_SERVER_READY: - return "RpcMessageTypes_SERVER_READY" - default: - return "UNKNOWN" - } -} - -export interface RpcMessageHeader { - messageIdentifier: number -} - -export interface CreatePort { - messageIdentifier: number - portName: string -} - -export interface CreatePortResponse { - messageIdentifier: number - portId: number -} - -export interface RequestModule { - messageIdentifier: number - portId: number - moduleName: string -} - -export interface RequestModuleResponse { - messageIdentifier: number - portId: number - procedures: ModuleProcedure[] -} - -export interface DestroyPort { - messageIdentifier: number - portId: number -} - -export interface ModuleProcedure { - procedureId: number - procedureName: string -} - -export interface Request { - messageIdentifier: number - portId: number - procedureId: number - payload: Uint8Array -} - -export interface RemoteError { - messageIdentifier: number - errorCode: number - errorMessage: string -} - -export interface Response { - messageIdentifier: number - payload: Uint8Array -} - -export interface StreamMessage { - messageIdentifier: number - portId: number - sequenceId: number - payload: Uint8Array - closed: boolean - ack: boolean -} - -function createBaseRpcMessageHeader(): RpcMessageHeader { - return { messageIdentifier: 0 } -} - -export const RpcMessageHeader = { - encode(message: RpcMessageHeader, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RpcMessageHeader { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseRpcMessageHeader() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): RpcMessageHeader { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - } - }, - - toJSON(message: RpcMessageHeader): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - return obj - }, - - fromPartial, I>>(object: I): RpcMessageHeader { - const message = createBaseRpcMessageHeader() - message.messageIdentifier = object.messageIdentifier ?? 0 - return message - }, -} - -function createBaseCreatePort(): CreatePort { - return { messageIdentifier: 0, portName: "" } -} - -export const CreatePort = { - encode(message: CreatePort, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portName !== "") { - writer.uint32(34).string(message.portName) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): CreatePort { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseCreatePort() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 4: - message.portName = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): CreatePort { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portName: isSet(object.portName) ? String(object.portName) : "", - } - }, - - toJSON(message: CreatePort): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portName !== undefined && (obj.portName = message.portName) - return obj - }, - - fromPartial, I>>(object: I): CreatePort { - const message = createBaseCreatePort() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portName = object.portName ?? "" - return message - }, -} - -function createBaseCreatePortResponse(): CreatePortResponse { - return { messageIdentifier: 0, portId: 0 } -} - -export const CreatePortResponse = { - encode(message: CreatePortResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portId !== 0) { - writer.uint32(21).fixed32(message.portId) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): CreatePortResponse { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseCreatePortResponse() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.portId = reader.fixed32() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): CreatePortResponse { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portId: isSet(object.portId) ? Number(object.portId) : 0, - } - }, - - toJSON(message: CreatePortResponse): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portId !== undefined && (obj.portId = Math.round(message.portId)) - return obj - }, - - fromPartial, I>>(object: I): CreatePortResponse { - const message = createBaseCreatePortResponse() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portId = object.portId ?? 0 - return message - }, -} - -function createBaseRequestModule(): RequestModule { - return { messageIdentifier: 0, portId: 0, moduleName: "" } -} - -export const RequestModule = { - encode(message: RequestModule, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portId !== 0) { - writer.uint32(21).fixed32(message.portId) - } - if (message.moduleName !== "") { - writer.uint32(34).string(message.moduleName) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RequestModule { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseRequestModule() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.portId = reader.fixed32() - break - case 4: - message.moduleName = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): RequestModule { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portId: isSet(object.portId) ? Number(object.portId) : 0, - moduleName: isSet(object.moduleName) ? String(object.moduleName) : "", - } - }, - - toJSON(message: RequestModule): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portId !== undefined && (obj.portId = Math.round(message.portId)) - message.moduleName !== undefined && (obj.moduleName = message.moduleName) - return obj - }, - - fromPartial, I>>(object: I): RequestModule { - const message = createBaseRequestModule() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portId = object.portId ?? 0 - message.moduleName = object.moduleName ?? "" - return message - }, -} - -function createBaseRequestModuleResponse(): RequestModuleResponse { - return { messageIdentifier: 0, portId: 0, procedures: [] } -} - -export const RequestModuleResponse = { - encode(message: RequestModuleResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portId !== 0) { - writer.uint32(21).fixed32(message.portId) - } - for (const v of message.procedures) { - ModuleProcedure.encode(v!, writer.uint32(42).fork()).ldelim() - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RequestModuleResponse { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseRequestModuleResponse() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.portId = reader.fixed32() - break - case 5: - message.procedures.push(ModuleProcedure.decode(reader, reader.uint32())) - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): RequestModuleResponse { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portId: isSet(object.portId) ? Number(object.portId) : 0, - procedures: Array.isArray(object?.procedures) - ? object.procedures.map((e: any) => ModuleProcedure.fromJSON(e)) - : [], - } - }, - - toJSON(message: RequestModuleResponse): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portId !== undefined && (obj.portId = Math.round(message.portId)) - if (message.procedures) { - obj.procedures = message.procedures.map((e) => (e ? ModuleProcedure.toJSON(e) : undefined)) - } else { - obj.procedures = [] - } - return obj - }, - - fromPartial, I>>(object: I): RequestModuleResponse { - const message = createBaseRequestModuleResponse() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portId = object.portId ?? 0 - message.procedures = object.procedures?.map((e) => ModuleProcedure.fromPartial(e)) || [] - return message - }, -} - -function createBaseDestroyPort(): DestroyPort { - return { messageIdentifier: 0, portId: 0 } -} - -export const DestroyPort = { - encode(message: DestroyPort, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portId !== 0) { - writer.uint32(21).fixed32(message.portId) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): DestroyPort { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseDestroyPort() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.portId = reader.fixed32() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): DestroyPort { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portId: isSet(object.portId) ? Number(object.portId) : 0, - } - }, - - toJSON(message: DestroyPort): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portId !== undefined && (obj.portId = Math.round(message.portId)) - return obj - }, - - fromPartial, I>>(object: I): DestroyPort { - const message = createBaseDestroyPort() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portId = object.portId ?? 0 - return message - }, -} - -function createBaseModuleProcedure(): ModuleProcedure { - return { procedureId: 0, procedureName: "" } -} - -export const ModuleProcedure = { - encode(message: ModuleProcedure, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.procedureId !== 0) { - writer.uint32(13).fixed32(message.procedureId) - } - if (message.procedureName !== "") { - writer.uint32(18).string(message.procedureName) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): ModuleProcedure { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseModuleProcedure() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.procedureId = reader.fixed32() - break - case 2: - message.procedureName = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): ModuleProcedure { - return { - procedureId: isSet(object.procedureId) ? Number(object.procedureId) : 0, - procedureName: isSet(object.procedureName) ? String(object.procedureName) : "", - } - }, - - toJSON(message: ModuleProcedure): unknown { - const obj: any = {} - message.procedureId !== undefined && (obj.procedureId = Math.round(message.procedureId)) - message.procedureName !== undefined && (obj.procedureName = message.procedureName) - return obj - }, - - fromPartial, I>>(object: I): ModuleProcedure { - const message = createBaseModuleProcedure() - message.procedureId = object.procedureId ?? 0 - message.procedureName = object.procedureName ?? "" - return message - }, -} - -function createBaseRequest(): Request { - return { messageIdentifier: 0, portId: 0, procedureId: 0, payload: new Uint8Array() } -} - -export const Request = { - encode(message: Request, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portId !== 0) { - writer.uint32(21).fixed32(message.portId) - } - if (message.procedureId !== 0) { - writer.uint32(37).fixed32(message.procedureId) - } - if (message.payload.length !== 0) { - writer.uint32(50).bytes(message.payload) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): Request { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseRequest() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.portId = reader.fixed32() - break - case 4: - message.procedureId = reader.fixed32() - break - case 6: - message.payload = reader.bytes() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): Request { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portId: isSet(object.portId) ? Number(object.portId) : 0, - procedureId: isSet(object.procedureId) ? Number(object.procedureId) : 0, - payload: isSet(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), - } - }, - - toJSON(message: Request): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portId !== undefined && (obj.portId = Math.round(message.portId)) - message.procedureId !== undefined && (obj.procedureId = Math.round(message.procedureId)) - message.payload !== undefined && - (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())) - return obj - }, - - fromPartial, I>>(object: I): Request { - const message = createBaseRequest() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portId = object.portId ?? 0 - message.procedureId = object.procedureId ?? 0 - message.payload = object.payload ?? new Uint8Array() - return message - }, -} - -function createBaseRemoteError(): RemoteError { - return { messageIdentifier: 0, errorCode: 0, errorMessage: "" } -} - -export const RemoteError = { - encode(message: RemoteError, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.errorCode !== 0) { - writer.uint32(21).fixed32(message.errorCode) - } - if (message.errorMessage !== "") { - writer.uint32(26).string(message.errorMessage) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): RemoteError { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseRemoteError() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.errorCode = reader.fixed32() - break - case 3: - message.errorMessage = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): RemoteError { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - errorCode: isSet(object.errorCode) ? Number(object.errorCode) : 0, - errorMessage: isSet(object.errorMessage) ? String(object.errorMessage) : "", - } - }, - - toJSON(message: RemoteError): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.errorCode !== undefined && (obj.errorCode = Math.round(message.errorCode)) - message.errorMessage !== undefined && (obj.errorMessage = message.errorMessage) - return obj - }, - - fromPartial, I>>(object: I): RemoteError { - const message = createBaseRemoteError() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.errorCode = object.errorCode ?? 0 - message.errorMessage = object.errorMessage ?? "" - return message - }, -} - -function createBaseResponse(): Response { - return { messageIdentifier: 0, payload: new Uint8Array() } -} - -export const Response = { - encode(message: Response, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.payload.length !== 0) { - writer.uint32(50).bytes(message.payload) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): Response { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseResponse() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 6: - message.payload = reader.bytes() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): Response { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - payload: isSet(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), - } - }, - - toJSON(message: Response): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.payload !== undefined && - (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())) - return obj - }, - - fromPartial, I>>(object: I): Response { - const message = createBaseResponse() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.payload = object.payload ?? new Uint8Array() - return message - }, -} - -function createBaseStreamMessage(): StreamMessage { - return { messageIdentifier: 0, portId: 0, sequenceId: 0, payload: new Uint8Array(), closed: false, ack: false } -} - -export const StreamMessage = { - encode(message: StreamMessage, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.messageIdentifier !== 0) { - writer.uint32(13).fixed32(message.messageIdentifier) - } - if (message.portId !== 0) { - writer.uint32(21).fixed32(message.portId) - } - if (message.sequenceId !== 0) { - writer.uint32(37).fixed32(message.sequenceId) - } - if (message.payload.length !== 0) { - writer.uint32(50).bytes(message.payload) - } - if (message.closed === true) { - writer.uint32(56).bool(message.closed) - } - if (message.ack === true) { - writer.uint32(64).bool(message.ack) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): StreamMessage { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseStreamMessage() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.messageIdentifier = reader.fixed32() - break - case 2: - message.portId = reader.fixed32() - break - case 4: - message.sequenceId = reader.fixed32() - break - case 6: - message.payload = reader.bytes() - break - case 7: - message.closed = reader.bool() - break - case 8: - message.ack = reader.bool() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): StreamMessage { - return { - messageIdentifier: isSet(object.messageIdentifier) ? Number(object.messageIdentifier) : 0, - portId: isSet(object.portId) ? Number(object.portId) : 0, - sequenceId: isSet(object.sequenceId) ? Number(object.sequenceId) : 0, - payload: isSet(object.payload) ? bytesFromBase64(object.payload) : new Uint8Array(), - closed: isSet(object.closed) ? Boolean(object.closed) : false, - ack: isSet(object.ack) ? Boolean(object.ack) : false, - } - }, - - toJSON(message: StreamMessage): unknown { - const obj: any = {} - message.messageIdentifier !== undefined && (obj.messageIdentifier = Math.round(message.messageIdentifier)) - message.portId !== undefined && (obj.portId = Math.round(message.portId)) - message.sequenceId !== undefined && (obj.sequenceId = Math.round(message.sequenceId)) - message.payload !== undefined && - (obj.payload = base64FromBytes(message.payload !== undefined ? message.payload : new Uint8Array())) - message.closed !== undefined && (obj.closed = message.closed) - message.ack !== undefined && (obj.ack = message.ack) - return obj - }, - - fromPartial, I>>(object: I): StreamMessage { - const message = createBaseStreamMessage() - message.messageIdentifier = object.messageIdentifier ?? 0 - message.portId = object.portId ?? 0 - message.sequenceId = object.sequenceId ?? 0 - message.payload = object.payload ?? new Uint8Array() - message.closed = object.closed ?? false - message.ack = object.ack ?? false - return message - }, -} - -declare var self: any | undefined -declare var window: any | undefined -declare var global: any | undefined -var globalThis: any = (() => { - if (typeof globalThis !== "undefined") return globalThis - if (typeof self !== "undefined") return self - if (typeof window !== "undefined") return window - if (typeof global !== "undefined") return global - throw "Unable to locate global object" -})() - -const atob: (b64: string) => string = - globalThis.atob || ((b64) => globalThis.Buffer.from(b64, "base64").toString("binary")) -function bytesFromBase64(b64: string): Uint8Array { - const bin = atob(b64) - const arr = new Uint8Array(bin.length) - for (let i = 0; i < bin.length; ++i) { - arr[i] = bin.charCodeAt(i) - } - return arr -} - -const btoa: (bin: string) => string = - globalThis.btoa || ((bin) => globalThis.Buffer.from(bin, "binary").toString("base64")) -function base64FromBytes(arr: Uint8Array): string { - const bin: string[] = [] - arr.forEach((byte) => { - bin.push(String.fromCharCode(byte)) - }) - return btoa(bin.join("")) -} - -type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined - -export type DeepPartial = T extends Builtin - ? T - : T extends Array - ? Array> - : T extends ReadonlyArray - ? ReadonlyArray> - : T extends {} - ? { [K in keyof T]?: DeepPartial } - : Partial - -type KeysOfUnion = T extends T ? keyof T : never -export type Exact = P extends Builtin - ? P - : P & { [K in keyof P]: Exact } & Record>, never> - -if (_m0.util.Long !== Long) { - _m0.util.Long = Long as any - _m0.configure() -} - -function isSet(value: any): boolean { - return value !== null && value !== undefined -} diff --git a/test/codegen/client.ts b/test/codegen/client.ts deleted file mode 100644 index 52ed2fd..0000000 --- a/test/codegen/client.ts +++ /dev/null @@ -1,228 +0,0 @@ -/* eslint-disable */ -import Long from "long" -import * as _m0 from "protobufjs/minimal" - -export const protobufPackage = "" - -export interface Book { - isbn: number - title: string - author: string -} - -export interface GetBookRequest { - isbn: number -} - -export interface QueryBooksRequest { - authorPrefix: string -} - -function createBaseBook(): Book { - return { isbn: 0, title: "", author: "" } -} - -export const Book = { - encode(message: Book, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.isbn !== 0) { - writer.uint32(8).int64(message.isbn) - } - if (message.title !== "") { - writer.uint32(18).string(message.title) - } - if (message.author !== "") { - writer.uint32(26).string(message.author) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): Book { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseBook() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.isbn = longToNumber(reader.int64() as Long) - break - case 2: - message.title = reader.string() - break - case 3: - message.author = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): Book { - return { - isbn: isSet(object.isbn) ? Number(object.isbn) : 0, - title: isSet(object.title) ? String(object.title) : "", - author: isSet(object.author) ? String(object.author) : "", - } - }, - - toJSON(message: Book): unknown { - const obj: any = {} - message.isbn !== undefined && (obj.isbn = Math.round(message.isbn)) - message.title !== undefined && (obj.title = message.title) - message.author !== undefined && (obj.author = message.author) - return obj - }, - - fromPartial, I>>(object: I): Book { - const message = createBaseBook() - message.isbn = object.isbn ?? 0 - message.title = object.title ?? "" - message.author = object.author ?? "" - return message - }, -} - -function createBaseGetBookRequest(): GetBookRequest { - return { isbn: 0 } -} - -export const GetBookRequest = { - encode(message: GetBookRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.isbn !== 0) { - writer.uint32(8).int64(message.isbn) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): GetBookRequest { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseGetBookRequest() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.isbn = longToNumber(reader.int64() as Long) - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): GetBookRequest { - return { - isbn: isSet(object.isbn) ? Number(object.isbn) : 0, - } - }, - - toJSON(message: GetBookRequest): unknown { - const obj: any = {} - message.isbn !== undefined && (obj.isbn = Math.round(message.isbn)) - return obj - }, - - fromPartial, I>>(object: I): GetBookRequest { - const message = createBaseGetBookRequest() - message.isbn = object.isbn ?? 0 - return message - }, -} - -function createBaseQueryBooksRequest(): QueryBooksRequest { - return { authorPrefix: "" } -} - -export const QueryBooksRequest = { - encode(message: QueryBooksRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - if (message.authorPrefix !== "") { - writer.uint32(10).string(message.authorPrefix) - } - return writer - }, - - decode(input: _m0.Reader | Uint8Array, length?: number): QueryBooksRequest { - const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input) - let end = length === undefined ? reader.len : reader.pos + length - const message = createBaseQueryBooksRequest() - while (reader.pos < end) { - const tag = reader.uint32() - switch (tag >>> 3) { - case 1: - message.authorPrefix = reader.string() - break - default: - reader.skipType(tag & 7) - break - } - } - return message - }, - - fromJSON(object: any): QueryBooksRequest { - return { - authorPrefix: isSet(object.authorPrefix) ? String(object.authorPrefix) : "", - } - }, - - toJSON(message: QueryBooksRequest): unknown { - const obj: any = {} - message.authorPrefix !== undefined && (obj.authorPrefix = message.authorPrefix) - return obj - }, - - fromPartial, I>>(object: I): QueryBooksRequest { - const message = createBaseQueryBooksRequest() - message.authorPrefix = object.authorPrefix ?? "" - return message - }, -} - -declare var self: any | undefined -declare var window: any | undefined -declare var global: any | undefined -var globalThis: any = (() => { - if (typeof globalThis !== "undefined") return globalThis - if (typeof self !== "undefined") return self - if (typeof window !== "undefined") return window - if (typeof global !== "undefined") return global - throw "Unable to locate global object" -})() - -type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined - -export type DeepPartial = T extends Builtin - ? T - : T extends Array - ? Array> - : T extends ReadonlyArray - ? ReadonlyArray> - : T extends {} - ? { [K in keyof T]?: DeepPartial } - : Partial - -type KeysOfUnion = T extends T ? keyof T : never -export type Exact = P extends Builtin - ? P - : P & { [K in keyof P]: Exact } & Record>, never> - -function longToNumber(long: Long): number { - if (long.gt(Number.MAX_SAFE_INTEGER)) { - throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER") - } - return long.toNumber() -} - -if (_m0.util.Long !== Long) { - _m0.util.Long = Long as any - _m0.configure() -} - -function isSet(value: any): boolean { - return value !== null && value !== undefined -} From a29b61a68fdb48630a12b1183679d7e9cb8db27c Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:21:17 -0300 Subject: [PATCH 08/11] remove unused code generator --- scripts/generate-proto-file.ts | 2 +- scripts/print-proto-dsl.ts | 120 --------------------------------- 2 files changed, 1 insertion(+), 121 deletions(-) diff --git a/scripts/generate-proto-file.ts b/scripts/generate-proto-file.ts index 72b6332..aa062ed 100644 --- a/scripts/generate-proto-file.ts +++ b/scripts/generate-proto-file.ts @@ -1,4 +1,4 @@ -import { generateProtoFile, generateTsProtocol } from "./print-proto-dsl" +import { generateProtoFile } from "./print-proto-dsl" import { field, protoDsl } from "./proto-dsl" import { writeFileSync } from "fs" diff --git a/scripts/print-proto-dsl.ts b/scripts/print-proto-dsl.ts index 5349560..c9cead4 100644 --- a/scripts/print-proto-dsl.ts +++ b/scripts/print-proto-dsl.ts @@ -1,5 +1,4 @@ import { isProtoEnum, isProtoMessage, ProtoEnum, ProtoField, ProtoMessage } from "./proto-dsl" -import camelCase from "camelcase" export function generateProtoFile(names: Map): string { const parts: string[] = [`// THIS FILE IS AUTOGENERATED`, `syntax = "proto3";`] @@ -26,122 +25,3 @@ export function generateProtoFile(names: Map): return parts.join("\n") } - -function mapTypescriptType(incomingType: string): string { - switch (incomingType) { - case "bytes": - return "Uint8Array" - case "bool": - return "boolean" - } - return incomingType -} - -function unaryReader(type: ProtoField): string { - switch (type.type) { - case "fixed32": - return "d.readUint32($)" - case "string": - return "_readString($)" - case "bytes": - return "_readBytes($)" - case "bool": - return "d.readUint8($) != 0" - } - return `read${type.type}($)` -} - -function getReader(type: ProtoField): string { - if (type.repeated) { - return `_readArray($, ($) => ${unaryReader(type)})` - } - return unaryReader(type) -} - -function unaryWriter(type: ProtoField, valueName: string): string { - const accessor = valueName - switch (type.type) { - case `fixed32`: - return `e.writeUint32($, ${accessor})` - case `string`: - return `_writeString($, ${accessor})` - case `bytes`: - return `_writeBytes($, ${accessor})` - case `bool`: - return `e.writeUint8($, ${accessor} ? 1 : 0)` - } - return `write${type.type}($, ${accessor})` -} - -function getWriter(type: ProtoField, accessorName: string): string { - if (type.repeated) { - return `_writeArray($, ($, elem) => ${unaryWriter(type, "elem")}, ${accessorName})` - } - return unaryWriter(type, accessorName) -} - -export function generateTsProtocol(names: Map): string { - const parts: string[] = [ - `// THIS FILE IS AUTOGENERATED`, - `import * as e from '../encdec/encoding'`, - `import * as d from '../encdec/decoding'`, - `export type fixed32 = number\n`, - `function _readArray($: d.Decoder, reader: ($: d.Decoder) => T): Array {`, - ` const len = d.readUint32($); const ret: T[] = [];`, - ` for(let i = 0; i < len; i++) ret.push(reader($));`, - ` return ret;`, - `}`, - `function _readString($: d.Decoder) {`, - ` return d.readVarString($);`, - `}`, - `function _readBytes($: d.Decoder): Uint8Array {`, - ` return d.readVarUint8Array($);`, - `}`, - - `function _writeArray($: e.Encoder, writer: ($: e.Encoder, value: T) => void, array: T[]) {`, - ` e.writeUint32($, array.length);`, - ` for(let element of array) writer($, element);`, - `}`, - `function _writeString($: e.Encoder, value: string) {`, - ` e.writeVarString($, value);`, - `}`, - `function _writeBytes($: e.Encoder, value: Uint8Array) {`, - ` e.writeVarUint8Array($, value);`, - `}`, - ] - - for (const [name, value] of names) { - if (isProtoMessage(value)) { - const fields = value.fields.sort((a, b) => (a.number > b.number ? 1 : -1)) - - parts.push(`export type ${name} = {`) - for (const field of fields) { - const tsType = mapTypescriptType(field.type) - parts.push(` ${camelCase(field.name)}: ${field.repeated ? "Array<" + tsType + ">" : tsType}`) - } - parts.push(`}\n`) - - parts.push(`export function write${name}($: e.Encoder, value: ${name}) {`) - for (const field of fields) { - parts.push(` ${getWriter(field, `value[${JSON.stringify(camelCase(field.name))}]`)};`) - } - parts.push(`}\n`) - - parts.push(`export function read${name}($: d.Decoder): ${name} {`) - parts.push(` return {`) - for (const field of fields) { - parts.push(` ${camelCase(field.name)}: ${getReader(field)},`) - } - parts.push(` }`) - parts.push(`}\n`) - } else if (isProtoEnum(value)) { - parts.push(`export const enum ${name} {`) - for (const key in value.values) { - parts.push(` ${key} = ${value.values[key]},`) - } - parts.push(`}\n`) - } - } - - return parts.join("\n") -} From b624ae0bb565e4d8edec207e298b6fd7b9549db3 Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:22:16 -0300 Subject: [PATCH 09/11] remove commented code --- package-lock.json | 1 - package.json | 1 - scripts/generate-proto-file.ts | 2 -- 3 files changed, 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 32e33e7..4ecdb48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "camelcase": "^6.3.0", "mitt": "^3.0.0", "pascalcase": "^2.0.0", "ts-proto": "^1.112.1" diff --git a/package.json b/package.json index cfc3c6f..4d3c488 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "dist" ], "dependencies": { - "camelcase": "^6.3.0", "mitt": "^3.0.0", "pascalcase": "^2.0.0", "ts-proto": "^1.112.1" diff --git a/scripts/generate-proto-file.ts b/scripts/generate-proto-file.ts index aa062ed..7dcf813 100644 --- a/scripts/generate-proto-file.ts +++ b/scripts/generate-proto-file.ts @@ -112,7 +112,6 @@ proto.addMessage( ["RpcMessageHeader"] ) - /** * @description Signals the client about an error during the request * execution or malformed input. @@ -157,4 +156,3 @@ proto.addMessage( ) writeFileSync("src/protocol/index.proto", generateProtoFile(proto.validate())) -// writeFileSync("src/protocol/wire-protocol.ts", generateTsProtocol(proto.validate())) From 12b9fb74aa7d6d36a8ab50cf60d470250ebffb14 Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:22:56 -0300 Subject: [PATCH 10/11] npm dedup --- package-lock.json | 60 +++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ecdb48..a1db85b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1246,9 +1246,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1422,9 +1422,9 @@ } }, "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "dependencies": { "@babel/core": "^7.12.3", @@ -3456,9 +3456,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/mitt": { @@ -3786,9 +3786,9 @@ } }, "node_modules/protobufjs/node_modules/@types/node": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", - "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" }, "node_modules/psl": { "version": "1.8.0", @@ -3902,9 +3902,9 @@ } }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -5708,9 +5708,9 @@ "dev": true }, "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "dev": true }, "acorn-globals": { @@ -5837,9 +5837,9 @@ }, "dependencies": { "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -7413,9 +7413,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "mitt": { @@ -7662,9 +7662,9 @@ }, "dependencies": { "@types/node": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", - "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.32.tgz", + "integrity": "sha512-eAIcfAvhf/BkHcf4pkLJ7ECpBAhh9kcxRBpip9cTiO+hf+aJrsxYxBeS6OXvOd9WqNAJmavXVpZvY1rBjNsXmw==" } } }, @@ -7753,9 +7753,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" From e8ddc40fe93762c069b1e2c0e4b8654099c42b63 Mon Sep 17 00:00:00 2001 From: menduz Date: Wed, 11 May 2022 07:23:35 -0300 Subject: [PATCH 11/11] remove dp --- package-lock.json | 24 +++--------------------- package.json | 1 - 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/package-lock.json b/package-lock.json index a1db85b..7bda0f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,6 @@ "license": "Apache-2.0", "dependencies": { "mitt": "^3.0.0", - "pascalcase": "^2.0.0", "ts-proto": "^1.112.1" }, "devDependencies": { @@ -1607,6 +1606,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "engines": { "node": ">=10" }, @@ -3608,17 +3608,6 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "node_modules/pascalcase": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-2.0.0.tgz", - "integrity": "sha512-DHpENy5Qm/FaX+x3iBLoMLG/XHNCTgL+yErm1TwuVaj6u4fiOSkYkf60vGtITk7hrKHOO4uCl9vRrD4hqjNKjg==", - "dependencies": { - "camelcase": "^6.2.1" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5986,7 +5975,8 @@ "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true }, "caniuse-lite": { "version": "1.0.30001292", @@ -7535,14 +7525,6 @@ "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "pascalcase": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-2.0.0.tgz", - "integrity": "sha512-DHpENy5Qm/FaX+x3iBLoMLG/XHNCTgL+yErm1TwuVaj6u4fiOSkYkf60vGtITk7hrKHOO4uCl9vRrD4hqjNKjg==", - "requires": { - "camelcase": "^6.2.1" - } - }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", diff --git a/package.json b/package.json index 4d3c488..6f7ed39 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ ], "dependencies": { "mitt": "^3.0.0", - "pascalcase": "^2.0.0", "ts-proto": "^1.112.1" } }