UNPKG

@waku/core

Version:

TypeScript implementation of the Waku v2 protocol

127 lines 4.39 kB
import { ProtocolError } from "@waku/interfaces"; import { proto_metadata } from "@waku/proto"; import { encodeRelayShard, 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"; const log = new Logger("metadata"); export const MetadataCodec = "/vac/waku/metadata/1.0.0"; class Metadata { clusterId; streamManager; libp2pComponents; handshakesConfirmed = new Map(); multicodec = MetadataCodec; constructor(clusterId, libp2p) { this.clusterId = clusterId; this.streamManager = new StreamManager(MetadataCodec, libp2p); this.libp2pComponents = libp2p; void libp2p.registrar.handle(MetadataCodec, (streamData) => { void this.onRequest(streamData); }); } /** * Make a metadata query to a peer */ async query(peerId) { const request = proto_metadata.WakuMetadataRequest.encode({ clusterId: this.clusterId, shards: [] // Only services node need to provide shards }); const peer = await this.libp2pComponents.peerStore.get(peerId); if (!peer) { return { shardInfo: null, error: ProtocolError.NO_PEER_AVAILABLE }; } let stream; try { stream = await this.streamManager.getStream(peerId); } catch (error) { log.error("Failed to get stream", error); return { shardInfo: null, error: ProtocolError.NO_STREAM_AVAILABLE }; } const encodedResponse = await pipe([request], lp.encode, stream, lp.decode, async (source) => await all(source)); const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse); if (error) { return { shardInfo: null, error }; } await this.savePeerShardInfo(peerId, shardInfo); return { shardInfo, error: null }; } async confirmOrAttemptHandshake(peerId) { const shardInfo = this.handshakesConfirmed.get(peerId.toString()); if (shardInfo) { return { shardInfo, error: null }; } return await this.query(peerId); } /** * Handle an incoming metadata request */ async onRequest(streamData) { try { const { stream, connection } = streamData; const encodedShardInfo = proto_metadata.WakuMetadataResponse.encode({ clusterId: this.clusterId, shards: [] // Only service nodes need to provide shards }); const encodedResponse = await pipe([encodedShardInfo], lp.encode, stream, lp.decode, async (source) => await all(source)); const { error, shardInfo } = this.decodeMetadataResponse(encodedResponse); if (error) { return; } await this.savePeerShardInfo(connection.remotePeer, shardInfo); } catch (error) { log.error("Error handling metadata request", error); } } decodeMetadataResponse(encodedResponse) { const bytes = new Uint8ArrayList(); encodedResponse.forEach((chunk) => { bytes.append(chunk); }); const response = proto_metadata.WakuMetadataResponse.decode(bytes); if (!response) { log.error("Error decoding metadata response"); return { shardInfo: null, error: ProtocolError.DECODE_FAILED }; } return { shardInfo: response, error: null }; } async savePeerShardInfo(peerId, shardInfo) { // add or update the shardInfo to peer store await this.libp2pComponents.peerStore.merge(peerId, { metadata: { shardInfo: encodeRelayShard(shardInfo) } }); this.handshakesConfirmed.set(peerId.toString(), shardInfo); } } export function wakuMetadata(clusterId) { return (components) => new Metadata(clusterId, components); } //# sourceMappingURL=metadata.js.map