diff --git a/index.html b/index.html index d5a6e88..f363153 100644 --- a/index.html +++ b/index.html @@ -138,6 +138,7 @@
Message
CLI
GetStats
+
Ping
Set Path
Share (Zero Hop)
Export
@@ -501,6 +502,14 @@ } }, + async pingRepeater(contact) { + try { + const response = await this.connection.pingRepeaterZeroHop(contact.publicKey); + console.log(response); + } catch(e) { + console.log(e); + } + }, async reboot() { try { await this.connection.reboot(); diff --git a/src/connection/connection.js b/src/connection/connection.js index dbbc75e..5eb2a89 100644 --- a/src/connection/connection.js +++ b/src/connection/connection.js @@ -3,6 +3,7 @@ import BufferReader from "../buffer_reader.js"; import Constants from "../constants.js"; import EventEmitter from "../events.js"; import BufferUtils from "../buffer_utils.js"; +import Packet from "../packet.js"; class Connection extends EventEmitter { @@ -1421,6 +1422,88 @@ class Connection extends EventEmitter { }); } + pingRepeaterZeroHop(contactPublicKey, timeoutMillis) { + return new Promise(async (resolve, reject) => { + try { + + // create raw data using custom packet + const bufferWriter = new BufferWriter(); + bufferWriter.writeUInt32LE(Date.now()); // timestamp millis so every ping is unique + bufferWriter.writeBytes([0x70, 0x69, 0x6E, 0x67]); // "ping" as bytes + bufferWriter.writeBytes(contactPublicKey.subarray(0, 2)); // 2 bytes from the repeaters public key, so we don't use another repeaters ping response + const rawBytes = bufferWriter.toBytes(); + + var startMillis = Date.now(); + + // resolve promise when we receive expected response + const onLogRxDataPush = (response) => { + + // calculate round trip time + const endMillis = Date.now(); + const durationMillis = endMillis - startMillis; + + // parse packet from rx data, and make sure it's expected type + const packet = Packet.fromBytes(response.raw); + if(packet.payload_type !== Packet.PAYLOAD_TYPE_RAW_CUSTOM){ + return; + } + + // make sure the payload we sent, is the payload we received + if(!BufferUtils.areBuffersEqual(packet.payload, rawBytes)){ + return; + } + + // ping successful remove all listeners + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.PushCodes.LogRxData, onLogRxDataPush); + + // send back results + resolve({ + rtt: durationMillis, + snr: response.lastSnr, + rssi: response.lastRssi, + }); + + } + + // reject promise when we receive err + const onErr = () => { + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.PushCodes.LogRxData, onLogRxDataPush); + reject(); + } + + // listen for events + this.once(Constants.ResponseCodes.Err, onErr); + this.on(Constants.PushCodes.LogRxData, onLogRxDataPush); + + // check if a timeout was provided + if(timeoutMillis != null){ + setTimeout(() => { + + // stop listening for events + this.off(Constants.ResponseCodes.Err, onErr); + this.off(Constants.PushCodes.LogRxData, onLogRxDataPush); + + // reject since it timed out + reject("timeout"); + + }, timeoutMillis); + } + + // send raw data to repeater, for it to repeat zero hop + await this.sendCommandSendRawData([ + // we set the repeater we want to ping as the path + // it should repeat our packet, and we can listen for it + contactPublicKey.subarray(0, 1), + ], rawBytes); + + } catch(e) { + reject(e); + } + }); + } + } export default Connection;