@waku/core
Version:
TypeScript implementation of the Waku v2 protocol
141 lines • 5.16 kB
JavaScript
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