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