mirror of
https://github.com/logos-messaging/logos-messaging-js.git
synced 2026-01-14 05:53:07 +00:00
133 lines
3.6 KiB
TypeScript
133 lines
3.6 KiB
TypeScript
import type { PeerId } from "@libp2p/interface-peer-id";
|
|
import type { Peer } from "@libp2p/interface-peer-store";
|
|
import debug from "debug";
|
|
import all from "it-all";
|
|
import * as lp from "it-length-prefixed";
|
|
import { pipe } from "it-pipe";
|
|
import { Libp2p } from "libp2p";
|
|
import { Uint8ArrayList } from "uint8arraylist";
|
|
|
|
import { PushResponse } from "../../proto/light_push";
|
|
import { DefaultPubSubTopic } from "../constants";
|
|
import { Encoder, Message } from "../interfaces";
|
|
import { selectConnection } from "../select_connection";
|
|
import {
|
|
getPeersForProtocol,
|
|
selectPeerForProtocol,
|
|
selectRandomPeer,
|
|
} from "../select_peer";
|
|
|
|
import { PushRPC } from "./push_rpc";
|
|
|
|
const log = debug("waku:light-push");
|
|
|
|
export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
|
|
export { PushResponse };
|
|
|
|
export interface CreateOptions {
|
|
/**
|
|
* The PubSub Topic to use. Defaults to {@link DefaultPubSubTopic}.
|
|
*
|
|
* The usage of the default pubsub topic is recommended.
|
|
* See [Waku v2 Topic Usage Recommendations](https://rfc.vac.dev/spec/23/) for details.
|
|
*
|
|
* @default {@link DefaultPubSubTopic}
|
|
*/
|
|
pubSubTopic?: string;
|
|
}
|
|
|
|
export interface PushOptions {
|
|
peerId?: PeerId;
|
|
pubSubTopic?: string;
|
|
}
|
|
|
|
/**
|
|
* Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
|
|
*/
|
|
export class WakuLightPush {
|
|
pubSubTopic: string;
|
|
|
|
constructor(public libp2p: Libp2p, options?: CreateOptions) {
|
|
this.pubSubTopic = options?.pubSubTopic ?? DefaultPubSubTopic;
|
|
}
|
|
|
|
async push(
|
|
encoder: Encoder,
|
|
message: Message,
|
|
opts?: PushOptions
|
|
): Promise<PushResponse | undefined> {
|
|
const pubSubTopic = opts?.pubSubTopic ? opts.pubSubTopic : this.pubSubTopic;
|
|
|
|
const res = await selectPeerForProtocol(
|
|
this.libp2p.peerStore,
|
|
[LightPushCodec],
|
|
opts?.peerId
|
|
);
|
|
|
|
if (!res) {
|
|
throw new Error("Failed to get a peer");
|
|
}
|
|
const { peer } = res;
|
|
|
|
const connections = this.libp2p.connectionManager.getConnections(peer.id);
|
|
const connection = selectConnection(connections);
|
|
|
|
if (!connection) throw "Failed to get a connection to the peer";
|
|
|
|
const stream = await connection.newStream(LightPushCodec);
|
|
try {
|
|
const protoMessage = await encoder.encodeProto(message);
|
|
if (!protoMessage) {
|
|
log("Failed to encode to protoMessage, aborting push");
|
|
return;
|
|
}
|
|
const query = PushRPC.createRequest(protoMessage, pubSubTopic);
|
|
const res = await pipe(
|
|
[query.encode()],
|
|
lp.encode(),
|
|
stream,
|
|
lp.decode(),
|
|
async (source) => await all(source)
|
|
);
|
|
try {
|
|
const bytes = new Uint8ArrayList();
|
|
res.forEach((chunk) => {
|
|
bytes.append(chunk);
|
|
});
|
|
|
|
const response = PushRPC.decode(bytes).response;
|
|
|
|
if (!response) {
|
|
log("No response in PushRPC");
|
|
return;
|
|
}
|
|
|
|
return response;
|
|
} catch (err) {
|
|
log("Failed to decode push reply", err);
|
|
}
|
|
} catch (err) {
|
|
log("Failed to send waku light push request", err);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Returns known peers from the address book (`libp2p.peerStore`) that support
|
|
* light push protocol. Waku may or may not be currently connected to these
|
|
* peers.
|
|
*/
|
|
async peers(): Promise<Peer[]> {
|
|
return getPeersForProtocol(this.libp2p.peerStore, [LightPushCodec]);
|
|
}
|
|
|
|
/**
|
|
* Returns a random peer that supports light push protocol from the address
|
|
* book (`libp2p.peerStore`). Waku may or may not be currently connected to
|
|
* this peer.
|
|
*/
|
|
async randomPeer(): Promise<Peer | undefined> {
|
|
return selectRandomPeer(await this.peers());
|
|
}
|
|
}
|