@waku/core
Version:
TypeScript implementation of the Waku v2 protocol
144 lines • 5 kB
JavaScript
import { ProtocolError } from "@waku/interfaces";
import { PushResponse } from "@waku/proto";
import { isMessageSizeUnderCap } from "@waku/utils";
import { Logger } from "@waku/utils";
import all from "it-all";
import * as lp from "it-length-prefixed";
import { pipe } from "it-pipe";
import { Uint8ArrayList } from "uint8arraylist";
import { StreamManager } from "../stream_manager/index.js";
import { PushRpc } from "./push_rpc.js";
import { isRLNResponseError } from "./utils.js";
const log = new Logger("light-push");
export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
export { PushResponse };
/**
* Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
*/
export class LightPushCore {
streamManager;
multicodec = LightPushCodec;
constructor(libp2p) {
this.streamManager = new StreamManager(LightPushCodec, libp2p.components);
}
async preparePushMessage(encoder, message) {
try {
if (!message.payload || message.payload.length === 0) {
log.error("Failed to send waku light push: payload is empty");
return { query: null, error: ProtocolError.EMPTY_PAYLOAD };
}
if (!(await isMessageSizeUnderCap(encoder, message))) {
log.error("Failed to send waku light push: message is bigger than 1MB");
return { query: null, error: ProtocolError.SIZE_TOO_BIG };
}
const protoMessage = await encoder.toProtoObj(message);
if (!protoMessage) {
log.error("Failed to encode to protoMessage, aborting push");
return {
query: null,
error: ProtocolError.ENCODE_FAILED
};
}
const query = PushRpc.createRequest(protoMessage, encoder.pubsubTopic);
return { query, error: null };
}
catch (error) {
log.error("Failed to prepare push message", error);
return {
query: null,
error: ProtocolError.GENERIC_FAIL
};
}
}
async send(encoder, message, peerId) {
const { query, error: preparationError } = await this.preparePushMessage(encoder, message);
if (preparationError || !query) {
return {
success: null,
failure: {
error: preparationError,
peerId
}
};
}
let stream;
try {
stream = await this.streamManager.getStream(peerId);
}
catch (error) {
log.error("Failed to get stream", error);
return {
success: null,
failure: {
error: ProtocolError.NO_STREAM_AVAILABLE,
peerId: peerId
}
};
}
let res;
try {
res = await pipe([query.encode()], lp.encode, stream, lp.decode, async (source) => await all(source));
}
catch (err) {
// can fail only because of `stream` abortion
log.error("Failed to send waku light push request", err);
return {
success: null,
failure: {
error: ProtocolError.STREAM_ABORTED,
peerId: peerId
}
};
}
const bytes = new Uint8ArrayList();
res.forEach((chunk) => {
bytes.append(chunk);
});
let response;
try {
response = PushRpc.decode(bytes).response;
}
catch (err) {
log.error("Failed to decode push reply", err);
return {
success: null,
failure: {
error: ProtocolError.DECODE_FAILED,
peerId: peerId
}
};
}
if (!response) {
log.error("Remote peer fault: No response in PushRPC");
return {
success: null,
failure: {
error: ProtocolError.NO_RESPONSE,
peerId: peerId
}
};
}
if (isRLNResponseError(response.info)) {
log.error("Remote peer fault: RLN generation");
return {
success: null,
failure: {
error: ProtocolError.RLN_PROOF_GENERATION,
peerId: peerId
}
};
}
if (!response.isSuccess) {
log.error("Remote peer rejected the message: ", response.info);
return {
success: null,
failure: {
error: ProtocolError.REMOTE_PEER_REJECTED,
peerId: peerId
}
};
}
return { success: peerId, failure: null };
}
}
//# sourceMappingURL=light_push.js.map