mirror of https://github.com/status-im/js-waku.git
Implement chat message protobuf to support nick and time handles
This commit is contained in:
parent
0f694cf8e1
commit
cca1d685dc
|
@ -3,4 +3,4 @@ version: v1beta1
|
|||
plugins:
|
||||
- name: ts_proto
|
||||
out: ./src/proto
|
||||
opt: grpc_js
|
||||
opt: grpc_js,esModuleInterop=true
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package chat.v2;
|
||||
|
||||
message ChatMessageProto {
|
||||
uint64 timestamp = 1;
|
||||
string nick = 2;
|
||||
bytes payload = 3;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { expect } from 'chai';
|
||||
import fc from 'fast-check';
|
||||
|
||||
import { ChatMessage } from './chat_message';
|
||||
|
||||
describe('Chat Message', function () {
|
||||
it('Chat message round trip binary serialization', function () {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.date({ min: new Date(0) }),
|
||||
fc.string(),
|
||||
fc.string(),
|
||||
(timestamp, nick, message) => {
|
||||
const msg = new ChatMessage(timestamp, nick, message);
|
||||
const buf = msg.encode();
|
||||
const actual = ChatMessage.decode(buf);
|
||||
|
||||
// Date.toString does not include ms, as we loose this precision by design
|
||||
expect(actual.timestamp.toString()).to.eq(timestamp.toString());
|
||||
expect(actual.nick).to.eq(nick);
|
||||
expect(actual.message).to.eq(message);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,35 @@
|
|||
import { Reader } from 'protobufjs/minimal';
|
||||
|
||||
import { ChatMessageProto } from '../proto/chat/v2/chat_message';
|
||||
|
||||
export class ChatMessage {
|
||||
public constructor(
|
||||
public timestamp: Date,
|
||||
public nick: string,
|
||||
public message: string
|
||||
) {}
|
||||
|
||||
static decode(bytes: Uint8Array): ChatMessage {
|
||||
const protoMsg = ChatMessageProto.decode(Reader.create(bytes));
|
||||
const timestamp = new Date(protoMsg.timestamp * 1000);
|
||||
const message = protoMsg.payload
|
||||
? Array.from(protoMsg.payload)
|
||||
.map((char) => {
|
||||
return String.fromCharCode(char);
|
||||
})
|
||||
.join('')
|
||||
: '';
|
||||
return new ChatMessage(timestamp, protoMsg.nick, message);
|
||||
}
|
||||
|
||||
encode(): Uint8Array {
|
||||
const timestamp = Math.floor(this.timestamp.valueOf() / 1000);
|
||||
const payload = Buffer.from(this.message, 'utf-8');
|
||||
|
||||
return ChatMessageProto.encode({
|
||||
timestamp,
|
||||
nick: this.nick,
|
||||
payload,
|
||||
}).finish();
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ import { Message } from '../lib/waku_message';
|
|||
import { TOPIC } from '../lib/waku_relay';
|
||||
import { delay } from '../test_utils/delay';
|
||||
|
||||
import { ChatMessage } from './chat_message';
|
||||
|
||||
(async function () {
|
||||
const opts = processArguments();
|
||||
|
||||
|
@ -12,8 +14,18 @@ import { delay } from '../test_utils/delay';
|
|||
|
||||
// TODO: Bubble event to waku, infer topic, decode msg
|
||||
waku.libp2p.pubsub.on(TOPIC, (event) => {
|
||||
const msg = Message.fromBinary(event.data);
|
||||
console.log(msg.utf8Payload());
|
||||
const wakuMsg = Message.decode(event.data);
|
||||
if (wakuMsg.payload) {
|
||||
const chatMsg = ChatMessage.decode(wakuMsg.payload);
|
||||
const timestamp = chatMsg.timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
hour12: false,
|
||||
});
|
||||
console.log(`<${timestamp}> ${chatMsg.nick}: ${chatMsg.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
console.log('Waku started');
|
||||
|
@ -47,7 +59,9 @@ import { delay } from '../test_utils/delay';
|
|||
rl.prompt();
|
||||
rl.on('line', async (line) => {
|
||||
rl.prompt();
|
||||
const msg = Message.fromUtf8String('(js-chat) ' + line);
|
||||
const chatMessage = new ChatMessage(new Date(), 'js-chat', line);
|
||||
|
||||
const msg = Message.fromBytes(chatMessage.encode());
|
||||
await waku.relay.publish(msg);
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -8,7 +8,7 @@ describe('Waku Message', function () {
|
|||
fc.property(fc.string(), (s) => {
|
||||
const msg = Message.fromUtf8String(s);
|
||||
const binary = msg.toBinary();
|
||||
const actual = Message.fromBinary(binary);
|
||||
const actual = Message.decode(binary);
|
||||
|
||||
return actual.isEqualTo(msg);
|
||||
})
|
||||
|
|
|
@ -15,16 +15,25 @@ export class Message {
|
|||
) {}
|
||||
|
||||
/**
|
||||
* Create Message from utf-8 string
|
||||
* @param message
|
||||
* Create Message with a utf-8 string as payload
|
||||
* @param payload
|
||||
* @returns {Message}
|
||||
*/
|
||||
static fromUtf8String(message: string): Message {
|
||||
const payload = Buffer.from(message, 'utf-8');
|
||||
static fromUtf8String(payload: string): Message {
|
||||
const buf = Buffer.from(payload, 'utf-8');
|
||||
return new Message(buf, DEFAULT_CONTENT_TOPIC, DEFAULT_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Message with a byte array as payload
|
||||
* @param payload
|
||||
* @returns {Message}
|
||||
*/
|
||||
static fromBytes(payload: Uint8Array): Message {
|
||||
return new Message(payload, DEFAULT_CONTENT_TOPIC, DEFAULT_VERSION);
|
||||
}
|
||||
|
||||
static fromBinary(bytes: Uint8Array): Message {
|
||||
static decode(bytes: Uint8Array): Message {
|
||||
const wakuMsg = WakuMessage.decode(Reader.create(bytes));
|
||||
return new Message(wakuMsg.payload, wakuMsg.contentTopic, wakuMsg.version);
|
||||
}
|
||||
|
|
|
@ -392,6 +392,6 @@ function waitForNextData(pubsub: Pubsub): Promise<Message> {
|
|||
return new Promise((resolve) => {
|
||||
pubsub.once(TOPIC, resolve);
|
||||
}).then((msg: any) => {
|
||||
return Message.fromBinary(msg.data);
|
||||
return Message.decode(msg.data);
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue