UNPKG

@waku/core

Version:

TypeScript implementation of the Waku v2 protocol

144 lines 5 kB
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