From d6c7a4a234171ee6baa19f5c5d8aaebacfa5ce2a Mon Sep 17 00:00:00 2001 From: bratanon Date: Sat, 16 Dec 2023 01:57:22 +0100 Subject: [PATCH 1/2] More clear log messages for the base unit --- CHANGELOG.md | 11 +++++++++++ src/BaseUnit.ts | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7eef0ac --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Fixed +- More clear log messages for the base unit. diff --git a/src/BaseUnit.ts b/src/BaseUnit.ts index 00cfa1e..1045369 100644 --- a/src/BaseUnit.ts +++ b/src/BaseUnit.ts @@ -369,7 +369,7 @@ export class BaseUnit { } private async handleConnectionMade() { - logger.debug('Connected successfully'); + logger.debug('Connected to LifeSOS alarm'); this.isConnected = true; // Get initial state info and find devices @@ -378,9 +378,9 @@ export class BaseUnit { private handleConnectionClose(hadError: boolean) { if (hadError) { - logger.error('Connection closed with errors.'); + logger.error('Connection closed to LifeSOS alarm with errors.'); } else { - logger.info('Connection closed.'); + logger.info('Connection closed to LifeSOS alarm'); } this.isConnected = false; From ffb3d460785f2b93d8ee50d96c539dbe213c0e4f Mon Sep 17 00:00:00 2001 From: bratanon Date: Sat, 16 Dec 2023 02:09:53 +0100 Subject: [PATCH 2/2] Client now resolves immediately if the socket already is closed. --- CHANGELOG.md | 2 ++ src/Client.ts | 16 ++++++++++++---- src/Protocol.ts | 11 +++++------ tests/Client.test.ts | 29 ++++++++++++++++++++++++----- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eef0ac..e4b0d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - More clear log messages for the base unit. +- Events should be assigned before calling the handler. +- Client `close()` now resolves immediately if the socket already is closed. diff --git a/src/Client.ts b/src/Client.ts index 3cea700..e0327ac 100644 --- a/src/Client.ts +++ b/src/Client.ts @@ -26,8 +26,6 @@ class Client extends Protocol { */ async open(): Promise { return new Promise((resolve, reject) => { - this.socket.connect({ port: this.port, host: this.host }); - this.socket.once('connect', () => { resolve(); }); @@ -35,6 +33,8 @@ class Client extends Protocol { this.socket.once('error', (err) => { reject(err); }); + + this.socket.connect({ port: this.port, host: this.host }); }); } @@ -42,12 +42,20 @@ class Client extends Protocol { * Close connection to the LifeSOS ethernet interface. */ async close(): Promise { - return new Promise((resolve) => { - this.socket.end(); + if (this.socket.closed) { + return Promise.resolve(); + } + return new Promise((resolve, reject) => { this.socket.once('close', () => { resolve(); }); + + this.socket.once('error', (error: Error) => { + reject(error); + }); + + this.socket.end(); }); } } diff --git a/src/Protocol.ts b/src/Protocol.ts index 7dcc3f0..d0756f2 100644 --- a/src/Protocol.ts +++ b/src/Protocol.ts @@ -53,7 +53,6 @@ export type State = { * Base class containing common functionality for the Client implementation. */ export abstract class Protocol { - // static ENSURE_ALIVE_SECS = 30; static EXECUTE_TIMEOUT_SECS = 8; /** @@ -111,8 +110,6 @@ export abstract class Protocol { onResponse: ((response: Response) => void) | undefined; protected constructor() { - // @TODO: Fix keep alive? - // this._socket = new Socket().setKeepAlive(true, Protocol.ENSURE_ALIVE_SECS * 1000); this.socket = new Socket(); // Handle data received @@ -386,9 +383,7 @@ export abstract class Protocol { this.executing[command.name] = state; - this._send(command, password); - - return new Promise((resolve, reject) => { + const response = new Promise((resolve, reject) => { const timer = setTimeout(() => { reject(new CommandTimeoutError(command)); }, timeout * 1000); @@ -401,6 +396,10 @@ export abstract class Protocol { logger.debug(`Deleting command: ${command.name}`); delete this.executing[command.name]; }); + + this._send(command, password); + + return response; } private _send(command: Command, password: string) { diff --git a/tests/Client.test.ts b/tests/Client.test.ts index ffce861..6c942e1 100644 --- a/tests/Client.test.ts +++ b/tests/Client.test.ts @@ -29,11 +29,30 @@ describe('Client', () => { }); }); - test('close', async () => { - client.socket.end = jest.fn(); - const closePromise = client.close(); - client.socket.emit('close'); + describe('close', () => { + test('success', async () => { + client.socket.end = jest.fn(); + const closePromise = client.close(); + client.socket.emit('close'); + + await expect(closePromise).resolves.toBeUndefined(); + }); + + test('failure', async () => { + const closePromise = client.close(); + client.socket.emit('error'); - await expect(closePromise).resolves.toBeUndefined(); + await expect(closePromise).rejects.toBeUndefined(); + }); + + test('close when socket already is closed', async () => { + client.socket.end = jest.fn(); + client.socket.destroy(); + + const closePromise = client.close(); + await expect(closePromise).resolves.toBeUndefined(); + expect(client.socket.end).not.toHaveBeenCalled(); + }); }); + });