diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..cba6951 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,46 @@ +/// +/// +import EventEmitter from "events"; +import DHTFlood from "@lumeweb/dht-flood"; +export default class DHTCache extends EventEmitter { + protected swarm: any; + private id; + private bootstrapped; + private graph; + private connectedTo; + protected flood: DHTFlood; + constructor(swarm: any, { id, ...opts }?: { + id?: Buffer; + [key: string]: any; + }); + private _cache; + get cache(): {}; + get all_cache(): string[]; + addItem(item: string | Buffer): void; + private _compileMessage; + private _broadcastMessage; + removeItem(item: string | Buffer): boolean; + private _online; + get online(): Set; + broadcast(message: any, ttl?: number): void; + send(message: any): void; + protected addPeerHandler(peer: any): void; + removePeerHandler(peer: any): void; + protected onRemovePeer(peer: any): void; + protected onGetBroadcast(message: Buffer, id: Buffer): void; + private _signItem; + private _setEntity; + private _ensureItem; + private _ensurePeer; + private _ensureEntity; + private _hasSeenEntity; + private _addEntityConnection; + private _removeEntityConnection; + private _removeEntity; + private _bootstrapFrom; + private _getBootstrapInfo; + private _recalculate; + private _maybeHexify; + private _pruneItems; +} +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/index.d.ts.map b/dist/index.d.ts.map new file mode 100644 index 0000000..4c5262f --- /dev/null +++ b/dist/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAYlC,OAAO,QAAQ,MAAM,oBAAoB,CAAC;AAa1C,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,YAAY;IAChD,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC;IACrB,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,WAAW,CAAW;IAE9B,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC;gBAGxB,KAAK,EAAE,GAAG,EACV,EACE,EAA4B,EAC5B,GAAG,IAAI,EACR,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAO;IAkC7C,OAAO,CAAC,MAAM,CAAc;IAE5B,IAAW,KAAK,IAAI,EAAE,CAErB;IAED,IAAW,SAAS,IAAI,MAAM,EAAE,CAU/B;IAEM,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAqBpC,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,iBAAiB;IAIlB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO;IAmBjD,OAAO,CAAC,OAAO,CAAc;IAE7B,IAAW,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAE/B;IAEM,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM;IAIpC,IAAI,CAAC,OAAO,EAAE,GAAG;IAIxB,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG;IA2BlC,iBAAiB,CAAC,IAAI,EAAE,GAAG;IAW3B,SAAS,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG;IAmBhC,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAsDpD,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,cAAc;IAuBtB,OAAO,CAAC,iBAAiB;IAiBzB,OAAO,CAAC,YAAY;IA+BpB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,WAAW;CAyBpB"} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..ec451fb --- /dev/null +++ b/dist/index.js @@ -0,0 +1,337 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const events_1 = __importDefault(require("events")); +// @ts-ignore +const jsnetworkx_1 = require("jsnetworkx"); +// @ts-ignore +const hypercore_crypto_1 = __importDefault(require("hypercore-crypto")); +const b4a_1 = __importDefault(require("b4a")); +const messages_js_1 = require("./messages.js"); +const dht_flood_1 = __importDefault(require("@lumeweb/dht-flood")); +const EntityType = { + PUBKEY: Symbol.for("PUBKEY"), + ITEM: Symbol.for("ITEM"), +}; +const DISCONNECT_SMOOTH = 500; +class DHTCache extends events_1.default { + swarm; + id; + bootstrapped; + graph; + connectedTo; + flood; + constructor(swarm, { id = swarm.keyPair.publicKey, ...opts } = {}) { + super(); + if (!id) + throw new TypeError("Must provide id for self"); + this.id = id; + this.bootstrapped = false; + this.graph = new jsnetworkx_1.DiGraph(); + this.connectedTo = new Set(); + this._cache = new Set(); + this._online = new Set([this._maybeHexify(this.id)]); + this.swarm = swarm; + this.flood = new dht_flood_1.default({ id, swarm, ...opts }); + this.flood.on("peer-open", (peer) => this.addPeerHandler(peer)); + this.flood.on("peer-remove", (peer) => this.removePeerHandler(peer)); + this.flood.on("message", (message, id) => this.onGetBroadcast(message, id)); + this.swarm.on("connection", (peer) => this.flood.send(peer, Buffer.from("hello"), 0)); + [...this.swarm.peers.values()] + .map((item) => { + remotePublicKey: item.publicKey; + }) + .filter((item) => !!item) + .forEach((item) => { + this.addPeerHandler(item); + }); + this._ensurePeer(id); + } + _cache; + get cache() { + return [...this._cache].sort(); + } + get all_cache() { + const items = []; + for (const id of this.graph.nodesIter()) { + const item = this.graph.node.get(id); + if (item?.type !== EntityType.ITEM) { + continue; + } + items.push(id); + } + return items.sort(); + } + addItem(item) { + item = this._maybeHexify(item); + this._cache.add(item); + this._ensureItem(item); + const broadcast = () => { + this._broadcastMessage({ + type: messages_js_1.Type.ADD_ITEM, + data: b4a_1.default.from(item, "hex"), + signature: this._signItem(item), + }); + }; + if (!this.bootstrapped) { + this.once("bootstrapped", broadcast); + } + else { + broadcast(); + } + } + _compileMessage(message) { + return messages_js_1.Message.toBinary(messages_js_1.Message.create(message)); + } + _broadcastMessage(message, ttl) { + this.broadcast(this._compileMessage(message), ttl); + } + removeItem(item) { + item = this._maybeHexify(item); + if (!this._cache.has(item)) { + return false; + } + this._cache.delete(item); + this._removeEntity(item); + this._broadcastMessage({ + type: messages_js_1.Type.REMOVE_ITEM, + data: b4a_1.default.from(item, "hex"), + signature: this._signItem(item), + }); + return true; + } + _online; + get online() { + return this._online; + } + broadcast(message, ttl) { + this.flood.broadcast(message, ttl); + } + send(message) { + this.flood.send(message, 0); + } + addPeerHandler(peer) { + const id = peer.remotePublicKey; + const stringId = id.toString("hex"); + if (this.connectedTo.has(stringId)) { + return; + } // Already know we're connected here + this.connectedTo.add(stringId); + this._ensurePeer(id); + this._addEntityConnection(this.id, id); + this.emit("peer-add", id); + this._recalculate(); + this._broadcastMessage({ + type: messages_js_1.Type.CONNECTED, + id, + }); + if (this.bootstrapped) { + return; + } + // If this is the first person we've met, get their graph + this._broadcastMessage({ type: messages_js_1.Type.BOOTSTRAP_REQUEST }, 0); + } + removePeerHandler(peer) { + const id = peer.remotePublicKey; + // Wait for a bit and check if we're still disconnected before removing the peer + setTimeout(() => { + if (this.swarm._allConnections.has(id)) { + return; + } + this.onRemovePeer(peer); + }, DISCONNECT_SMOOTH); + } + onRemovePeer(peer) { + const id = peer.remotePublicKey; + this.connectedTo.delete(id.toString("hex")); + this._removeEntityConnection(this.id, id); + this.emit("peer-remove"); + this._recalculate(); + this._broadcastMessage({ + type: messages_js_1.Type.DISCONNECTED, + id, + }, 0); + } + onGetBroadcast(message, id) { + let decoded; + try { + decoded = messages_js_1.Message.fromBinary(message); + } + catch { + return; + } + const { type } = decoded; + if (!type) { + throw new Error("Missing Type In Message"); + } + if ([messages_js_1.Type.ADD_ITEM, messages_js_1.Type.REMOVE_ITEM].includes(type)) { + const { data: rawData, signature } = decoded; + const bufData = b4a_1.default.from(rawData); + if (signature && hypercore_crypto_1.default.verify(bufData, signature, id)) { + if (messages_js_1.Type.ADD_ITEM === type) { + this._ensureItem(bufData); + this._addEntityConnection(id, bufData); + } + if (messages_js_1.Type.REMOVE_ITEM === type) { + this.removeItem(bufData); + this._pruneItems(); + } + } + } + else if (type === messages_js_1.Type.CONNECTED) { + const { id: toId } = decoded; + this._addEntityConnection(id, Buffer.from(toId)); + this.emit("peer-add-seen", id, toId); + this._recalculate(); + } + else if (type === messages_js_1.Type.DISCONNECTED) { + const { id: toId } = decoded; + this._removeEntityConnection(id, Buffer.from(toId)); + this.emit("peer-remove-seen", id, toId); + this._recalculate(); + } + else if (type === messages_js_1.Type.BOOTSTRAP_REQUEST) { + const bootstrap = this._getBootstrapInfo(); + this.broadcast(messages_js_1.Message.toBinary(messages_js_1.Message.create({ + type: messages_js_1.Type.BOOTSTRAP_RESPONSE, + bootstrap, + })), 0); + } + else if (type === messages_js_1.Type.BOOTSTRAP_RESPONSE) { + const { bootstrap } = decoded; + this._bootstrapFrom(bootstrap); + } + } + _signItem(item) { + item = this._maybeHexify(item); + return hypercore_crypto_1.default.sign(b4a_1.default.from(item, "hex"), this.swarm.keyPair.secretKey); + } + _setEntity(id, data) { + this.graph.addNode(this._maybeHexify(id), data); + } + _ensureItem(id) { + this._ensureEntity(id, { type: EntityType.ITEM }); + } + _ensurePeer(id) { + this._ensureEntity(id, { type: EntityType.PUBKEY }); + } + _ensureEntity(id, def = {}) { + id = this._maybeHexify(id); + if (!this._hasSeenEntity(id)) { + this._setEntity(id, def); + } + } + _hasSeenEntity(id) { + return this.graph.hasNode(this._maybeHexify(id)); + } + _addEntityConnection(origin, destination) { + this._ensureEntity(origin); + this._ensureEntity(destination); + this.graph.addEdge(this._maybeHexify(origin), this._maybeHexify(destination)); + } + _removeEntityConnection(origin, destination) { + try { + this._ensureEntity(origin); + this._ensureEntity(destination); + this.graph.removeEdge(origin.toString("hex"), destination.toString("hex")); + } + catch (e) { + if (e.name !== "JSNetworkXError") + throw e; + } + } + _removeEntity(id) { + this.graph.removeNode(this._maybeHexify(id)); + } + _bootstrapFrom(bootstrap) { + if (this.bootstrapped) { + return; + } + for (const id in bootstrap) { + const { connectedTo } = bootstrap[id]; + if (id === this.id.toString("hex")) { + continue; + } + for (const connection of connectedTo) { + const peer = b4a_1.default.from(connection); + this._ensurePeer(peer); + this._addEntityConnection(id, peer); + } + } + this.emit("bootstrapped"); + this._recalculate(); + } + _getBootstrapInfo() { + const state = {}; + for (const id of this.graph.nodesIter()) { + const item = this.graph.node.get(id); + if (item?.type !== EntityType.PUBKEY) { + continue; + } + const connectedTo = this.graph + .neighbors(id) + .map((id) => Buffer.from(id, "hex")); + state[id] = { connectedTo }; + } + return state; + } + // Calculate who's online and emit an event + _recalculate() { + const online = new Set(); + const offline = new Set(); + for (const id of this.graph.nodesIter()) { + const item = this.graph.node.get(id); + if (item?.type !== EntityType.PUBKEY) { + continue; + } + if ((0, jsnetworkx_1.hasPath)(this.graph, { + source: this._maybeHexify(this.id), + target: id, + })) { + online.add(id); + } + else { + offline.add(id); + } + } + for (const id of offline) { + this.graph.removeNode(id); + } + this._online = online; + this.emit("online", online); + } + _maybeHexify(data) { + if (b4a_1.default.isBuffer(data)) { + return data.toString("hex"); + } + return data; + } + _pruneItems(item) { + let items; + if (!item) { + items = this.graph.nodesIter(); + } + else { + items = [item]; + } + (async () => { + for (const id of items) { + const item = this.graph.node.get(id); + if (item?.type !== EntityType.ITEM) { + continue; + } + (async () => { + try { + if (0 === this.graph.neighbors(id)?.length) { + this.graph.removeNode(id); + } + } + catch { } + })(); + } + })(); + } +} +exports.default = DHTCache; diff --git a/dist/messages.d.ts b/dist/messages.d.ts new file mode 100644 index 0000000..275da8a --- /dev/null +++ b/dist/messages.d.ts @@ -0,0 +1,98 @@ +import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; +import type { IBinaryWriter } from "@protobuf-ts/runtime"; +import type { BinaryReadOptions } from "@protobuf-ts/runtime"; +import type { IBinaryReader } from "@protobuf-ts/runtime"; +import type { PartialMessage } from "@protobuf-ts/runtime"; +import { MessageType } from "@protobuf-ts/runtime"; +/** + * @generated from protobuf message Message + */ +export interface Message { + /** + * @generated from protobuf field: Type type = 1; + */ + type: Type; + /** + * @generated from protobuf field: map bootstrap = 2; + */ + bootstrap: { + [key: string]: State; + }; + /** + * @generated from protobuf field: optional bytes data = 3; + */ + data?: Uint8Array; + /** + * @generated from protobuf field: optional bytes signature = 4; + */ + signature?: Uint8Array; + /** + * @generated from protobuf field: optional bytes id = 5; + */ + id?: Uint8Array; +} +/** + * @generated from protobuf message State + */ +export interface State { + /** + * @generated from protobuf field: repeated bytes connectedTo = 1; + */ + connectedTo: Uint8Array[]; +} +/** + * @generated from protobuf enum Type + */ +export declare enum Type { + /** + * @generated synthetic value - protobuf-ts requires all enums to have a 0 value + */ + UNSPECIFIED$ = 0, + /** + * @generated from protobuf enum value: BOOTSTRAP_REQUEST = 1; + */ + BOOTSTRAP_REQUEST = 1, + /** + * @generated from protobuf enum value: BOOTSTRAP_RESPONSE = 2; + */ + BOOTSTRAP_RESPONSE = 2, + /** + * @generated from protobuf enum value: CONNECTED = 3; + */ + CONNECTED = 3, + /** + * @generated from protobuf enum value: DISCONNECTED = 4; + */ + DISCONNECTED = 4, + /** + * @generated from protobuf enum value: ADD_ITEM = 5; + */ + ADD_ITEM = 5, + /** + * @generated from protobuf enum value: REMOVE_ITEM = 6; + */ + REMOVE_ITEM = 6 +} +declare class Message$Type extends MessageType { + constructor(); + create(value?: PartialMessage): Message; + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Message): Message; + private binaryReadMap2; + internalBinaryWrite(message: Message, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter; +} +/** + * @generated MessageType for protobuf message Message + */ +export declare const Message: Message$Type; +declare class State$Type extends MessageType { + constructor(); + create(value?: PartialMessage): State; + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: State): State; + internalBinaryWrite(message: State, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter; +} +/** + * @generated MessageType for protobuf message State + */ +export declare const State: State$Type; +export {}; +//# sourceMappingURL=messages.d.ts.map \ No newline at end of file diff --git a/dist/messages.d.ts.map b/dist/messages.d.ts.map new file mode 100644 index 0000000..621dcc1 --- /dev/null +++ b/dist/messages.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD;;GAEG;AACH,MAAM,WAAW,OAAO;IACpB;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC;IACX;;OAEG;IACH,SAAS,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;KACxB,CAAC;IACF;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AACD;;GAEG;AACH,MAAM,WAAW,KAAK;IAClB;;OAEG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;CAC7B;AACD;;GAEG;AACH,oBAAY,IAAI;IACZ;;OAEG;IACH,YAAY,IAAI;IAChB;;OAEG;IACH,iBAAiB,IAAI;IACrB;;OAEG;IACH,kBAAkB,IAAI;IACtB;;OAEG;IACH,SAAS,IAAI;IACb;;OAEG;IACH,YAAY,IAAI;IAChB;;OAEG;IACH,QAAQ,IAAI;IACZ;;OAEG;IACH,WAAW,IAAI;CAClB;AAED,cAAM,YAAa,SAAQ,WAAW,CAAC,OAAO,CAAC;;IAU3C,MAAM,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,OAAO;IAOhD,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO;IA+BhH,OAAO,CAAC,cAAc;IAgBtB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CAyB3G;AACD;;GAEG;AACH,eAAO,MAAM,OAAO,cAAqB,CAAC;AAE1C,cAAM,UAAW,SAAQ,WAAW,CAAC,KAAK,CAAC;;IAMvC,MAAM,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG,KAAK;IAO5C,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK;IAmB5G,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CASzG;AACD;;GAEG;AACH,eAAO,MAAM,KAAK,YAAmB,CAAC"} \ No newline at end of file diff --git a/dist/messages.js b/dist/messages.js new file mode 100644 index 0000000..a10c6dd --- /dev/null +++ b/dist/messages.js @@ -0,0 +1,184 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.State = exports.Message = exports.Type = void 0; +const runtime_1 = require("@protobuf-ts/runtime"); +const runtime_2 = require("@protobuf-ts/runtime"); +const runtime_3 = require("@protobuf-ts/runtime"); +const runtime_4 = require("@protobuf-ts/runtime"); +const runtime_5 = require("@protobuf-ts/runtime"); +/** + * @generated from protobuf enum Type + */ +var Type; +(function (Type) { + /** + * @generated synthetic value - protobuf-ts requires all enums to have a 0 value + */ + Type[Type["UNSPECIFIED$"] = 0] = "UNSPECIFIED$"; + /** + * @generated from protobuf enum value: BOOTSTRAP_REQUEST = 1; + */ + Type[Type["BOOTSTRAP_REQUEST"] = 1] = "BOOTSTRAP_REQUEST"; + /** + * @generated from protobuf enum value: BOOTSTRAP_RESPONSE = 2; + */ + Type[Type["BOOTSTRAP_RESPONSE"] = 2] = "BOOTSTRAP_RESPONSE"; + /** + * @generated from protobuf enum value: CONNECTED = 3; + */ + Type[Type["CONNECTED"] = 3] = "CONNECTED"; + /** + * @generated from protobuf enum value: DISCONNECTED = 4; + */ + Type[Type["DISCONNECTED"] = 4] = "DISCONNECTED"; + /** + * @generated from protobuf enum value: ADD_ITEM = 5; + */ + Type[Type["ADD_ITEM"] = 5] = "ADD_ITEM"; + /** + * @generated from protobuf enum value: REMOVE_ITEM = 6; + */ + Type[Type["REMOVE_ITEM"] = 6] = "REMOVE_ITEM"; +})(Type = exports.Type || (exports.Type = {})); +// @generated message type with reflection information, may provide speed optimized methods +class Message$Type extends runtime_5.MessageType { + constructor() { + super("Message", [ + { no: 1, name: "type", kind: "enum", T: () => ["Type", Type] }, + { no: 2, name: "bootstrap", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => exports.State } }, + { no: 3, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }, + { no: 4, name: "signature", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }, + { no: 5, name: "id", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value) { + const message = { type: 0, bootstrap: {} }; + globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + (0, runtime_3.reflectionMergePartial)(this, message, value); + return message; + } + internalBinaryRead(reader, length, options, target) { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* Type type */ 1: + message.type = reader.int32(); + break; + case /* map bootstrap */ 2: + this.binaryReadMap2(message.bootstrap, reader, options); + break; + case /* optional bytes data */ 3: + message.data = reader.bytes(); + break; + case /* optional bytes signature */ 4: + message.signature = reader.bytes(); + break; + case /* optional bytes id */ 5: + message.id = reader.bytes(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + binaryReadMap2(map, reader, options) { + let len = reader.uint32(), end = reader.pos + len, key, val; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = exports.State.internalBinaryRead(reader, reader.uint32(), options); + break; + default: throw new globalThis.Error("unknown map entry field for field Message.bootstrap"); + } + } + map[key ?? ""] = val ?? exports.State.create(); + } + internalBinaryWrite(message, writer, options) { + /* Type type = 1; */ + if (message.type !== 0) + writer.tag(1, runtime_1.WireType.Varint).int32(message.type); + /* map bootstrap = 2; */ + for (let k of Object.keys(message.bootstrap)) { + writer.tag(2, runtime_1.WireType.LengthDelimited).fork().tag(1, runtime_1.WireType.LengthDelimited).string(k); + writer.tag(2, runtime_1.WireType.LengthDelimited).fork(); + exports.State.internalBinaryWrite(message.bootstrap[k], writer, options); + writer.join().join(); + } + /* optional bytes data = 3; */ + if (message.data !== undefined) + writer.tag(3, runtime_1.WireType.LengthDelimited).bytes(message.data); + /* optional bytes signature = 4; */ + if (message.signature !== undefined) + writer.tag(4, runtime_1.WireType.LengthDelimited).bytes(message.signature); + /* optional bytes id = 5; */ + if (message.id !== undefined) + writer.tag(5, runtime_1.WireType.LengthDelimited).bytes(message.id); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message Message + */ +exports.Message = new Message$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class State$Type extends runtime_5.MessageType { + constructor() { + super("State", [ + { no: 1, name: "connectedTo", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 12 /*ScalarType.BYTES*/ } + ]); + } + create(value) { + const message = { connectedTo: [] }; + globalThis.Object.defineProperty(message, runtime_4.MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + (0, runtime_3.reflectionMergePartial)(this, message, value); + return message; + } + internalBinaryRead(reader, length, options, target) { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated bytes connectedTo */ 1: + message.connectedTo.push(reader.bytes()); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? runtime_2.UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message, writer, options) { + /* repeated bytes connectedTo = 1; */ + for (let i = 0; i < message.connectedTo.length; i++) + writer.tag(1, runtime_1.WireType.LengthDelimited).bytes(message.connectedTo[i]); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message State + */ +exports.State = new State$Type();