mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-05 23:33:08 +00:00
feat: add POC for Subscribe API
This commit is contained in:
parent
82be279331
commit
68b6bf90bd
@ -84,6 +84,11 @@ export interface ISendMessage {
|
|||||||
*/
|
*/
|
||||||
export type RequestId = string;
|
export type RequestId = string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for subscribe messages.
|
||||||
|
*/
|
||||||
|
export type SubscribeListener = (message: IDecodedMessage) => void;
|
||||||
|
|
||||||
export interface IMetaSetter {
|
export interface IMetaSetter {
|
||||||
(message: IProtoMessage & { meta: undefined }): Uint8Array;
|
(message: IProtoMessage & { meta: undefined }): Uint8Array;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,12 +4,12 @@ import {
|
|||||||
IDecoder,
|
IDecoder,
|
||||||
IFilter,
|
IFilter,
|
||||||
IStore,
|
IStore,
|
||||||
NetworkConfig
|
NetworkConfig,
|
||||||
|
SubscribeListener
|
||||||
} from "@waku/interfaces";
|
} from "@waku/interfaces";
|
||||||
import { createRoutingInfo } from "@waku/utils";
|
import { createRoutingInfo } from "@waku/utils";
|
||||||
|
|
||||||
import { MessageStore } from "./message_store.js";
|
import { MessageStore } from "./message_store.js";
|
||||||
import { IAckManager } from "./utils.js";
|
|
||||||
|
|
||||||
type AckManagerConstructorParams = {
|
type AckManagerConstructorParams = {
|
||||||
messageStore: MessageStore;
|
messageStore: MessageStore;
|
||||||
@ -18,6 +18,14 @@ type AckManagerConstructorParams = {
|
|||||||
networkConfig: NetworkConfig;
|
networkConfig: NetworkConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface IAckManager {
|
||||||
|
start(): void;
|
||||||
|
stop(): void;
|
||||||
|
observe(contentTopic: string): Promise<boolean>;
|
||||||
|
subscribe(contentTopic: string, cb: SubscribeListener): Promise<boolean>;
|
||||||
|
unsubscribe(contentTopic: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
export class AckManager implements IAckManager {
|
export class AckManager implements IAckManager {
|
||||||
private readonly messageStore: MessageStore;
|
private readonly messageStore: MessageStore;
|
||||||
private readonly filterAckManager: FilterAckManager;
|
private readonly filterAckManager: FilterAckManager;
|
||||||
@ -49,7 +57,7 @@ export class AckManager implements IAckManager {
|
|||||||
this.subscribedContentTopics.clear();
|
this.subscribedContentTopics.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async subscribe(contentTopic: string): Promise<boolean> {
|
public async observe(contentTopic: string): Promise<boolean> {
|
||||||
if (this.subscribedContentTopics.has(contentTopic)) {
|
if (this.subscribedContentTopics.has(contentTopic)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -69,6 +77,24 @@ export class AckManager implements IAckManager {
|
|||||||
])
|
])
|
||||||
).some((success) => success);
|
).some((success) => success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async subscribe(
|
||||||
|
contentTopic: string,
|
||||||
|
cb: SubscribeListener
|
||||||
|
): Promise<boolean> {
|
||||||
|
const decoder = createDecoder(
|
||||||
|
contentTopic,
|
||||||
|
createRoutingInfo(this.networkConfig, {
|
||||||
|
contentTopic
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.filterAckManager.subscribe(decoder, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async unsubscribe(contentTopic: string): Promise<void> {
|
||||||
|
return this.filterAckManager.unsubscribe(contentTopic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FilterAckManager {
|
class FilterAckManager {
|
||||||
@ -77,7 +103,9 @@ class FilterAckManager {
|
|||||||
public constructor(
|
public constructor(
|
||||||
private messageStore: MessageStore,
|
private messageStore: MessageStore,
|
||||||
private filter: IFilter
|
private filter: IFilter
|
||||||
) {}
|
) {
|
||||||
|
this.onMessage = this.onMessage.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
return;
|
return;
|
||||||
@ -91,18 +119,48 @@ class FilterAckManager {
|
|||||||
this.decoders.clear();
|
this.decoders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async subscribe(decoder: IDecoder<IDecodedMessage>): Promise<boolean> {
|
public async subscribe(
|
||||||
const success = await this.filter.subscribe(
|
decoder: IDecoder<IDecodedMessage>,
|
||||||
decoder,
|
cb?: SubscribeListener
|
||||||
this.onMessage.bind(this)
|
): Promise<boolean> {
|
||||||
);
|
const success = await this.filter.subscribe(decoder, (message) => {
|
||||||
|
try {
|
||||||
|
cb?.(message);
|
||||||
|
} catch (error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.onMessage(message);
|
||||||
|
} catch (error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
this.decoders.add(decoder);
|
this.decoders.add(decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async onMessage(message: IDecodedMessage): Promise<void> {
|
public async unsubscribe(contentTopic: string): Promise<void> {
|
||||||
|
const decoders = Array.from(this.decoders).filter(
|
||||||
|
(decoder) => decoder.contentTopic === contentTopic
|
||||||
|
);
|
||||||
|
|
||||||
|
const promises = decoders.map((decoder) =>
|
||||||
|
this.filter.unsubscribe(decoder)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
|
for (const decoder of decoders) {
|
||||||
|
this.decoders.delete(decoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onMessage(message: IDecodedMessage): void {
|
||||||
if (!this.messageStore.has(message.hashStr)) {
|
if (!this.messageStore.has(message.hashStr)) {
|
||||||
this.messageStore.add(message, { filterAck: true });
|
this.messageStore.add(message, { filterAck: true });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import {
|
|||||||
ISendMessage,
|
ISendMessage,
|
||||||
IStore,
|
IStore,
|
||||||
NetworkConfig,
|
NetworkConfig,
|
||||||
RequestId
|
RequestId,
|
||||||
|
SubscribeListener
|
||||||
} from "@waku/interfaces";
|
} from "@waku/interfaces";
|
||||||
|
|
||||||
import { AckManager } from "./ack_manager.js";
|
import { AckManager } from "./ack_manager.js";
|
||||||
@ -58,4 +59,15 @@ export class Messaging implements IMessaging {
|
|||||||
public send(wakuLikeMessage: ISendMessage): Promise<RequestId> {
|
public send(wakuLikeMessage: ISendMessage): Promise<RequestId> {
|
||||||
return this.sender.send(wakuLikeMessage);
|
return this.sender.send(wakuLikeMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public subscribe(
|
||||||
|
contentTopic: string,
|
||||||
|
cb: SubscribeListener
|
||||||
|
): Promise<boolean> {
|
||||||
|
return this.ackManager.subscribe(contentTopic, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsubscribe(contentTopic: string): Promise<void> {
|
||||||
|
return this.ackManager.unsubscribe(contentTopic);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,7 @@ export class Sender {
|
|||||||
public async send(message: ISendMessage): Promise<RequestId> {
|
public async send(message: ISendMessage): Promise<RequestId> {
|
||||||
const requestId = await this.messageStore.queue(message);
|
const requestId = await this.messageStore.queue(message);
|
||||||
|
|
||||||
await this.ackManager.subscribe(message.contentTopic);
|
await this.ackManager.observe(message.contentTopic);
|
||||||
await this.sendMessage(requestId, message);
|
await this.sendMessage(requestId, message);
|
||||||
|
|
||||||
return requestId;
|
return requestId;
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
export interface IAckManager {
|
|
||||||
start(): void;
|
|
||||||
stop(): void;
|
|
||||||
subscribe(contentTopic: string): Promise<boolean>;
|
|
||||||
}
|
|
||||||
@ -21,7 +21,8 @@ import type {
|
|||||||
IWaku,
|
IWaku,
|
||||||
IWakuEventEmitter,
|
IWakuEventEmitter,
|
||||||
Libp2p,
|
Libp2p,
|
||||||
NetworkConfig
|
NetworkConfig,
|
||||||
|
SubscribeListener
|
||||||
} from "@waku/interfaces";
|
} from "@waku/interfaces";
|
||||||
import {
|
import {
|
||||||
DefaultNetworkConfig,
|
DefaultNetworkConfig,
|
||||||
@ -305,6 +306,25 @@ export class WakuNode implements IWaku {
|
|||||||
return this.messaging.send(message);
|
return this.messaging.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public subscribe(
|
||||||
|
contentTopic: string,
|
||||||
|
cb: SubscribeListener
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (!this.messaging) {
|
||||||
|
throw new Error("Messaging not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.messaging.subscribe(contentTopic, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsubscribe(contentTopic: string): Promise<void> {
|
||||||
|
if (!this.messaging) {
|
||||||
|
throw new Error("Messaging not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.messaging.unsubscribe(contentTopic);
|
||||||
|
}
|
||||||
|
|
||||||
private createRoutingInfo(
|
private createRoutingInfo(
|
||||||
contentTopic?: string,
|
contentTopic?: string,
|
||||||
shardId?: number
|
shardId?: number
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user