Merge 0f5e437680e7b879224ee7b1245756d426baa036 into 788f7e62c5141d10d013c91c28d549188d165762

This commit is contained in:
Sasha 2025-12-01 11:55:51 +09:00 committed by GitHub
commit 315a19699c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 237 additions and 0 deletions

View File

@ -18,3 +18,4 @@ export * from "./constants.js";
export * from "./sharding.js";
export * from "./health_status.js";
export * from "./discovery.js";
export * from "./webrtc.js";

View File

@ -15,6 +15,7 @@ import type { Protocols } from "./protocols.js";
import type { IRelay } from "./relay.js";
import type { ShardId } from "./sharding.js";
import type { IStore } from "./store.js";
import type { IWebRTC } from "./webrtc.js";
export type CreateDecoderParams = {
contentTopic: string;
@ -62,6 +63,7 @@ export interface IWaku {
store?: IStore;
filter?: IFilter;
lightPush?: ILightPush;
webRTC?: IWebRTC;
/**
* Emits events related to the Waku node.
@ -272,6 +274,7 @@ export interface LightNode extends IWaku {
store: IStore;
filter: IFilter;
lightPush: ILightPush;
webRTC: IWebRTC;
}
export interface RelayNode extends IWaku {

View File

@ -0,0 +1,93 @@
import type { PeerId, TypedEventEmitter } from "@libp2p/interface";
export enum WebRTCEvent {
InboundRequest = "webRTC:inbound-request",
Connected = "webRTC:connected",
Closed = "webRTC:closed",
Rejected = "webRTC:rejected"
}
export interface IWebRTCEvents {
/**
* Used to listen to incoming WebRTC connection request.
*
* @example
* ```typescript
* waku.addEventListener(WebRTCEvent.Inbound, (event) => {
* const requesterPeerId = event.detail;
*
* if (requesterPeerId.equals(expectedPeerId)) {
* waku.webRTC.accept(requesterPeerId);
* } else {
* waku.webRTC.hangUp(requesterPeerId);
* }
* });
*/
[WebRTCEvent.InboundRequest]: CustomEvent<PeerId>;
/**
* Used to listen to get notified when a WebRTC connection is established.
*
* @example
* ```typescript
* waku.addEventListener(WebRTCEvent.Connected, (event) => {
* const connection = event.detail; // RTCPeerConnection
* });
* ```
*/
[WebRTCEvent.Connected]: CustomEvent<RTCPeerConnection>;
}
export type PeerIdOrString = PeerId | string;
export type WebRTCDialOptions = {
peerId: PeerIdOrString;
timeoutMs?: number;
};
export interface IWebRTC {
/**
* Used to listen to incoming WebRTC connection request or progress of established connections.
*/
events: TypedEventEmitter<IWebRTCEvents>;
/**
* Starts the listening to incoming WebRTC connection requests.
*/
start(): Promise<void>;
/**
* Stops the listening to incoming WebRTC connection requests.
*/
stop(): Promise<void>;
/**
* Dials a peer using Waku WebRTC protocol.
*/
dial(options: WebRTCDialOptions): Promise<void>;
/**
* Accepts a WebRTC connection request from a peer.
*/
accept(peerId: PeerIdOrString): void;
/**
* Hang up a WebRTC connection to a peer or incoming connection request.
*/
hangUp(peerId: PeerIdOrString): void;
/**
* Checks if a WebRTC connection is established to a peer.
*/
isConnected(peerId: PeerIdOrString): boolean;
/**
* Gets the list of connected peers using Waku WebRTC protocol.
*/
getConnectedPeers(): PeerId[];
/**
* Gets map of WebRTC connections by peer ID.
*/
getConnections(): Record<string, RTCPeerConnection>;
}

View File

@ -20,6 +20,7 @@ import type {
IStore,
IWaku,
IWakuEventEmitter,
IWebRTC,
Libp2p,
NetworkConfig
} from "@waku/interfaces";
@ -35,6 +36,7 @@ import { HealthIndicator } from "../health_indicator/index.js";
import { LightPush } from "../light_push/index.js";
import { PeerManager } from "../peer_manager/index.js";
import { Store } from "../store/index.js";
import { WebRTC } from "../webrtc/index.js";
import { waitForRemotePeer } from "./wait_for_remote_peer.js";
@ -52,6 +54,7 @@ export class WakuNode implements IWaku {
public store?: IStore;
public filter?: IFilter;
public lightPush?: ILightPush;
public webRTC?: IWebRTC;
public readonly events: IWakuEventEmitter = new TypedEventEmitter();
@ -126,6 +129,21 @@ export class WakuNode implements IWaku {
});
}
if (this.lightPush && this.filter) {
const webRtcContentTopic = WebRTC.buildContentTopic(this.libp2p.peerId);
this.webRTC = new WebRTC({
lightPush: this.lightPush,
filter: this.filter,
encoder: this.createEncoder({
contentTopic: webRtcContentTopic
}),
decoder: this.createDecoder({
contentTopic: webRtcContentTopic
})
});
}
log.info(
"Waku node created",
peerId,

View File

@ -0,0 +1 @@
export { WebRTC } from "./webrtc.js";

View File

@ -0,0 +1,121 @@
import { PeerId, TypedEventEmitter } from "@libp2p/interface";
import type {
IDecodedMessage,
IDecoder,
IEncoder,
IFilter,
ILightPush,
IWebRTC,
IWebRTCEvents,
PeerIdOrString,
WebRTCDialOptions
} from "@waku/interfaces";
type WebRTCConstructorOptions = {
lightPush: ILightPush;
filter: IFilter;
decoder: IDecoder<IDecodedMessage>;
encoder: IEncoder;
};
export class WebRTC implements IWebRTC {
private readonly lightPush: ILightPush;
private readonly filter: IFilter;
private readonly decoder: IDecoder<IDecodedMessage>;
private readonly encoder: IEncoder;
public readonly events: TypedEventEmitter<IWebRTCEvents> =
new TypedEventEmitter();
private isStarted = false;
public static buildContentTopic(peerId: PeerId): string {
return `/js-waku-webrtc/1/${peerId.toString()}/proto`;
}
public constructor(options: WebRTCConstructorOptions) {
this.lightPush = options.lightPush;
this.filter = options.filter;
this.decoder = options.decoder;
this.encoder = options.encoder;
this.handleInboundRequest = this.handleInboundRequest.bind(this);
}
public async start(): Promise<void> {
if (this.isStarted) {
return;
}
this.isStarted = true;
await this.subscribeToInboundRequests();
}
public async stop(): Promise<void> {
if (!this.isStarted) {
return;
}
this.isStarted = false;
await this.unsubscribeFromInboundRequests();
}
public async dial(options: WebRTCDialOptions): Promise<void> {
// TODO: implement
}
public accept(peerId: PeerIdOrString): void {
// TODO: implement
}
public hangUp(peerId: PeerIdOrString): void {
// TODO: implement
}
public isConnected(peerId: PeerIdOrString): boolean {
// TODO: implement
return false;
}
public getConnectedPeers(): PeerId[] {
// TODO: implement
return [];
}
public getConnections(): Record<string, RTCPeerConnection> {
// TODO: implement
return {};
}
private async subscribeToInboundRequests(): Promise<void> {
await this.filter.subscribe(this.decoder, this.handleInboundRequest);
}
private async unsubscribeFromInboundRequests(): Promise<void> {
await this.filter.unsubscribe(this.decoder);
}
private handleInboundRequest(message: IDecodedMessage): void {
/*
const decryptedMessage = decrypt(message.payload, this.privateKey);
switch (decryptedMessage.type) {
case "dial":
break;
case "ack":
break;
case "answer":
break;
case "reject":
break;
case "candidate":
break;
case "close":
break;
default:
break;
}
*/
}
}