Compare commits

..

5 Commits

15 changed files with 306 additions and 112 deletions

View File

@ -1,14 +1,14 @@
/// <reference types="node" /> /// <reference types="node" />
/// <reference types="node" /> /// <reference types="node" />
import EventEmitter from "events"; import EventEmitter from "events";
export default class DHTOnlineBase extends EventEmitter { export default class DHTDataBase extends EventEmitter {
protected swarm: any;
private id; private id;
private bootstrapped; private bootstrapped;
private graph; private graph;
private connectedTo; private connectedTo;
private encoding; constructor(id: Buffer, { swarm }?: {
constructor(id: Buffer, { encoding }?: { swarm?: any;
encoding?: string | undefined;
}); });
private _data; private _data;
get data(): {}; get data(): {};
@ -16,7 +16,11 @@ export default class DHTOnlineBase extends EventEmitter {
private _online; private _online;
get online(): string[]; get online(): string[];
broadcast(data: any, ttl?: number): void; broadcast(data: any, ttl?: number): void;
getPeerRaw(id: Buffer | string): any;
getPeerField(id: Buffer | string, field: string): any;
getPeerData(id: Buffer | string): any; getPeerData(id: Buffer | string): any;
getPeerTimestamp(id: Buffer | string): any;
getPeerSignature(id: Buffer | string): any;
protected onAddPeer(id: Buffer): void; protected onAddPeer(id: Buffer): void;
protected onRemovePeer(id: Buffer): void; protected onRemovePeer(id: Buffer): void;
protected onGetBroadcast(message: Buffer, id: Buffer): void; protected onGetBroadcast(message: Buffer, id: Buffer): void;
@ -31,4 +35,4 @@ export default class DHTOnlineBase extends EventEmitter {
private _recalculate; private _recalculate;
private _maybeHexify; private _maybeHexify;
} }
//# sourceMappingURL=dhtOnlineBase.d.ts.map //# sourceMappingURL=DHTDataBase.d.ts.map

1
dist/DHTDataBase.d.ts.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"DHTDataBase.d.ts","sourceRoot":"","sources":["../src/DHTDataBase.ts"],"names":[],"mappings":";;AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAiBlC,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,YAAY;IACnD,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;gBAElB,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,GAAE;QAAE,KAAK,CAAC,EAAE,GAAG,CAAA;KAAO;IAavD,OAAO,CAAC,KAAK,CAAK;IAElB,IAAI,IAAI,IAAI,EAAE,CAEb;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE,EAcjB;IAED,OAAO,CAAC,OAAO,CAAW;IAE1B,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IAED,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM;IAIjC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAI9B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM;IAI/C,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAG/B,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAIpC,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAIpC,SAAS,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM;IAqC9B,SAAS,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM;IAiBjC,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAqDpD,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,cAAc;IAuCtB,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,YAAY;CAOrB"}

View File

@ -6,16 +6,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
const events_1 = __importDefault(require("events")); const events_1 = __importDefault(require("events"));
// @ts-ignore // @ts-ignore
const jsnetworkx_1 = require("jsnetworkx"); const jsnetworkx_1 = require("jsnetworkx");
const codecs_1 = __importDefault(require("codecs")); // @ts-ignore
const ordered_json_1 = __importDefault(require("ordered-json"));
// @ts-ignore
const hypercore_crypto_1 = __importDefault(require("hypercore-crypto"));
const b4a_1 = __importDefault(require("b4a"));
const messages_js_1 = require("./messages.js"); const messages_js_1 = require("./messages.js");
const DEFAULT_ENCODING = "json"; const debug_1 = __importDefault(require("debug"));
class DHTOnlineBase extends events_1.default { class DHTDataBase extends events_1.default {
swarm;
id; id;
bootstrapped; bootstrapped;
graph; graph;
connectedTo; connectedTo;
encoding; constructor(id, { swarm } = {}) {
constructor(id, { encoding = DEFAULT_ENCODING } = {}) {
super(); super();
if (!id) if (!id)
throw new TypeError("Must provide id for self"); throw new TypeError("Must provide id for self");
@ -24,8 +28,8 @@ class DHTOnlineBase extends events_1.default {
this.graph = new jsnetworkx_1.DiGraph(); this.graph = new jsnetworkx_1.DiGraph();
this.connectedTo = new Set(); this.connectedTo = new Set();
this._data = {}; this._data = {};
this.encoding = (0, codecs_1.default)(encoding || DEFAULT_ENCODING);
this._online = [this._maybeHexify(this.id)]; this._online = [this._maybeHexify(this.id)];
this.swarm = swarm;
} }
_data; _data;
get data() { get data() {
@ -33,7 +37,10 @@ class DHTOnlineBase extends events_1.default {
} }
set data(value) { set data(value) {
this._data = value; this._data = value;
this._setPeer(this.id, value); const timestamp = BigInt(Date.now());
const rawData = ordered_json_1.default.stringify(value);
const signature = hypercore_crypto_1.default.sign(b4a_1.default.from(`${timestamp}${rawData}`), this.swarm.keyPair.secretKey);
this._setPeer(this.id, value, timestamp, signature);
this._broadcastData(); this._broadcastData();
} }
_online; _online;
@ -43,9 +50,21 @@ class DHTOnlineBase extends events_1.default {
broadcast(data, ttl) { broadcast(data, ttl) {
throw new TypeError("Broadcast has not been implemented"); throw new TypeError("Broadcast has not been implemented");
} }
getPeerData(id) { getPeerRaw(id) {
return this.graph.node.get(this._maybeHexify(id)); return this.graph.node.get(this._maybeHexify(id));
} }
getPeerField(id, field) {
return this.getPeerRaw(id)?.[field];
}
getPeerData(id) {
return this.getPeerField(id, "data");
}
getPeerTimestamp(id) {
return this.getPeerField(id, "timestamp");
}
getPeerSignature(id) {
return this.getPeerField(id, "signature");
}
onAddPeer(id) { onAddPeer(id) {
const stringId = id.toString("hex"); const stringId = id.toString("hex");
if (this.connectedTo.has(stringId)) { if (this.connectedTo.has(stringId)) {
@ -91,11 +110,16 @@ class DHTOnlineBase extends events_1.default {
throw new Error("Missing Type In Message"); throw new Error("Missing Type In Message");
} }
if (type === messages_js_1.Type.STATE) { if (type === messages_js_1.Type.STATE) {
const { data: rawData } = decoded; const { data: rawData, timestamp, signature } = decoded;
const data = this.encoding.decode(rawData); if (signature &&
this._setPeer(id, data); hypercore_crypto_1.default.verify(b4a_1.default.from(`${timestamp}${rawData}`), signature, id)) {
const data = rawData ? ordered_json_1.default.parse(rawData) : null;
this._setPeer(id, data, timestamp, signature);
this.emit("peer-data", data, id); this.emit("peer-data", data, id);
this._recalculate(); this._recalculate();
return;
}
(0, debug_1.default)(`Invalid signature received for peer ${id}`);
} }
else if (type === messages_js_1.Type.CONNECTED) { else if (type === messages_js_1.Type.CONNECTED) {
const { id: toId } = decoded; const { id: toId } = decoded;
@ -126,17 +150,24 @@ class DHTOnlineBase extends events_1.default {
if (!Object.keys(rawData).length) { if (!Object.keys(rawData).length) {
return; return;
} }
const data = this.encoding.encode(rawData); const data = ordered_json_1.default.stringify(rawData);
const { timestamp, signature } = this.getPeerRaw(this.id);
this.broadcast(messages_js_1.Message.toBinary(messages_js_1.Message.create({ this.broadcast(messages_js_1.Message.toBinary(messages_js_1.Message.create({
type: messages_js_1.Type.STATE, type: messages_js_1.Type.STATE,
data, data: b4a_1.default.from(data),
signature,
timestamp,
}))); })));
} }
_hasSeenPeer(id) { _hasSeenPeer(id) {
return this.graph.hasNode(this._maybeHexify(id)); return this.graph.hasNode(this._maybeHexify(id));
} }
_setPeer(id, data) { _setPeer(id, data, timestamp, signature) {
this.graph.addNode(this._maybeHexify(id), data); this.graph.addNode(this._maybeHexify(id), {
timestamp,
signature,
data,
});
} }
_ensurePeer(id) { _ensurePeer(id) {
id = this._maybeHexify(id); id = this._maybeHexify(id);
@ -165,19 +196,26 @@ class DHTOnlineBase extends events_1.default {
return; return;
} }
for (const id in bootstrap) { for (const id in bootstrap) {
const { data, connectedTo } = bootstrap[id]; const { data, connectedTo, signature, timestamp } = bootstrap[id];
const parsedData = data ? this.encoding.decode(data) : null; if (id === this.id.toString("hex")) {
let peerData = parsedData || {};
if (id === this.id.toString("hex"))
continue; continue;
}
if (signature &&
hypercore_crypto_1.default.verify(b4a_1.default.from(`${timestamp}${data}`), signature, b4a_1.default.from(id))) {
const parsedData = data ? ordered_json_1.default.parse(data) : null;
let peerData = parsedData || {};
// If we're already tracking them // If we're already tracking them
if (this._hasSeenPeer(id)) { if (this._hasSeenPeer(id)) {
// See what data we already have for them // See what data we already have for them
// Add their existing data to what we got from the bootstrap // Add their existing data to what we got from the bootstrap
const existingPeerData = this.getPeerData(id); const existingPeerData = this.getPeerData(id);
peerData = { ...existingPeerData, ...peerData }; peerData = { ...existingPeerData, ...peerData };
this._setPeer(id, peerData, timestamp, signature);
}
}
else {
(0, debug_1.default)(`Invalid signature received for peer ${id}`);
} }
this._setPeer(id, peerData);
for (const connection of connectedTo) { for (const connection of connectedTo) {
this._addPeerConnection(id, Buffer.from(connection)); this._addPeerConnection(id, Buffer.from(connection));
} }
@ -191,8 +229,9 @@ class DHTOnlineBase extends events_1.default {
const connectedTo = this.graph const connectedTo = this.graph
.neighbors(id) .neighbors(id)
.map((id) => Buffer.from(id, "hex")); .map((id) => Buffer.from(id, "hex"));
const data = rawData ? this.encoding.encode(rawData) : null; const data = rawData ? ordered_json_1.default.stringify(rawData?.data) : null;
state[id] = { data, connectedTo }; const { timestamp = undefined, signature = undefined } = rawData;
state[id] = { data: b4a_1.default.from(data), connectedTo, timestamp, signature };
} }
return state; return state;
} }
@ -217,10 +256,10 @@ class DHTOnlineBase extends events_1.default {
this.emit("online", online); this.emit("online", online);
} }
_maybeHexify(data) { _maybeHexify(data) {
if (Buffer.isBuffer(data)) { if (b4a_1.default.isBuffer(data)) {
return data.toString("hex"); return data.toString("hex");
} }
return data; return data;
} }
} }
exports.default = DHTOnlineBase; exports.default = DHTDataBase;

View File

@ -1 +0,0 @@
{"version":3,"file":"dhtOnlineBase.d.ts","sourceRoot":"","sources":["../src/dhtOnlineBase.ts"],"names":[],"mappings":";;AAAA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAYlC,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,YAAY;IACrD,OAAO,CAAC,EAAE,CAAS;IACnB,OAAO,CAAC,YAAY,CAAU;IAC9B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,WAAW,CAAW;IAC9B,OAAO,CAAC,QAAQ,CAAoB;gBAExB,EAAE,EAAE,MAAM,EAAE,EAAE,QAA2B,EAAE;;KAAK;IAa5D,OAAO,CAAC,KAAK,CAAK;IAElB,IAAI,IAAI,IAAI,EAAE,CAEb;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE,EAMjB;IAED,OAAO,CAAC,OAAO,CAAW;IAE1B,IAAI,MAAM,IAAI,MAAM,EAAE,CAErB;IAED,SAAS,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM;IAIjC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;IAI/B,SAAS,CAAC,SAAS,CAAC,EAAE,EAAE,MAAM;IAqC9B,SAAS,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM;IAiBjC,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IA6CpD,OAAO,CAAC,cAAc;IAgBtB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,QAAQ;IAGhB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,iBAAiB;IAczB,OAAO,CAAC,YAAY;IAwBpB,OAAO,CAAC,YAAY;CAOrB"}

5
dist/index.d.ts vendored
View File

@ -1,8 +1,7 @@
/// <reference types="node" /> /// <reference types="node" />
import DHTOnlineBase from "./dhtOnlineBase.js"; import DHTDataBase from "./DHTDataBase.js";
export default class DHTOnline extends DHTOnlineBase { export default class DHTData extends DHTDataBase {
private flood; private flood;
private swarm;
constructor(swarm: any, { id, data, ...opts }?: { constructor(swarm: any, { id, data, ...opts }?: {
id?: Buffer; id?: Buffer;
data?: {}; data?: {};

2
dist/index.d.ts.map vendored
View File

@ -1 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,aAAa,MAAM,oBAAoB,CAAC;AAK/C,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,aAAa;IAClD,OAAO,CAAC,KAAK,CAAW;IACxB,OAAO,CAAC,KAAK,CAAM;gBAGjB,KAAK,EAAE,GAAG,EACV,EACE,EAA4B,EAC5B,IAAS,EACT,GAAG,IAAI,EACR,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAO;IAmBxD,aAAa,CAAC,IAAI,EAAE,GAAG;IAKvB,gBAAgB,CAAC,IAAI,EAAE,GAAG;IAW1B,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM;CAGrC"} {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,OAAO,WAAW,MAAM,kBAAkB,CAAC;AAK3C,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,WAAW;IAC9C,OAAO,CAAC,KAAK,CAAW;gBAGtB,KAAK,EAAE,GAAG,EACV,EACE,EAA4B,EAC5B,IAAS,EACT,GAAG,IAAI,EACR,GAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAO;IAkBxD,aAAa,CAAC,IAAI,EAAE,GAAG;IAKvB,gBAAgB,CAAC,IAAI,EAAE,GAAG;IAW1B,SAAS,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM;CAGrC"}

10
dist/index.js vendored
View File

@ -3,16 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const dhtOnlineBase_js_1 = __importDefault(require("./dhtOnlineBase.js")); const DHTDataBase_js_1 = __importDefault(require("./DHTDataBase.js"));
const dht_flood_1 = __importDefault(require("@lumeweb/dht-flood")); const dht_flood_1 = __importDefault(require("@lumeweb/dht-flood"));
const DISCONNECT_SMOOTH = 500; const DISCONNECT_SMOOTH = 500;
class DHTOnline extends dhtOnlineBase_js_1.default { class DHTData extends DHTDataBase_js_1.default {
flood; flood;
swarm;
constructor(swarm, { id = swarm.keyPair.publicKey, data = {}, ...opts } = {}) { constructor(swarm, { id = swarm.keyPair.publicKey, data = {}, ...opts } = {}) {
super(id, opts); super(id, { swarm, ...opts });
this.flood = new dht_flood_1.default({ id, swarm, ...opts }); this.flood = new dht_flood_1.default({ id, swarm, ...opts });
this.swarm = swarm;
this.flood.on("peer-open", (peer) => this.handlePeerAdd(peer)); this.flood.on("peer-open", (peer) => this.handlePeerAdd(peer));
this.flood.on("peer-remove", (peer) => this.handlePeerRemove(peer)); this.flood.on("peer-remove", (peer) => this.handlePeerRemove(peer));
this.flood.on("message", (message, id) => this.onGetBroadcast(message, id)); this.flood.on("message", (message, id) => this.onGetBroadcast(message, id));
@ -38,4 +36,4 @@ class DHTOnline extends dhtOnlineBase_js_1.default {
this.flood.broadcast(message, ttl); this.flood.broadcast(message, ttl);
} }
} }
exports.default = DHTOnline; exports.default = DHTData;

18
dist/messages.d.ts vendored
View File

@ -23,7 +23,15 @@ export interface Message {
*/ */
data?: Uint8Array; data?: Uint8Array;
/** /**
* @generated from protobuf field: optional bytes id = 4; * @generated from protobuf field: optional bytes signature = 4;
*/
signature?: Uint8Array;
/**
* @generated from protobuf field: optional int64 timestamp = 5;
*/
timestamp?: bigint;
/**
* @generated from protobuf field: optional bytes id = 6;
*/ */
id?: Uint8Array; id?: Uint8Array;
} }
@ -39,6 +47,14 @@ export interface State {
* @generated from protobuf field: optional bytes data = 2; * @generated from protobuf field: optional bytes data = 2;
*/ */
data?: Uint8Array; data?: Uint8Array;
/**
* @generated from protobuf field: optional bytes signature = 3;
*/
signature?: Uint8Array;
/**
* @generated from protobuf field: optional int64 timestamp = 4;
*/
timestamp?: bigint;
} }
/** /**
* @generated from protobuf enum Type * @generated from protobuf enum Type

View File

@ -1 +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,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AACD;;GAEG;AACH,MAAM,WAAW,KAAK;IAClB;;OAEG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;CACrB;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,KAAK,IAAI;CACZ;AAED,cAAM,YAAa,SAAQ,WAAW,CAAC,OAAO,CAAC;;IAS3C,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;IA4BhH,OAAO,CAAC,cAAc;IAgBtB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CAsB3G;AACD;;GAEG;AACH,eAAO,MAAM,OAAO,cAAqB,CAAC;AAE1C,cAAM,UAAW,SAAQ,WAAW,CAAC,KAAK,CAAC;;IAOvC,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;IAsB5G,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CAYzG;AACD;;GAEG;AACH,eAAO,MAAM,KAAK,YAAmB,CAAC"} {"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,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,EAAE,CAAC,EAAE,UAAU,CAAC;CACnB;AACD;;GAEG;AACH,MAAM,WAAW,KAAK;IAClB;;OAEG;IACH,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;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,KAAK,IAAI;CACZ;AAED,cAAM,YAAa,SAAQ,WAAW,CAAC,OAAO,CAAC;;IAW3C,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;IAkChH,OAAO,CAAC,cAAc;IAgBtB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CA4B3G;AACD;;GAEG;AACH,eAAO,MAAM,OAAO,cAAqB,CAAC;AAE1C,cAAM,UAAW,SAAQ,WAAW,CAAC,KAAK,CAAC;;IASvC,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;IA4B5G,mBAAmB,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CAkBzG;AACD;;GAEG;AACH,eAAO,MAAM,KAAK,YAAmB,CAAC"}

38
dist/messages.js vendored
View File

@ -43,7 +43,9 @@ class Message$Type extends runtime_5.MessageType {
{ no: 1, name: "type", kind: "enum", T: () => ["Type", Type] }, { 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: 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: 3, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 4, name: "id", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ } { no: 4, name: "signature", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 5, name: "timestamp", kind: "scalar", opt: true, T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ },
{ no: 6, name: "id", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }
]); ]);
} }
create(value) { create(value) {
@ -67,7 +69,13 @@ class Message$Type extends runtime_5.MessageType {
case /* optional bytes data */ 3: case /* optional bytes data */ 3:
message.data = reader.bytes(); message.data = reader.bytes();
break; break;
case /* optional bytes id */ 4: case /* optional bytes signature */ 4:
message.signature = reader.bytes();
break;
case /* optional int64 timestamp */ 5:
message.timestamp = reader.int64().toBigInt();
break;
case /* optional bytes id */ 6:
message.id = reader.bytes(); message.id = reader.bytes();
break; break;
default: default:
@ -111,9 +119,15 @@ class Message$Type extends runtime_5.MessageType {
/* optional bytes data = 3; */ /* optional bytes data = 3; */
if (message.data !== undefined) if (message.data !== undefined)
writer.tag(3, runtime_1.WireType.LengthDelimited).bytes(message.data); writer.tag(3, runtime_1.WireType.LengthDelimited).bytes(message.data);
/* optional bytes id = 4; */ /* optional bytes signature = 4; */
if (message.signature !== undefined)
writer.tag(4, runtime_1.WireType.LengthDelimited).bytes(message.signature);
/* optional int64 timestamp = 5; */
if (message.timestamp !== undefined)
writer.tag(5, runtime_1.WireType.Varint).int64(message.timestamp);
/* optional bytes id = 6; */
if (message.id !== undefined) if (message.id !== undefined)
writer.tag(4, runtime_1.WireType.LengthDelimited).bytes(message.id); writer.tag(6, runtime_1.WireType.LengthDelimited).bytes(message.id);
let u = options.writeUnknownFields; let u = options.writeUnknownFields;
if (u !== false) if (u !== false)
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@ -129,7 +143,9 @@ class State$Type extends runtime_5.MessageType {
constructor() { constructor() {
super("State", [ super("State", [
{ no: 1, name: "connectedTo", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 12 /*ScalarType.BYTES*/ }, { no: 1, name: "connectedTo", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 12 /*ScalarType.BYTES*/ },
{ no: 2, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ } { no: 2, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 3, name: "signature", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 4, name: "timestamp", kind: "scalar", opt: true, T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ }
]); ]);
} }
create(value) { create(value) {
@ -150,6 +166,12 @@ class State$Type extends runtime_5.MessageType {
case /* optional bytes data */ 2: case /* optional bytes data */ 2:
message.data = reader.bytes(); message.data = reader.bytes();
break; break;
case /* optional bytes signature */ 3:
message.signature = reader.bytes();
break;
case /* optional int64 timestamp */ 4:
message.timestamp = reader.int64().toBigInt();
break;
default: default:
let u = options.readUnknownField; let u = options.readUnknownField;
if (u === "throw") if (u === "throw")
@ -168,6 +190,12 @@ class State$Type extends runtime_5.MessageType {
/* optional bytes data = 2; */ /* optional bytes data = 2; */
if (message.data !== undefined) if (message.data !== undefined)
writer.tag(2, runtime_1.WireType.LengthDelimited).bytes(message.data); writer.tag(2, runtime_1.WireType.LengthDelimited).bytes(message.data);
/* optional bytes signature = 3; */
if (message.signature !== undefined)
writer.tag(3, runtime_1.WireType.LengthDelimited).bytes(message.signature);
/* optional int64 timestamp = 4; */
if (message.timestamp !== undefined)
writer.tag(4, runtime_1.WireType.Varint).int64(message.timestamp);
let u = options.writeUnknownFields; let u = options.writeUnknownFields;
if (u !== false) if (u !== false)
(u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); (u == true ? runtime_2.UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);

View File

@ -12,10 +12,14 @@ message Message {
required Type type = 1; required Type type = 1;
map<string, State> bootstrap = 2; // For bootstrap events map<string, State> bootstrap = 2; // For bootstrap events
optional bytes data = 3; // For state event optional bytes data = 3; // For state event
optional bytes id = 4; // For connected and disconnected events optional bytes signature = 4;
optional int64 timestamp = 5;
optional bytes id = 6; // For connected and disconnected events
} }
message State { message State {
repeated bytes connectedTo = 1; repeated bytes connectedTo = 1;
optional bytes data = 2; optional bytes data = 2;
optional bytes signature = 3;
optional int64 timestamp = 4;
} }

View File

@ -1,16 +1,17 @@
{ {
"name": "@lumeweb/dht-online", "name": "@lumeweb/dht-data",
"type": "commonjs", "type": "commonjs",
"version": "0.1.0", "version": "0.1.0",
"main": "dist/index.js", "main": "dist/index.js",
"dependencies": { "dependencies": {
"@lumeweb/dht-flood": "https://git.lumeweb.com/LumeWeb/dht-flood.git", "@lumeweb/dht-flood": "https://git.lumeweb.com/LumeWeb/dht-flood.git",
"@protobuf-ts/plugin": "^2.8.1", "@protobuf-ts/plugin": "^2.8.1",
"@types/codecs": "^2.2.3", "b4a": "^1.6.1",
"codecs": "^3.0.0",
"compact-encoding": "^2.11.0", "compact-encoding": "^2.11.0",
"hypercore-crypto": "^3.3.0",
"jsnetworkx": "^0.3.4", "jsnetworkx": "^0.3.4",
"lru": "^3.1.0", "lru": "^3.1.0",
"ordered-json": "^0.1.1",
"protocol-buffers-encodings": "^1.2.0", "protocol-buffers-encodings": "^1.2.0",
"protomux-rpc": "^1.3.0" "protomux-rpc": "^1.3.0"
}, },

View File

@ -1,23 +1,28 @@
import EventEmitter from "events"; import EventEmitter from "events";
// @ts-ignore // @ts-ignore
import { DiGraph, hasPath } from "jsnetworkx"; import { DiGraph, hasPath } from "jsnetworkx";
import codecs from "codecs"; // @ts-ignore
import orderedJSON from "ordered-json";
// @ts-ignore
import crypto from "hypercore-crypto";
import b4a from "b4a";
import { Message, State, Type } from "./messages.js"; import { Message, State, Type } from "./messages.js";
// @ts-ignore
const DEFAULT_ENCODING = "json"; import sodium from "sodium-universal";
import debug from "debug";
type Bootstrap = { type Bootstrap = {
[key: string]: State; [key: string]: State;
}; };
export default class DHTOnlineBase extends EventEmitter { export default class DHTDataBase extends EventEmitter {
protected swarm: any;
private id: Buffer; private id: Buffer;
private bootstrapped: boolean; private bootstrapped: boolean;
private graph: any; private graph: any;
private connectedTo: Set<any>; private connectedTo: Set<any>;
private encoding: codecs.Codec<any>;
constructor(id: Buffer, { encoding = DEFAULT_ENCODING } = {}) { constructor(id: Buffer, { swarm }: { swarm?: any } = {}) {
super(); super();
if (!id) throw new TypeError("Must provide id for self"); if (!id) throw new TypeError("Must provide id for self");
@ -26,8 +31,8 @@ export default class DHTOnlineBase extends EventEmitter {
this.graph = new DiGraph(); this.graph = new DiGraph();
this.connectedTo = new Set(); this.connectedTo = new Set();
this._data = {}; this._data = {};
this.encoding = codecs(encoding || DEFAULT_ENCODING);
this._online = [this._maybeHexify(this.id)]; this._online = [this._maybeHexify(this.id)];
this.swarm = swarm;
} }
private _data: {}; private _data: {};
@ -39,8 +44,16 @@ export default class DHTOnlineBase extends EventEmitter {
set data(value: {}) { set data(value: {}) {
this._data = value; this._data = value;
this._setPeer(this.id, value); const timestamp = BigInt(Date.now());
const rawData = orderedJSON.stringify(value);
const signature = crypto.sign(
b4a.from(`${timestamp}${rawData}`),
this.swarm.keyPair.secretKey
);
this._setPeer(this.id, value, timestamp, signature);
this._broadcastData(); this._broadcastData();
} }
@ -54,10 +67,25 @@ export default class DHTOnlineBase extends EventEmitter {
throw new TypeError("Broadcast has not been implemented"); throw new TypeError("Broadcast has not been implemented");
} }
getPeerData(id: Buffer | string) { getPeerRaw(id: Buffer | string) {
return this.graph.node.get(this._maybeHexify(id)); return this.graph.node.get(this._maybeHexify(id));
} }
getPeerField(id: Buffer | string, field: string) {
return this.getPeerRaw(id)?.[field];
}
getPeerData(id: Buffer | string) {
return this.getPeerField(id, "data");
}
getPeerTimestamp(id: Buffer | string) {
return this.getPeerField(id, "timestamp");
}
getPeerSignature(id: Buffer | string) {
return this.getPeerField(id, "signature");
}
protected onAddPeer(id: Buffer) { protected onAddPeer(id: Buffer) {
const stringId = id.toString("hex"); const stringId = id.toString("hex");
if (this.connectedTo.has(stringId)) { if (this.connectedTo.has(stringId)) {
@ -125,11 +153,19 @@ export default class DHTOnlineBase extends EventEmitter {
throw new Error("Missing Type In Message"); throw new Error("Missing Type In Message");
} }
if (type === Type.STATE) { if (type === Type.STATE) {
const { data: rawData } = decoded; const { data: rawData, timestamp, signature } = decoded;
const data = this.encoding.decode(rawData);
this._setPeer(id, data); if (
signature &&
crypto.verify(b4a.from(`${timestamp}${rawData}`), signature, id)
) {
const data = rawData ? orderedJSON.parse(rawData) : null;
this._setPeer(id, data, timestamp, signature);
this.emit("peer-data", data, id); this.emit("peer-data", data, id);
this._recalculate(); this._recalculate();
return;
}
debug(`Invalid signature received for peer ${id}`);
} else if (type === Type.CONNECTED) { } else if (type === Type.CONNECTED) {
const { id: toId } = decoded; const { id: toId } = decoded;
this._addPeerConnection(id, Buffer.from(toId as Uint8Array)); this._addPeerConnection(id, Buffer.from(toId as Uint8Array));
@ -162,12 +198,15 @@ export default class DHTOnlineBase extends EventEmitter {
if (!Object.keys(rawData).length) { if (!Object.keys(rawData).length) {
return; return;
} }
const data = this.encoding.encode(rawData); const data = orderedJSON.stringify(rawData);
const { timestamp, signature } = this.getPeerRaw(this.id);
this.broadcast( this.broadcast(
Message.toBinary( Message.toBinary(
Message.create({ Message.create({
type: Type.STATE, type: Type.STATE,
data, data: b4a.from(data),
signature,
timestamp,
}) })
) )
); );
@ -177,9 +216,19 @@ export default class DHTOnlineBase extends EventEmitter {
return this.graph.hasNode(this._maybeHexify(id)); return this.graph.hasNode(this._maybeHexify(id));
} }
private _setPeer(id: Buffer | string, data: any) { private _setPeer(
this.graph.addNode(this._maybeHexify(id), data); id: Buffer | string,
data: any,
timestamp?: BigInt,
signature?: Uint8Array
) {
this.graph.addNode(this._maybeHexify(id), {
timestamp,
signature,
data,
});
} }
private _ensurePeer(id: Buffer | string) { private _ensurePeer(id: Buffer | string) {
id = this._maybeHexify(id); id = this._maybeHexify(id);
if (!this._hasSeenPeer(id)) { if (!this._hasSeenPeer(id)) {
@ -218,18 +267,29 @@ export default class DHTOnlineBase extends EventEmitter {
} }
for (const id in bootstrap) { for (const id in bootstrap) {
const { data, connectedTo } = bootstrap[id]; const { data, connectedTo, signature, timestamp } = bootstrap[id];
const parsedData = data ? this.encoding.decode(data) : null; if (id === this.id.toString("hex")) {
continue;
}
if (
signature &&
crypto.verify(b4a.from(`${timestamp}${data}`), signature, b4a.from(id))
) {
const parsedData = data ? orderedJSON.parse(data) : null;
let peerData = parsedData || {}; let peerData = parsedData || {};
if (id === this.id.toString("hex")) continue;
// If we're already tracking them // If we're already tracking them
if (this._hasSeenPeer(id)) { if (this._hasSeenPeer(id)) {
// See what data we already have for them // See what data we already have for them
// Add their existing data to what we got from the bootstrap // Add their existing data to what we got from the bootstrap
const existingPeerData = this.getPeerData(id); const existingPeerData = this.getPeerData(id);
peerData = { ...existingPeerData, ...peerData }; peerData = { ...existingPeerData, ...peerData };
this._setPeer(id, peerData, timestamp, signature);
}
} else {
debug(`Invalid signature received for peer ${id}`);
} }
this._setPeer(id, peerData);
for (const connection of connectedTo) { for (const connection of connectedTo) {
this._addPeerConnection(id, Buffer.from(connection)); this._addPeerConnection(id, Buffer.from(connection));
} }
@ -239,14 +299,17 @@ export default class DHTOnlineBase extends EventEmitter {
this._recalculate(); this._recalculate();
} }
private _getBootstrapInfo() { private _getBootstrapInfo() {
const state: Bootstrap = {}; const state: Bootstrap = {};
for (const [id, rawData] of this.graph.nodes(true)) { for (const [id, rawData] of this.graph.nodes(true)) {
const connectedTo = this.graph const connectedTo = this.graph
.neighbors(id) .neighbors(id)
.map((id: string) => Buffer.from(id, "hex")); .map((id: string) => Buffer.from(id, "hex"));
const data = rawData ? this.encoding.encode(rawData) : null;
state[id] = { data, connectedTo }; const data = rawData ? orderedJSON.stringify(rawData?.data) : null;
const { timestamp = undefined, signature = undefined } = rawData;
state[id] = { data: b4a.from(data), connectedTo, timestamp, signature };
} }
return state; return state;
@ -278,7 +341,7 @@ export default class DHTOnlineBase extends EventEmitter {
} }
private _maybeHexify(data: Buffer | string): string { private _maybeHexify(data: Buffer | string): string {
if (Buffer.isBuffer(data)) { if (b4a.isBuffer(data)) {
return data.toString("hex"); return data.toString("hex");
} }

View File

@ -1,11 +1,10 @@
import DHTOnlineBase from "./dhtOnlineBase.js"; import DHTDataBase from "./DHTDataBase.js";
import DHTFlood from "@lumeweb/dht-flood"; import DHTFlood from "@lumeweb/dht-flood";
const DISCONNECT_SMOOTH = 500; const DISCONNECT_SMOOTH = 500;
export default class DHTOnline extends DHTOnlineBase { export default class DHTData extends DHTDataBase {
private flood: DHTFlood; private flood: DHTFlood;
private swarm: any;
constructor( constructor(
swarm: any, swarm: any,
@ -15,9 +14,8 @@ export default class DHTOnline extends DHTOnlineBase {
...opts ...opts
}: { id?: Buffer; data?: {}; [key: string]: any } = {} }: { id?: Buffer; data?: {}; [key: string]: any } = {}
) { ) {
super(id, opts as any); super(id, { swarm, ...(opts as any) });
this.flood = new DHTFlood({ id, swarm, ...opts }); this.flood = new DHTFlood({ id, swarm, ...opts });
this.swarm = swarm;
this.flood.on("peer-open", (peer) => this.handlePeerAdd(peer)); this.flood.on("peer-open", (peer) => this.handlePeerAdd(peer));
this.flood.on("peer-remove", (peer) => this.handlePeerRemove(peer)); this.flood.on("peer-remove", (peer) => this.handlePeerRemove(peer));

View File

@ -30,7 +30,15 @@ export interface Message {
*/ */
data?: Uint8Array; // For state event data?: Uint8Array; // For state event
/** /**
* @generated from protobuf field: optional bytes id = 4; * @generated from protobuf field: optional bytes signature = 4;
*/
signature?: Uint8Array;
/**
* @generated from protobuf field: optional int64 timestamp = 5;
*/
timestamp?: bigint;
/**
* @generated from protobuf field: optional bytes id = 6;
*/ */
id?: Uint8Array; // For connected and disconnected events id?: Uint8Array; // For connected and disconnected events
} }
@ -46,6 +54,14 @@ export interface State {
* @generated from protobuf field: optional bytes data = 2; * @generated from protobuf field: optional bytes data = 2;
*/ */
data?: Uint8Array; data?: Uint8Array;
/**
* @generated from protobuf field: optional bytes signature = 3;
*/
signature?: Uint8Array;
/**
* @generated from protobuf field: optional int64 timestamp = 4;
*/
timestamp?: bigint;
} }
/** /**
* @generated from protobuf enum Type * @generated from protobuf enum Type
@ -83,7 +99,9 @@ class Message$Type extends MessageType<Message> {
{ no: 1, name: "type", kind: "enum", T: () => ["Type", Type] }, { no: 1, name: "type", kind: "enum", T: () => ["Type", Type] },
{ no: 2, name: "bootstrap", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => State } }, { no: 2, name: "bootstrap", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => State } },
{ no: 3, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }, { no: 3, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 4, name: "id", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ } { no: 4, name: "signature", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 5, name: "timestamp", kind: "scalar", opt: true, T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ },
{ no: 6, name: "id", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ }
]); ]);
} }
create(value?: PartialMessage<Message>): Message { create(value?: PartialMessage<Message>): Message {
@ -107,7 +125,13 @@ class Message$Type extends MessageType<Message> {
case /* optional bytes data */ 3: case /* optional bytes data */ 3:
message.data = reader.bytes(); message.data = reader.bytes();
break; break;
case /* optional bytes id */ 4: case /* optional bytes signature */ 4:
message.signature = reader.bytes();
break;
case /* optional int64 timestamp */ 5:
message.timestamp = reader.int64().toBigInt();
break;
case /* optional bytes id */ 6:
message.id = reader.bytes(); message.id = reader.bytes();
break; break;
default: default:
@ -151,9 +175,15 @@ class Message$Type extends MessageType<Message> {
/* optional bytes data = 3; */ /* optional bytes data = 3; */
if (message.data !== undefined) if (message.data !== undefined)
writer.tag(3, WireType.LengthDelimited).bytes(message.data); writer.tag(3, WireType.LengthDelimited).bytes(message.data);
/* optional bytes id = 4; */ /* optional bytes signature = 4; */
if (message.signature !== undefined)
writer.tag(4, WireType.LengthDelimited).bytes(message.signature);
/* optional int64 timestamp = 5; */
if (message.timestamp !== undefined)
writer.tag(5, WireType.Varint).int64(message.timestamp);
/* optional bytes id = 6; */
if (message.id !== undefined) if (message.id !== undefined)
writer.tag(4, WireType.LengthDelimited).bytes(message.id); writer.tag(6, WireType.LengthDelimited).bytes(message.id);
let u = options.writeUnknownFields; let u = options.writeUnknownFields;
if (u !== false) if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);
@ -169,7 +199,9 @@ class State$Type extends MessageType<State> {
constructor() { constructor() {
super("State", [ super("State", [
{ no: 1, name: "connectedTo", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 12 /*ScalarType.BYTES*/ }, { no: 1, name: "connectedTo", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 12 /*ScalarType.BYTES*/ },
{ no: 2, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ } { no: 2, name: "data", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 3, name: "signature", kind: "scalar", opt: true, T: 12 /*ScalarType.BYTES*/ },
{ no: 4, name: "timestamp", kind: "scalar", opt: true, T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ }
]); ]);
} }
create(value?: PartialMessage<State>): State { create(value?: PartialMessage<State>): State {
@ -190,6 +222,12 @@ class State$Type extends MessageType<State> {
case /* optional bytes data */ 2: case /* optional bytes data */ 2:
message.data = reader.bytes(); message.data = reader.bytes();
break; break;
case /* optional bytes signature */ 3:
message.signature = reader.bytes();
break;
case /* optional int64 timestamp */ 4:
message.timestamp = reader.int64().toBigInt();
break;
default: default:
let u = options.readUnknownField; let u = options.readUnknownField;
if (u === "throw") if (u === "throw")
@ -208,6 +246,12 @@ class State$Type extends MessageType<State> {
/* optional bytes data = 2; */ /* optional bytes data = 2; */
if (message.data !== undefined) if (message.data !== undefined)
writer.tag(2, WireType.LengthDelimited).bytes(message.data); writer.tag(2, WireType.LengthDelimited).bytes(message.data);
/* optional bytes signature = 3; */
if (message.signature !== undefined)
writer.tag(3, WireType.LengthDelimited).bytes(message.signature);
/* optional int64 timestamp = 4; */
if (message.timestamp !== undefined)
writer.tag(4, WireType.Varint).int64(message.timestamp);
let u = options.writeUnknownFields; let u = options.writeUnknownFields;
if (u !== false) if (u !== false)
(u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer);