UNPKG

@waku/core

Version:

TypeScript implementation of the Waku v2 protocol

141 lines 5.16 kB
import { proto_message as proto } from "@waku/proto"; import { determinePubsubTopic, Logger } from "@waku/utils"; const log = new Logger("message:version-0"); const OneMillion = BigInt(1_000_000); export const Version = 0; export { proto }; export class DecodedMessage { pubsubTopic; proto; constructor(pubsubTopic, proto) { this.pubsubTopic = pubsubTopic; this.proto = proto; } get ephemeral() { return Boolean(this.proto.ephemeral); } get payload() { return this.proto.payload; } get contentTopic() { return this.proto.contentTopic; } get timestamp() { // In the case we receive a value that is bigger than JS's max number, // we catch the error and return undefined. try { if (this.proto.timestamp) { // nanoseconds 10^-9 to milliseconds 10^-3 const timestamp = this.proto.timestamp / OneMillion; return new Date(Number(timestamp)); } return; } catch (e) { return; } } get meta() { return this.proto.meta; } get version() { // https://rfc.vac.dev/spec/14/ // > If omitted, the value SHOULD be interpreted as version 0. return this.proto.version ?? Version; } get rateLimitProof() { return this.proto.rateLimitProof; } } export class Encoder { contentTopic; ephemeral; pubsubTopic; metaSetter; constructor(contentTopic, ephemeral = false, pubsubTopic, metaSetter) { this.contentTopic = contentTopic; this.ephemeral = ephemeral; this.pubsubTopic = pubsubTopic; this.metaSetter = metaSetter; if (!contentTopic || contentTopic === "") { throw new Error("Content topic must be specified"); } } async toWire(message) { return proto.WakuMessage.encode(await this.toProtoObj(message)); } async toProtoObj(message) { const timestamp = message.timestamp ?? new Date(); const protoMessage = { payload: message.payload, version: Version, contentTopic: this.contentTopic, timestamp: BigInt(timestamp.valueOf()) * OneMillion, meta: undefined, rateLimitProof: message.rateLimitProof, ephemeral: this.ephemeral }; if (this.metaSetter) { const meta = this.metaSetter(protoMessage); return { ...protoMessage, meta }; } return protoMessage; } } /** * Creates an encoder that encode messages without Waku level encryption or signature. * * An encoder is used to encode messages in the [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) * format to be sent over the Waku network. The resulting encoder can then be * pass to { @link @waku/interfaces!ISender.send } to automatically encode outgoing * messages. */ export function createEncoder({ pubsubTopic, pubsubTopicShardInfo, contentTopic, ephemeral, metaSetter }) { return new Encoder(contentTopic, ephemeral, determinePubsubTopic(contentTopic, pubsubTopic ?? pubsubTopicShardInfo), metaSetter); } export class Decoder { pubsubTopic; contentTopic; constructor(pubsubTopic, contentTopic) { this.pubsubTopic = pubsubTopic; this.contentTopic = contentTopic; if (!contentTopic || contentTopic === "") { throw new Error("Content topic must be specified"); } } fromWireToProtoObj(bytes) { const protoMessage = proto.WakuMessage.decode(bytes); return Promise.resolve({ payload: protoMessage.payload, contentTopic: protoMessage.contentTopic, version: protoMessage.version ?? undefined, timestamp: protoMessage.timestamp ?? undefined, meta: protoMessage.meta ?? undefined, rateLimitProof: protoMessage.rateLimitProof ?? undefined, ephemeral: protoMessage.ephemeral ?? false }); } async fromProtoObj(pubsubTopic, proto) { // https://rfc.vac.dev/spec/14/ // > If omitted, the value SHOULD be interpreted as version 0. if (proto.version ?? 0 !== Version) { log.error("Failed to decode due to incorrect version, expected:", Version, ", actual:", proto.version); return Promise.resolve(undefined); } return new DecodedMessage(pubsubTopic, proto); } } /** * Creates a decoder that decode messages without Waku level encryption. * * A decoder is used to decode messages from the [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/) * format when received from the Waku network. The resulting decoder can then be * pass to { @link @waku/interfaces!IReceiver.subscribe } to automatically decode incoming * messages. * * @param contentTopic The resulting decoder will only decode messages with this content topic. */ export function createDecoder(contentTopic, pubsubTopicShardInfo) { return new Decoder(determinePubsubTopic(contentTopic, pubsubTopicShardInfo), contentTopic); } //# sourceMappingURL=version_0.js.map