chore: simplify encoders/decoders

This commit is contained in:
Danish Arora 2025-08-29 16:30:19 +05:30
parent 907b5f8c5f
commit 991e5cedc5
No known key found for this signature in database
GPG Key ID: 1C6EF37CDAE1426E
5 changed files with 109 additions and 77 deletions

View File

@ -336,6 +336,7 @@ export const moderatePost = async (
const modMsg: ModerateMessage = { const modMsg: ModerateMessage = {
type: MessageType.MODERATE, type: MessageType.MODERATE,
id: uuidv4(),
cellId, cellId,
targetType: 'post', targetType: 'post',
targetId: postId, targetId: postId,
@ -386,6 +387,7 @@ export const moderateComment = async (
const modMsg: ModerateMessage = { const modMsg: ModerateMessage = {
type: MessageType.MODERATE, type: MessageType.MODERATE,
id: uuidv4(),
cellId, cellId,
targetType: 'comment', targetType: 'comment',
targetId: commentId, targetId: commentId,
@ -433,6 +435,7 @@ export const moderateUser = async (
const modMsg: ModerateMessage = { const modMsg: ModerateMessage = {
type: MessageType.MODERATE, type: MessageType.MODERATE,
id: uuidv4(),
cellId, cellId,
targetType: 'user', targetType: 'user',
targetId: userAddress, targetId: userAddress,

View File

@ -1,70 +1,105 @@
import { createDecoder, createEncoder } from '@waku/sdk'; import {
IDecodedMessage,
IDecoder,
IEncoder,
LightNode,
} from '@waku/sdk';
import { MessageType } from './types'; import { MessageType } from './types';
import { CellMessage, PostMessage, CommentMessage, VoteMessage } from './types'; import {
import { CONTENT_TOPICS, NETWORK_CONFIG } from './constants'; CellMessage,
PostMessage,
CommentMessage,
VoteMessage,
} from './types';
import { CONTENT_TOPICS } from './constants';
import { OpchanMessage } from '@/types/forum'; import { OpchanMessage } from '@/types/forum';
// Create the sharded pubsub topic export class CodecManager {
const PUBSUB_TOPIC = `/waku/2/rs/${NETWORK_CONFIG.clusterId}/0`; private encoders: Map<MessageType, IEncoder> = new Map();
private decoders: Map<MessageType, IDecoder<IDecodedMessage>> = new Map();
export const encoders = { constructor(private node: LightNode) {
[MessageType.CELL]: createEncoder({ this.encoders = new Map(
contentTopic: CONTENT_TOPICS[MessageType.CELL], Object.values(MessageType).map((type) => [
routingInfo: { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC } type,
}), this.node.createEncoder({ contentTopic: CONTENT_TOPICS[type] }),
[MessageType.POST]: createEncoder({ ])
contentTopic: CONTENT_TOPICS[MessageType.POST], );
routingInfo: { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }
}),
[MessageType.COMMENT]: createEncoder({
contentTopic: CONTENT_TOPICS[MessageType.COMMENT],
routingInfo: { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }
}),
[MessageType.VOTE]: createEncoder({
contentTopic: CONTENT_TOPICS[MessageType.VOTE],
routingInfo: { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }
}),
[MessageType.MODERATE]: createEncoder({
contentTopic: CONTENT_TOPICS[MessageType.MODERATE],
routingInfo: { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }
})
}
export const decoders = { this.decoders = new Map(
[MessageType.CELL]: createDecoder(CONTENT_TOPICS[MessageType.CELL], { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }), Object.values(MessageType).map((type) => [
[MessageType.POST]: createDecoder(CONTENT_TOPICS[MessageType.POST], { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }), type,
[MessageType.COMMENT]: createDecoder(CONTENT_TOPICS[MessageType.COMMENT], { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }), this.node.createDecoder({ contentTopic: CONTENT_TOPICS[type] }),
[MessageType.VOTE]: createDecoder(CONTENT_TOPICS[MessageType.VOTE], { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }), ])
[MessageType.MODERATE]: createDecoder(CONTENT_TOPICS[MessageType.MODERATE], { clusterId: NETWORK_CONFIG.clusterId, shardId: 0, pubsubTopic: PUBSUB_TOPIC }) );
}
/**
* Encode a message object into a Uint8Array for transmission
*/
export function encodeMessage(message: OpchanMessage): Uint8Array {
const messageJson = JSON.stringify(message);
return new TextEncoder().encode(messageJson);
}
/**
* Decode a message from a Uint8Array based on its type
*/
export function decodeMessage(payload: Uint8Array): OpchanMessage {
const messageJson = new TextDecoder().decode(payload);
const message = JSON.parse(messageJson) as OpchanMessage;
switch(message.type) {
case MessageType.CELL:
return message as CellMessage;
case MessageType.POST:
return message as PostMessage;
case MessageType.COMMENT:
return message as CommentMessage;
case MessageType.VOTE:
return message as VoteMessage;
default:
throw new Error(`Unknown message type: ${message}`);
} }
}
/**
* Encode a message for transmission
*/
encodeMessage(message: OpchanMessage): Uint8Array {
const messageJson = JSON.stringify(message);
return new TextEncoder().encode(messageJson);
}
/**
* Decode a received message
*/
decodeMessage(payload: Uint8Array): OpchanMessage {
const messageJson = new TextDecoder().decode(payload);
const message = JSON.parse(messageJson) as OpchanMessage;
switch (message.type) {
case MessageType.CELL:
return message as CellMessage;
case MessageType.POST:
return message as PostMessage;
case MessageType.COMMENT:
return message as CommentMessage;
case MessageType.VOTE:
return message as VoteMessage;
default:
throw new Error(`Unknown message type: ${message}`);
}
}
/**
* Get encoder for a specific message type
*/
getEncoder(messageType: MessageType): IEncoder {
const encoder = this.encoders.get(messageType);
if (!encoder) {
throw new Error(`No encoder found for message type: ${messageType}`);
}
return encoder;
}
/**
* Get decoder for a specific message type
*/
getDecoder(
messageType: MessageType
): IDecoder<IDecodedMessage> {
const decoder = this.decoders.get(messageType);
if (!decoder) {
throw new Error(`No decoder found for message type: ${messageType}`);
}
return decoder;
}
/**
* Get all decoders for subscribing to multiple message types
*/
getAllDecoders(): IDecoder<IDecodedMessage>[] {
return Array.from(this.decoders.values());
}
/**
* Get decoders for specific message types
*/
getDecoders(
messageTypes: MessageType[]
): IDecoder<IDecodedMessage>[] {
return messageTypes.map((type) => this.getDecoder(type));
}
}

View File

@ -11,12 +11,6 @@ export const CONTENT_TOPICS: Record<MessageType, string> = {
[MessageType.MODERATE]: '/opchan-sds/1/moderate/proto' [MessageType.MODERATE]: '/opchan-sds/1/moderate/proto'
}; };
export const NETWORK_CONFIG = {
// contentTopics: Object.values(CONTENT_TOPICS),
clusterId: 1,
shards: [0,1,2,3,4,5,6,7]
}
/** /**
* Bootstrap nodes for the Waku network * Bootstrap nodes for the Waku network
* These are public Waku nodes that our node will connect to on startup * These are public Waku nodes that our node will connect to on startup

View File

@ -6,7 +6,6 @@ import { CommentCache, MessageType, VoteCache, ModerateMessage } from "./types";
import { PostCache } from "./types"; import { PostCache } from "./types";
import { CellCache } from "./types"; import { CellCache } from "./types";
import { OpchanMessage } from "@/types/forum"; import { OpchanMessage } from "@/types/forum";
import { NETWORK_CONFIG } from "./constants";
import { ReliableMessageManager } from "./reliable_channel"; import { ReliableMessageManager } from "./reliable_channel";
export type HealthChangeCallback = (isReady: boolean, health: HealthStatus) => void; export type HealthChangeCallback = (isReady: boolean, health: HealthStatus) => void;
@ -37,7 +36,6 @@ class MessageManager {
public static async create(): Promise<MessageManager> { public static async create(): Promise<MessageManager> {
const node = await createLightNode({ const node = await createLightNode({
defaultBootstrap: true, defaultBootstrap: true,
networkConfig: NETWORK_CONFIG,
autoStart: true, autoStart: true,
}); });

View File

@ -1,6 +1,6 @@
import { IDecodedMessage, LightNode, ReliableChannel, ReliableChannelEvent } from "@waku/sdk"; import { IDecodedMessage, LightNode, ReliableChannel, ReliableChannelEvent } from "@waku/sdk";
import { MessageType } from "./types"; import { MessageType } from "./types";
import { decodeMessage, decoders, encodeMessage, encoders } from "./codec"; import { CodecManager } from "./codec";
import { generateStringId } from "@/lib/utils"; import { generateStringId } from "@/lib/utils";
import { OpchanMessage } from "@/types/forum"; import { OpchanMessage } from "@/types/forum";
@ -18,15 +18,17 @@ export class ReliableMessageManager {
private channels: Map<MessageType, ReliableChannel<IDecodedMessage>> = new Map(); private channels: Map<MessageType, ReliableChannel<IDecodedMessage>> = new Map();
private messageCallbacks: Map<string, MessageStatusCallback> = new Map(); private messageCallbacks: Map<string, MessageStatusCallback> = new Map();
private incomingMessageCallbacks: IncomingMessageCallback[] = []; private incomingMessageCallbacks: IncomingMessageCallback[] = [];
private codecManager: CodecManager;
constructor(node: LightNode) { constructor(node: LightNode) {
this.codecManager = new CodecManager(node);
this.initializeChannels(node); this.initializeChannels(node);
} }
private async initializeChannels(node: LightNode) { private async initializeChannels(node: LightNode) {
for (const type of Object.values(MessageType)) { for (const type of Object.values(MessageType)) {
const encoder = encoders[type]; const encoder = this.codecManager.getEncoder(type);
const decoder = decoders[type]; const decoder = this.codecManager.getDecoder(type);
const senderId = generateStringId(); const senderId = generateStringId();
const channelId = `opchan-${type}`; // Unique channel ID for each message type const channelId = `opchan-${type}`; // Unique channel ID for each message type
@ -45,7 +47,7 @@ export class ReliableMessageManager {
try { try {
const wakuMessage = event.detail; const wakuMessage = event.detail;
if (wakuMessage.payload) { if (wakuMessage.payload) {
const opchanMessage = decodeMessage(wakuMessage.payload); const opchanMessage = this.codecManager.decodeMessage(wakuMessage.payload);
this.incomingMessageCallbacks.forEach(callback => { this.incomingMessageCallbacks.forEach(callback => {
@ -92,7 +94,7 @@ export class ReliableMessageManager {
throw new Error(`No reliable channel for message type: ${message.type}`); throw new Error(`No reliable channel for message type: ${message.type}`);
} }
const encodedMessage = encodeMessage(message); const encodedMessage = this.codecManager.encodeMessage(message);
const messageId = ReliableChannel.getMessageId(encodedMessage); const messageId = ReliableChannel.getMessageId(encodedMessage);
// Store callback for this message // Store callback for this message