From 37b13d4193bcbd1cbf39a9289cab891d55fb755d Mon Sep 17 00:00:00 2001 From: liamcottle Date: Thu, 13 Feb 2025 22:54:18 +1300 Subject: [PATCH] add ability to send and receive channel messages --- index.html | 17 ++++++++- src/connection/connection.js | 72 +++++++++++++++++++++++++++++++++++- src/constants.js | 6 +-- 3 files changed, 89 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 16c6e93..de5e6c1 100644 --- a/index.html +++ b/index.html @@ -89,6 +89,9 @@ + @@ -284,7 +287,8 @@ await this.connection.sendCommandAddUpdateContact(publicKey, type, flags, outPathLen, outPath, advName, lastAdvert, advLat, advLon); }, async sendCommandSyncNextMessage() { - await this.connection.sendCommandSyncNextMessage(); + const message = await this.connection.syncNextMessage(); + console.log("syncNextMessage", message); }, async sendMessage(contact) { @@ -298,6 +302,17 @@ const response = await this.connection.sendTextMessage(contact.publicKey, message); console.log(response); + }, + async sendChannelTextMessage() { + + // ask user for message + const message = prompt("Enter message to send"); + if(!message){ + return; + } + + await this.connection.sendChannelTextMessage(0, message); + }, async resetPath(contact) { diff --git a/src/connection/connection.js b/src/connection/connection.js index 58e1a45..350d06a 100644 --- a/src/connection/connection.js +++ b/src/connection/connection.js @@ -41,6 +41,16 @@ class Connection extends EventEmitter { await this.sendToRadioFrame(data.toBytes()); } + async sendCommandSendChannelTxtMsg(txtType, channelIdx, senderTimestamp, text) { + const data = new BufferWriter(); + data.writeByte(Constants.CommandCodes.SendChannelTxtMsg); + data.writeByte(txtType); + data.writeByte(channelIdx); + data.writeUInt32LE(senderTimestamp); + data.writeString(text); + await this.sendToRadioFrame(data.toBytes()); + } + async sendCommandGetContacts(since) { const data = new BufferWriter(); data.writeByte(Constants.CommandCodes.GetContacts); @@ -153,6 +163,8 @@ class Connection extends EventEmitter { this.onNoMoreMessagesResponse(bufferReader); } else if(responseCode === Constants.ResponseCodes.ContactMsgRecv){ this.onContactMsgRecvResponse(bufferReader); + } else if(responseCode === Constants.ResponseCodes.ChannelMsgRecv){ + this.onChannelMsgRecvResponse(bufferReader); } else if(responseCode === Constants.ResponseCodes.ContactsStart){ this.onContactsStartResponse(bufferReader); } else if(responseCode === Constants.ResponseCodes.Contact){ @@ -274,6 +286,16 @@ class Connection extends EventEmitter { }); } + onChannelMsgRecvResponse(bufferReader) { + this.emit(Constants.ResponseCodes.ChannelMsgRecv, { + channelIdx: bufferReader.readInt8(), // reserved (0 for now, ie. 'public') + pathLen: bufferReader.readByte(), // 0xFF if was sent direct, otherwise hop count for flood-mode + txtType: bufferReader.readByte(), + senderTimestamp: bufferReader.readUInt32LE(), + text: bufferReader.readString(), + }); + } + getSelfInfo() { return new Promise(async (resolve, reject) => { @@ -343,25 +365,71 @@ class Connection extends EventEmitter { }); } + sendChannelTextMessage(channelIdx, text) { + return new Promise(async (resolve, reject) => { + try { + + // resolve promise when we receive ok + const onOk = () => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); + resolve(); + } + + // reject promise when we receive err + const onErr = () => { + this.off(Constants.ResponseCodes.Ok, onOk); + this.off(Constants.ResponseCodes.Err, onErr); + reject(); + } + + // compose message + const txtType = Constants.TxtTypes.Plain; + const senderTimestamp = Math.floor(Date.now() / 1000); + + // send message + await this.sendCommandSendChannelTxtMsg(txtType, channelIdx, senderTimestamp, text); + + } catch(e) { + reject(e); + } + }); + } + syncNextMessage() { return new Promise(async (resolve, reject) => { - // resolve promise when we receive the message + // resolve promise when we receive a contact message const onContactMessageReceived = (message) => { this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived); + this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived); this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived); - resolve(message); + resolve({ + contactMessage: message, + }); + } + + // resolve promise when we receive a channel message + const onChannelMessageReceived = (message) => { + this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived); + this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived); + this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived); + resolve({ + channelMessage: message, + }); } // resolve promise when we have no more messages to receive const onNoMoreMessagesReceived = () => { this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived); + this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived); this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived); resolve(null); } // listen for events this.once(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived); + this.once(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived); this.once(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived); // sync next message from device diff --git a/src/constants.js b/src/constants.js index 0a3c5c0..304160b 100644 --- a/src/constants.js +++ b/src/constants.js @@ -14,7 +14,7 @@ class Constants { static CommandCodes = { AppStart: 1, SendTxtMsg: 2, - SendChannelTxtMsg: 3, // todo + SendChannelTxtMsg: 3, GetContacts: 4, GetDeviceTime: 5, SetDeviceTime: 6, @@ -38,14 +38,14 @@ class Constants { SelfInfo: 5, Sent: 6, ContactMsgRecv: 7, - ChannelMsgRecv: 8, // todo + ChannelMsgRecv: 8, CurrTime: 9, NoMoreMessages: 10, } static PushCodes = { Advert: 0x80, - PathUpdated: 0x81, // todo + PathUpdated: 0x81, SendConfirmed: 0x82, MsgWaiting: 0x83, }