diff --git a/packages/core/src/meshDevice.ts b/packages/core/src/meshDevice.ts index 2504719d..41ada369 100755 --- a/packages/core/src/meshDevice.ts +++ b/packages/core/src/meshDevice.ts @@ -818,6 +818,7 @@ export class MeshDevice { this.complete(); await this.transport.toDevice.close(); + await this.transport.disconnect(); } /** diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 1130824d..5a487415 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -15,6 +15,7 @@ export type DeviceOutput = Packet | DebugLog; export interface Transport { toDevice: WritableStream; fromDevice: ReadableStream; + disconnect(): Promise; } export interface QueueItem { diff --git a/packages/transport-deno/src/transport.ts b/packages/transport-deno/src/transport.ts index f65e6bd0..d5e41aa6 100644 --- a/packages/transport-deno/src/transport.ts +++ b/packages/transport-deno/src/transport.ts @@ -4,6 +4,7 @@ import { Utils } from "@meshtastic/core"; export class TransportDeno implements Types.Transport { private _toDevice: WritableStream; private _fromDevice: ReadableStream; + private connection: Deno.Conn | undefined; public static async create(hostname: string): Promise { const connection = await Deno.connect({ @@ -14,10 +15,11 @@ export class TransportDeno implements Types.Transport { } constructor(connection: Deno.Conn) { - Utils.toDeviceStream.readable.pipeTo(connection.writable); + this.connection = connection; + Utils.toDeviceStream.readable.pipeTo(this.connection.writable); this._toDevice = Utils.toDeviceStream.writable; - this._fromDevice = connection.readable.pipeThrough( + this._fromDevice = this.connection.readable.pipeThrough( Utils.fromDeviceStream(), ); } @@ -29,4 +31,10 @@ export class TransportDeno implements Types.Transport { get fromDevice(): ReadableStream { return this._fromDevice; } + + disconnect(): Promise { + this.connection.close(); + this.connection = undefined; + return Promise.resolve(); + } } diff --git a/packages/transport-http/src/transport.ts b/packages/transport-http/src/transport.ts index 5616c1b4..bf5ee17d 100644 --- a/packages/transport-http/src/transport.ts +++ b/packages/transport-http/src/transport.ts @@ -6,6 +6,8 @@ export class TransportHTTP implements Types.Transport { private url: string; private receiveBatchRequests: boolean; private fetchInterval: number; + private fetching: boolean; + private interval: number | undefined; public static async create( address: string, @@ -23,6 +25,7 @@ export class TransportHTTP implements Types.Transport { this.url = url; this.receiveBatchRequests = false; this.fetchInterval = 3000; + this.fetching = false; this._toDevice = new WritableStream({ write: async (chunk) => { @@ -38,8 +41,18 @@ export class TransportHTTP implements Types.Transport { }, }); - setInterval(async () => { - await this.readFromRadio(controller); + this.interval = setInterval(async () => { + if (this.fetching) { + // We still have the previous request open + return; + } + this.fetching = true; + try { + await this.readFromRadio(controller); + } catch (e) { + // TODO: Emit disconnection events for certain types of errors + } + this.fetching = false; }, this.fetchInterval); } @@ -88,4 +101,13 @@ export class TransportHTTP implements Types.Transport { get fromDevice(): ReadableStream { return this._fromDevice; } + + disconnect() : Promise { + this.fetching = false; + if (this.interval) { + clearInterval(this.interval); + } + this.interval = undefined; + return Promise.resolve(); + } } diff --git a/packages/transport-node/src/transport.ts b/packages/transport-node/src/transport.ts index 664e8aff..1a98828d 100644 --- a/packages/transport-node/src/transport.ts +++ b/packages/transport-node/src/transport.ts @@ -6,6 +6,7 @@ import { Utils } from "@meshtastic/core"; export class TransportNode implements Types.Transport { private readonly _toDevice: WritableStream; private readonly _fromDevice: ReadableStream; + private socket: Socket | undefined; /** * Creates and connects a new TransportNode instance. @@ -36,7 +37,8 @@ export class TransportNode implements Types.Transport { * @param connection - An active Node.js net.Socket connection. */ constructor(connection: Socket) { - connection.on("error", (err) => { + this.socket = connection; + this.socket.on("error", (err) => { console.error("Socket connection error:", err); }); @@ -56,7 +58,7 @@ export class TransportNode implements Types.Transport { .pipeTo(Writable.toWeb(connection) as WritableStream) .catch((err) => { console.error("Error piping data to socket:", err); - connection.destroy(err as Error); + this.socket.destroy(err as Error); }); } @@ -73,4 +75,10 @@ export class TransportNode implements Types.Transport { public get fromDevice(): ReadableStream { return this._fromDevice; } + + disconnect() { + this.socket.destroy(); + this.socket = undefined; + return Promise.resolve(); + } } diff --git a/packages/transport-web-bluetooth/src/transport.ts b/packages/transport-web-bluetooth/src/transport.ts index 91ceec53..d09abe47 100644 --- a/packages/transport-web-bluetooth/src/transport.ts +++ b/packages/transport-web-bluetooth/src/transport.ts @@ -9,6 +9,7 @@ export class TransportWebBluetooth implements Types.Transport { private toRadioCharacteristic: BluetoothRemoteGATTCharacteristic; private fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic; private fromNumCharacteristic: BluetoothRemoteGATTCharacteristic; + private gattServer: BluetoothRemoteGATTServer; static ToRadioUuid = "f75c76d2-129e-4dad-a1dd-7866124401e7"; static FromRadioUuid = "2c55e69e-4993-11ed-b878-0242ac120002"; @@ -65,6 +66,7 @@ export class TransportWebBluetooth implements Types.Transport { toRadioCharacteristic, fromRadioCharacteristic, fromNumCharacteristic, + gattServer, ); } @@ -72,10 +74,12 @@ export class TransportWebBluetooth implements Types.Transport { toRadioCharacteristic: BluetoothRemoteGATTCharacteristic, fromRadioCharacteristic: BluetoothRemoteGATTCharacteristic, fromNumCharacteristic: BluetoothRemoteGATTCharacteristic, + gattServer: BluetoothRemoteGATTServer, ) { this.toRadioCharacteristic = toRadioCharacteristic; this.fromRadioCharacteristic = fromRadioCharacteristic; this.fromNumCharacteristic = fromNumCharacteristic; + this.gattServer = gattServer; this._fromDevice = new ReadableStream({ start: (ctrl) => { @@ -133,4 +137,9 @@ export class TransportWebBluetooth implements Types.Transport { }); } } + + disconnect() : Promise { + this.gattServer.disconnect(); + return Promise.resolve(); + } } diff --git a/packages/transport-web-serial/src/transport.ts b/packages/transport-web-serial/src/transport.ts index 4a931709..47d98586 100644 --- a/packages/transport-web-serial/src/transport.ts +++ b/packages/transport-web-serial/src/transport.ts @@ -4,6 +4,7 @@ import { Utils } from "@meshtastic/core"; export class TransportWebSerial implements Types.Transport { private _toDevice: WritableStream; private _fromDevice: ReadableStream; + private connection: SerialPort; public static async create(baudRate?: number): Promise { const port = await navigator.serial.requestPort(); @@ -24,6 +25,8 @@ export class TransportWebSerial implements Types.Transport { throw new Error("Stream not accessible"); } + this.connection = connection; + Utils.toDeviceStream.readable.pipeTo(connection.writable); this._toDevice = Utils.toDeviceStream.writable; @@ -39,4 +42,8 @@ export class TransportWebSerial implements Types.Transport { get fromDevice(): ReadableStream { return this._fromDevice; } + + disconnect() { + return this.connection.close(); + } }