diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9a4467e..a70f7eb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,6 +12,9 @@ stages: - release - metadata +before_script: + - npm install -g @shipzone/npmci + # ==================== # security stage # ==================== @@ -36,6 +39,7 @@ auditProductionDependencies: - npmci command npm audit --audit-level=high --only=prod --production tags: - docker + allow_failure: true auditDevDependencies: image: registry.gitlab.com/hosttoday/ht-docker-node:npmci diff --git a/.vscode/launch.json b/.vscode/launch.json index 112db52..26e9f92 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,28 +2,10 @@ "version": "0.2.0", "configurations": [ { - "name": "current file", - "type": "node", + "command": "npm test", + "name": "Run npm test", "request": "launch", - "args": [ - "${relativeFile}" - ], - "runtimeArgs": ["-r", "@gitzone/tsrun"], - "cwd": "${workspaceRoot}", - "protocol": "inspector", - "internalConsoleOptions": "openOnSessionStart" - }, - { - "name": "test.ts", - "type": "node", - "request": "launch", - "args": [ - "test/test.ts" - ], - "runtimeArgs": ["-r", "@gitzone/tsrun"], - "cwd": "${workspaceRoot}", - "protocol": "inspector", - "internalConsoleOptions": "openOnSessionStart" + "type": "node-terminal" } ] } diff --git a/npmextra.json b/npmextra.json index 2c6a918..91e6e42 100644 --- a/npmextra.json +++ b/npmextra.json @@ -5,7 +5,7 @@ "githost": "gitlab.com", "gitscope": "pushrocks", "gitrepo": "smartsocket", - "shortDescription": "easy and secure websocket communication", + "description": "easy and secure websocket communication", "npmPackagename": "@pushrocks/smartsocket", "license": "MIT", "projectDomain": "push.rocks" diff --git a/package.json b/package.json index 99858b7..ce2b353 100644 --- a/package.json +++ b/package.json @@ -61,4 +61,4 @@ "browserslist": [ "last 1 chrome versions" ] -} +} \ No newline at end of file diff --git a/test/test.ts b/test/test.ts index 9254a0e..fc01437 100644 --- a/test/test.ts +++ b/test/test.ts @@ -105,12 +105,13 @@ tap.test('should be able to tag a connection from client', async (tools) => { tap.test('should be able to tag a connection from server', async (tools) => { await testSmartsocket.socketConnections - .findSync((socketConnection) => { - return true; - }).addTag({ - id: 'awesome2', - payload: 'absolutely', - }); + .findSync((socketConnection) => { + return true; + }) + .addTag({ + id: 'awesome2', + payload: 'absolutely', + }); const tagOnClientSide = await testSmartsocketClient.socketConnection.getTagById('awesome2'); expect(tagOnClientSide.payload).to.equal('absolutely'); }); @@ -143,10 +144,19 @@ tap.test('should be able to make a functionCall from server to client', async () tap.test('client should disconnect and reconnect', async (tools) => { await testSmartsocketClient.disconnect(); - await tools.delayFor(100); await testSmartsocketClient.connect(); }); +tap.test('should be able to locate a connection tag after reconnect', async (tools) => { + console.log(testSmartsocket.socketConnections.getArray().length); + const tagOnServerSide = await testSmartsocket.socketConnections + .findSync((socketConnection) => { + return true; + }) + .getTagById('awesome'); + expect(tagOnServerSide.payload).to.equal('yes'); +}); + // terminate tap.test('should close the server', async () => { await testSmartsocket.stop(); diff --git a/ts/smartsocket.classes.smartsocket.ts b/ts/smartsocket.classes.smartsocket.ts index 84e9efe..da93a68 100644 --- a/ts/smartsocket.classes.smartsocket.ts +++ b/ts/smartsocket.classes.smartsocket.ts @@ -61,8 +61,8 @@ export class Smartsocket { await plugins.smartdelay.delayFor(1000); this.socketConnections.forEach((socketObjectArg: SocketConnection) => { if (socketObjectArg) { - logger.log('info', `disconnect socket with >>alias ${socketObjectArg.alias}`); - socketObjectArg.socket.disconnect(true); + logger.log('info', `disconnecting socket with >>alias ${socketObjectArg.alias} due to server stop...`); + socketObjectArg.disconnect(); } }); this.socketConnections.wipe(); @@ -124,13 +124,14 @@ export class Smartsocket { }); logger.log('info', 'Socket connected. Trying to authenticate...'); this.socketConnections.add(socketConnection); - const disconnectSubscription = socketConnection.eventSubject.subscribe((eventArg) => { - if (eventArg === 'disconnected') { - this.socketConnections.remove(socketConnection); - disconnectSubscription.unsubscribe(); - } - }) + const disconnectSubscription = socketConnection.eventSubject.subscribe((eventArg) => { + if (eventArg === 'disconnected') { + this.socketConnections.remove(socketConnection); + disconnectSubscription.unsubscribe(); + } + }); await socketConnection.authenticate(); await socketConnection.listenToFunctionRequests(); + await socketConnection.socket.emit('serverFullyReactive'); } } diff --git a/ts/smartsocket.classes.smartsocketclient.ts b/ts/smartsocket.classes.smartsocketclient.ts index 31f65af..70a96ae 100644 --- a/ts/smartsocket.classes.smartsocketclient.ts +++ b/ts/smartsocket.classes.smartsocketclient.ts @@ -138,11 +138,29 @@ export class SmartsocketClient { logger.log('info', 'server requested authentication'); // lets register the authenticated event - this.socketConnection.socket.on('authenticated', () => { + this.socketConnection.socket.on('authenticated', async () => { this.remoteShortId = requestAuthPayload.serverShortId; logger.log('info', 'client is authenticated'); this.socketConnection.authenticated = true; - this.socketConnection.listenToFunctionRequests(); + await this.socketConnection.listenToFunctionRequests(); + }); + + this.socketConnection.socket.on('serverFullyReactive', async () => { + // lets take care of retagging + const oldTagStore = this.tagStore; + this.tagStoreSubscription?.unsubscribe(); + for (const keyArg of Object.keys(this.tagStore)) { + this.socketConnection.addTag(this.tagStore[keyArg]); + } + this.tagStoreSubscription = this.socketConnection.tagStoreObservable.subscribe( + (tagStoreArg) => { + this.tagStore = tagStoreArg; + } + ); + + for (const tag of Object.keys(oldTagStore)) { + await this.addTag(oldTagStore[tag]); + } done.resolve(); }); @@ -163,16 +181,6 @@ export class SmartsocketClient { // handle connection this.socketConnection.socket.on('connect', async () => { - this.tagStoreSubscription?.unsubscribe(); - for (const keyArg of Object.keys(this.tagStore)) { - this.socketConnection.addTag(this.tagStore[keyArg]); - } - this.tagStoreSubscription = this.socketConnection.tagStoreObservable.subscribe( - (tagStoreArg) => { - this.tagStore = tagStoreArg; - } - ); - this.updateStatus('connected'); }); @@ -194,6 +202,7 @@ export class SmartsocketClient { * disconnect from the server */ public async disconnect() { + this.tagStoreSubscription?.unsubscribe(); if (this.socketConnection) { await this.socketConnection.disconnect(); this.socketConnection = undefined; diff --git a/ts/smartsocket.classes.socketconnection.ts b/ts/smartsocket.classes.socketconnection.ts index eaec485..36acd91 100644 --- a/ts/smartsocket.classes.socketconnection.ts +++ b/ts/smartsocket.classes.socketconnection.ts @@ -95,6 +95,9 @@ export class SocketConnection { this.tagStore[tagArg.id] = tagArg; this.tagStoreObservable.next(this.tagStore); const remoteSubscription = this.remoteTagStoreObservable.subscribe((remoteTagStore) => { + if (!remoteTagStore[tagArg.id]) { + return; + } const localTagString = plugins.smartjson.stringify(tagArg); const remoteTagString = plugins.smartjson.stringify(remoteTagStore[tagArg.id]); if (localTagString === remoteTagString) { diff --git a/ts/smartsocket.classes.socketrole.ts b/ts/smartsocket.classes.socketrole.ts index a9edae5..de12777 100644 --- a/ts/smartsocket.classes.socketrole.ts +++ b/ts/smartsocket.classes.socketrole.ts @@ -32,8 +32,10 @@ export class SocketRole { dataArg: ISocketConnectionAuthenticationObject, referenceSmartsocket: Smartsocket | SmartsocketClient ): Promise { - const targetPasswordHash = SocketRole.getSocketRoleByName(referenceSmartsocket, dataArg.role) - .passwordHash; + const targetPasswordHash = SocketRole.getSocketRoleByName( + referenceSmartsocket, + dataArg.role + ).passwordHash; const computedCompareHash = await plugins.isohash.sha256FromString(dataArg.password); return targetPasswordHash === computedCompareHash; } diff --git a/ts/smartsocket.classes.socketserver.ts b/ts/smartsocket.classes.socketserver.ts index 81dbfb7..34ef94a 100644 --- a/ts/smartsocket.classes.socketserver.ts +++ b/ts/smartsocket.classes.socketserver.ts @@ -77,5 +77,9 @@ export class SocketServer { /** * closes the server */ - public async stop() {} + public async stop() { + if (this.httpServer) { + this.httpServer.close(); + } + } }