mirror of
https://github.com/logos-messaging/logos-messaging-js.git
synced 2026-01-16 06:53:08 +00:00
108 lines
3.3 KiB
TypeScript
108 lines
3.3 KiB
TypeScript
import Gossipsub from 'libp2p-gossipsub';
|
|
import { Libp2p } from 'libp2p-gossipsub/src/interfaces';
|
|
import Pubsub from 'libp2p-interfaces/src/pubsub';
|
|
import { SignaturePolicy } from 'libp2p-interfaces/src/pubsub/signature-policy';
|
|
|
|
import { getWakuPeers } from './get_waku_peers';
|
|
import { Message } from './waku_message';
|
|
|
|
export const CODEC = '/vac/waku/relay/2.0.0-beta2';
|
|
|
|
// As per waku specs, the topic is fixed, value taken from nim-waku
|
|
export const TOPIC = '/waku/2/default-waku/proto';
|
|
|
|
// This is the class to pass to libp2p as pubsub protocol
|
|
export class WakuRelayPubsub extends Gossipsub {
|
|
/**
|
|
*
|
|
* @param libp2p: Libp2p
|
|
* @param options: Partial<GossipInputOptions>
|
|
*/
|
|
constructor(libp2p: Libp2p) {
|
|
super(libp2p, {
|
|
emitSelf: true,
|
|
// Ensure that no signature is expected in the messages.
|
|
globalSignaturePolicy: SignaturePolicy.StrictNoSign,
|
|
});
|
|
|
|
const multicodecs = [CODEC];
|
|
|
|
// This is the downside of using `libp2p-gossipsub` instead of
|
|
// implementing WakuRelay from scratch.
|
|
Object.assign(this, { multicodecs });
|
|
}
|
|
|
|
/**
|
|
* Join topic
|
|
* @param {string} topic
|
|
* @returns {void}
|
|
* @override
|
|
*/
|
|
join(topic: string): void {
|
|
if (!this.started) {
|
|
throw new Error('WakuRelayPubsub has not started');
|
|
}
|
|
|
|
const fanoutPeers = this.fanout.get(topic);
|
|
if (fanoutPeers) {
|
|
// these peers have a score above the publish threshold, which may be negative
|
|
// so drop the ones with a negative score
|
|
fanoutPeers.forEach((id) => {
|
|
if (this.score.score(id) < 0) {
|
|
fanoutPeers.delete(id);
|
|
}
|
|
});
|
|
if (fanoutPeers.size < this._options.D) {
|
|
// we need more peers; eager, as this would get fixed in the next heartbeat
|
|
getWakuPeers(
|
|
this,
|
|
topic,
|
|
this._options.D - fanoutPeers.size,
|
|
(id: string): boolean => {
|
|
// filter our current peers, direct peers, and peers with negative scores
|
|
return (
|
|
!fanoutPeers.has(id) &&
|
|
!this.direct.has(id) &&
|
|
this.score.score(id) >= 0
|
|
);
|
|
}
|
|
).forEach((id) => fanoutPeers.add(id));
|
|
}
|
|
this.mesh.set(topic, fanoutPeers);
|
|
this.fanout.delete(topic);
|
|
this.lastpub.delete(topic);
|
|
} else {
|
|
const peers = getWakuPeers(
|
|
this,
|
|
topic,
|
|
this._options.D,
|
|
(id: string): boolean => {
|
|
// filter direct peers and peers with negative score
|
|
return !this.direct.has(id) && this.score.score(id) >= 0;
|
|
}
|
|
);
|
|
this.mesh.set(topic, peers);
|
|
}
|
|
this.mesh.get(topic)!.forEach((id) => {
|
|
this.log('JOIN: Add mesh link to %s in %s', id, topic);
|
|
this._sendGraft(id, topic);
|
|
});
|
|
}
|
|
}
|
|
|
|
// TODO: Implement dial for an address with format '/ip4/127.0.0.1/tcp/60000/p2p/16Uiu2HAkyzsXzENw5XBDYEQQAeQTCYjBJpMLgBmEXuwbtcrgxBJ4'
|
|
// This class provides an interface to execute the waku relay protocol
|
|
export class WakuRelay {
|
|
constructor(private pubsub: Pubsub) {}
|
|
|
|
// At this stage we are always using the same topic so we do not pass it as a parameter
|
|
async subscribe() {
|
|
await this.pubsub.subscribe(TOPIC);
|
|
}
|
|
|
|
async publish(message: Message) {
|
|
const msg = message.toBinary();
|
|
await this.pubsub.publish(TOPIC, msg);
|
|
}
|
|
}
|