mirror of
https://github.com/meshcore-dev/meshcore.js.git
synced 2026-04-20 22:13:49 +00:00
Add websocket connection support, add v3 protocol support, fix syncMessage console error
This commit is contained in:
parent
f6fea65063
commit
a4ccd3692a
5 changed files with 136 additions and 12 deletions
|
|
@ -11,6 +11,7 @@ It can also be used in NodeJS to connect to MeshCore Companion devices over TCP/
|
|||
- Web Browser
|
||||
- BLE: [WebBleConnection()](./src/connection/web_ble_connection.js)
|
||||
- USB/Serial: [WebSerialConnection()](./src/connection/web_serial_connection.js)
|
||||
- WebSocket: [WebSocketConnection()](./src/connection/websocket_connection.js)
|
||||
- NodeJS
|
||||
- TCP/WiFi: [TCPConnection("host", "port")](./src/connection/tcp_connection.js)
|
||||
- USB/Serial: [NodeJSSerialConnection("/dev/ttyUSB0")](./src/connection/nodejs_serial_connection.js)
|
||||
|
|
|
|||
11
index.html
11
index.html
|
|
@ -38,6 +38,9 @@
|
|||
<button v-if="!connection" @click="askForBleDevice" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
Connect (BLE)
|
||||
</button>
|
||||
<button v-if="!connection" @click="askForWebSocketDevice" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
Connect (WebSocket)
|
||||
</button>
|
||||
<button v-if="connection" @click="disconnect" class="border border-gray-500 px-2 bg-gray-100 hover:bg-gray-200 rounded">
|
||||
Disconnect
|
||||
</button>
|
||||
|
|
@ -198,6 +201,7 @@
|
|||
import Constants from "./src/constants.js";
|
||||
import WebSerialConnection from "./src/connection/web_serial_connection.js";
|
||||
import WebBleConnection from "./src/connection/web_ble_connection.js";
|
||||
import WebSocketConnection from "./src/connection/websocket_connection.js";
|
||||
import BufferUtils from "./src/buffer_utils.js";
|
||||
Vue.createApp({
|
||||
data() {
|
||||
|
|
@ -228,6 +232,11 @@
|
|||
// this.connection.on("tx", (data) => console.log("tx", data));
|
||||
// this.connection.on("rx", (data) => console.log("rx", data));
|
||||
},
|
||||
async askForWebSocketDevice() {
|
||||
this.connection = await WebSocketConnection.open();
|
||||
this.connection.on("connected", () => this.onConnected());
|
||||
this.connection.on("disconnected", () => this.onDisconnected());
|
||||
},
|
||||
async disconnect() {
|
||||
if(this.connection){
|
||||
await this.connection.close();
|
||||
|
|
@ -390,7 +399,7 @@
|
|||
console.log("syncNextMessage", message);
|
||||
|
||||
// check if contact message
|
||||
if(message.contactMessage){
|
||||
if(message!= null && message.contactMessage){
|
||||
|
||||
// check if from cli contact
|
||||
if(this.cliContact && BufferUtils.areBuffersEqual(message.contactMessage.pubKeyPrefix, this.cliContact.publicKey.subarray(0, 6))){
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class Connection extends EventEmitter {
|
|||
data.writeByte(Constants.CommandCodes.AppStart);
|
||||
data.writeByte(1); // appVer
|
||||
data.writeBytes(new Uint8Array(6)); // reserved
|
||||
data.writeString("test"); // appName
|
||||
data.writeString("test client"); // appName
|
||||
await this.sendToRadioFrame(data.toBytes());
|
||||
}
|
||||
|
||||
|
|
@ -334,6 +334,10 @@ class Connection extends EventEmitter {
|
|||
this.onContactMsgRecvResponse(bufferReader);
|
||||
} else if(responseCode === Constants.ResponseCodes.ChannelMsgRecv){
|
||||
this.onChannelMsgRecvResponse(bufferReader);
|
||||
} else if(responseCode === Constants.ResponseCodes.ContactMsgRecv3){
|
||||
this.onContactMsgRecvResponse(bufferReader);
|
||||
} else if(responseCode === Constants.ResponseCodes.ChannelMsgRecv3){
|
||||
this.onChannelMsgRecvResponse(bufferReader);
|
||||
} else if(responseCode === Constants.ResponseCodes.ContactsStart){
|
||||
this.onContactsStartResponse(bufferReader);
|
||||
} else if(responseCode === Constants.ResponseCodes.Contact){
|
||||
|
|
@ -635,23 +639,50 @@ class Connection extends EventEmitter {
|
|||
}
|
||||
|
||||
onContactMsgRecvResponse(bufferReader) {
|
||||
this.emit(Constants.ResponseCodes.ContactMsgRecv, {
|
||||
|
||||
if (Constants.SupportedCompanionProtocolVersion >= 3) {
|
||||
this.emit(Constants.ResponseCodes.ContactMsgRecv3, {
|
||||
snr: bufferReader.readByte() / 4.0,
|
||||
reserved1: bufferReader.readByte(),
|
||||
reserved2: bufferReader.readByte(),
|
||||
pubKeyPrefix: bufferReader.readBytes(6),
|
||||
pathLen: bufferReader.readByte(),
|
||||
txtType: bufferReader.readByte(),
|
||||
senderTimestamp: bufferReader.readUInt32LE(),
|
||||
text: bufferReader.readString(),
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
} else {
|
||||
this.emit(Constants.ResponseCodes.ContactMsgRecv, {
|
||||
pubKeyPrefix: bufferReader.readBytes(6),
|
||||
pathLen: bufferReader.readByte(),
|
||||
txtType: bufferReader.readByte(),
|
||||
senderTimestamp: bufferReader.readUInt32LE(),
|
||||
text: bufferReader.readString(),
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onChannelMsgRecvResponse(bufferReader) {
|
||||
if (Constants.SupportedCompanionProtocolVersion >= 3) {
|
||||
this.emit(Constants.ResponseCodes.ChannelMsgRecv3, {
|
||||
snr: bufferReader.readByte() / 4.0,
|
||||
reserved1: bufferReader.readByte(),
|
||||
reserved2: bufferReader.readByte(),
|
||||
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(),
|
||||
});
|
||||
} else {
|
||||
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(timeoutMillis = null) {
|
||||
|
|
@ -963,6 +994,8 @@ class Connection extends EventEmitter {
|
|||
const onContactMessageReceived = (message) => {
|
||||
this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
|
||||
this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
|
||||
resolve({
|
||||
contactMessage: message,
|
||||
|
|
@ -973,6 +1006,8 @@ class Connection extends EventEmitter {
|
|||
const onChannelMessageReceived = (message) => {
|
||||
this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
|
||||
this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
|
||||
resolve({
|
||||
channelMessage: message,
|
||||
|
|
@ -983,6 +1018,8 @@ class Connection extends EventEmitter {
|
|||
const onNoMoreMessagesReceived = () => {
|
||||
this.off(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
|
||||
this.off(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
|
||||
this.off(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
|
||||
resolve(null);
|
||||
}
|
||||
|
|
@ -990,6 +1027,8 @@ class Connection extends EventEmitter {
|
|||
// listen for events
|
||||
this.once(Constants.ResponseCodes.ContactMsgRecv, onContactMessageReceived);
|
||||
this.once(Constants.ResponseCodes.ChannelMsgRecv, onChannelMessageReceived);
|
||||
this.once(Constants.ResponseCodes.ContactMsgRecv3, onContactMessageReceived);
|
||||
this.once(Constants.ResponseCodes.ChannelMsgRecv3, onChannelMessageReceived);
|
||||
this.once(Constants.ResponseCodes.NoMoreMessages, onNoMoreMessagesReceived);
|
||||
|
||||
// sync next message from device
|
||||
|
|
|
|||
73
src/connection/websocket_connection.js
Normal file
73
src/connection/websocket_connection.js
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import Connection from "./connection.js";
|
||||
|
||||
// Easy way to test this is to run `websocat -s 5000`
|
||||
|
||||
class WebSocketConnection extends Connection {
|
||||
|
||||
constructor(url) {
|
||||
super();
|
||||
|
||||
let self = this
|
||||
this.isClosing = false
|
||||
|
||||
let socket = new WebSocket(url)
|
||||
socket.onopen = (event) => {
|
||||
//console.log("connected")
|
||||
this.onConnected();
|
||||
}
|
||||
socket.onerror = function(error) {
|
||||
//console.log(error);
|
||||
self.isClosing = true
|
||||
self.onDisconnected();
|
||||
}
|
||||
socket.onmessage = async function(event) {
|
||||
//console.log('got message', event.data)
|
||||
let buf = await event.data.arrayBuffer();
|
||||
self.onFrameReceived(buf);
|
||||
}
|
||||
socket.onclose = function() {
|
||||
if (!self.isClosing) {
|
||||
self.onDisconnected();
|
||||
}
|
||||
}
|
||||
this.socket = socket
|
||||
}
|
||||
|
||||
static async open() {
|
||||
|
||||
// ensure browser supports web bluetooth
|
||||
let url = prompt("Enter WebSocket URL", "ws://127.0.0.1:5000")
|
||||
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
||||
} else {
|
||||
url = "ws://" + url
|
||||
}
|
||||
|
||||
return new WebSocketConnection(url);
|
||||
}
|
||||
|
||||
async close() {
|
||||
try {
|
||||
this.isClosing = true
|
||||
this.socket.close()
|
||||
} catch(e) {
|
||||
//console.log("close error", e)
|
||||
// ignore error when disconnecting
|
||||
}
|
||||
}
|
||||
|
||||
async write(bytes) {
|
||||
try {
|
||||
this.socket.send(bytes)
|
||||
} catch(e) {
|
||||
console.log("failed to write to ble device", e);
|
||||
}
|
||||
}
|
||||
|
||||
async sendToRadioFrame(frame) {
|
||||
this.emit("tx", frame);
|
||||
await this.write(frame);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default WebSocketConnection;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
class Constants {
|
||||
|
||||
static SupportedCompanionProtocolVersion = 1;
|
||||
static SupportedCompanionProtocolVersion = 3;
|
||||
|
||||
static SerialFrameTypes = {
|
||||
Incoming: 0x3e, // ">"
|
||||
|
|
@ -71,6 +71,8 @@ class Constants {
|
|||
DeviceInfo: 13,
|
||||
PrivateKey: 14,
|
||||
Disabled: 15,
|
||||
ContactMsgRecv3: 16,
|
||||
ChannelMsgRecv3: 17,
|
||||
ChannelInfo: 18,
|
||||
SignStart: 19,
|
||||
Signature: 20,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue