From b0a38da78f837f5dfad1f44f0c54ae486cce49b3 Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Wed, 3 Jul 2024 16:07:52 +0200 Subject: [PATCH 1/5] fix: singleton call for websocket --- zerva-websocket/src/client.spec.ts | 11 ++++++----- zerva-websocket/src/client.ts | 5 ++++- zerva-websocket/src/index.ts | 2 -- zerva-websocket/src/server.spec.ts | 6 ++---- zerva-websocket/src/server.ts | 12 ++++++++---- zerva-websocket/src/singleton.spec.ts | 8 ++++++++ zerva-websocket/src/singleton.ts | 25 +++++++++++++++++++++++++ 7 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 zerva-websocket/src/singleton.spec.ts create mode 100644 zerva-websocket/src/singleton.ts diff --git a/zerva-websocket/src/client.spec.ts b/zerva-websocket/src/client.spec.ts index 53ddc32a..4498ebda 100644 --- a/zerva-websocket/src/client.spec.ts +++ b/zerva-websocket/src/client.spec.ts @@ -1,12 +1,9 @@ -// (C)opyright 2021-07-15 Dirk Holtwick, holtwick.it. All rights reserved. - import { on, serve, serveStop, setContext } from '@zerva/core' import { useHttp } from '@zerva/http' import WebSocket from 'ws' -import { Uint8ArrayToString, createPromise, stringToUInt8Array, waitOn } from 'zeed' +import { Uint8ArrayToString, createPromise, stringToUInt8Array, useDispose, waitOn } from 'zeed' import { WebSocketConnection } from './client' import { useWebSocket } from './server' -import { webSocketPath } from './_types' // @ts-expect-error xxx globalThis.WebSocket = WebSocket @@ -14,14 +11,17 @@ globalThis.WebSocket = WebSocket // const log = Logger("test:module") const port = 8886 +const webSocketPath = '/testClient' const url = `ws://localhost:${port}${webSocketPath}` describe('connection', () => { + const dispose = useDispose() + beforeAll(async () => { setContext() // Avoid conflict of multiple registration useHttp({ port }) - useWebSocket({}) + dispose.add(useWebSocket({ path: webSocketPath })) on('webSocketConnect', ({ channel }) => { channel.on('message', (msg) => { @@ -37,6 +37,7 @@ describe('connection', () => { afterAll(async () => { await serveStop() + await dispose() }) it('should ping', async () => { diff --git a/zerva-websocket/src/client.ts b/zerva-websocket/src/client.ts index d8cb42fc..834b664e 100644 --- a/zerva-websocket/src/client.ts +++ b/zerva-websocket/src/client.ts @@ -3,6 +3,7 @@ import type { LogConfig, LoggerInterface } from 'zeed' import { Channel, LogLevelInfo, LoggerFromConfig, createPromise, equalBinary, getTimestamp, isBrowser, useDispose, useEventListener } from 'zeed' import { pingMessage, pongMessage, webSocketPath, wsReadyStateConnecting, wsReadyStateOpen } from './_types' +import { useSingletonFlag } from './singleton' // See lib0 and y-websocket for initial implementation @@ -31,7 +32,7 @@ const PERFORM_RETRY = true export class WebSocketConnection extends Channel { public ws?: WebSocket - public url: string | URL + public url: string public shouldConnect = true public isConnected = false public lastMessageReceived = 0 @@ -57,6 +58,8 @@ export class WebSocketConnection extends Channel { this.opt = opt this.url = url ?? getWebsocketUrlFromLocation(path) + this.dispose.add(useSingletonFlag(`_zerva_websocket_client_${this.url}`, this.log)) + if (isBrowser()) { this.dispose.add(useEventListener(window, 'beforeunload', () => this.dispose())) this.dispose.add(useEventListener(window, 'focus', () => this.ping())) diff --git a/zerva-websocket/src/index.ts b/zerva-websocket/src/index.ts index ab9fed3f..f8d1fa7a 100644 --- a/zerva-websocket/src/index.ts +++ b/zerva-websocket/src/index.ts @@ -1,5 +1,3 @@ -// (C)opyright 2021-07-15 Dirk Holtwick, holtwick.it. All rights reserved. - export * from './_types' export * from './server' export * from './client' diff --git a/zerva-websocket/src/server.spec.ts b/zerva-websocket/src/server.spec.ts index cb05c8fc..35425cbf 100644 --- a/zerva-websocket/src/server.spec.ts +++ b/zerva-websocket/src/server.spec.ts @@ -1,5 +1,3 @@ -// (C)opyright 2021-07-15 Dirk Holtwick, holtwick.it. All rights reserved. - import { on, serve, serveStop, setContext } from '@zerva/core' import { useHttp } from '@zerva/http' import WebSocket from 'ws' @@ -106,7 +104,7 @@ describe('module', () => { expect(err.message).toBe('fakeError') } - channel.dispose() + await channel.dispose() }) it('should ping', async () => { @@ -117,6 +115,6 @@ describe('module', () => { await sleep(2000) // 2000 / 600 = 3.333... expect(channel.pingCount).toBe(3) - channel.dispose() + await channel.dispose() }, 5000) }) diff --git a/zerva-websocket/src/server.ts b/zerva-websocket/src/server.ts index 0efcd4ef..a247bfb0 100644 --- a/zerva-websocket/src/server.ts +++ b/zerva-websocket/src/server.ts @@ -1,5 +1,4 @@ -// (C)opyright 2021 Dirk Holtwick, holtwick.it. All rights reserved. - +import '@zerva/http' import type { Buffer } from 'node:buffer' import { URL } from 'node:url' import { assertModules, emit, on, once, register } from '@zerva/core' @@ -7,8 +6,8 @@ import type WebSocket from 'ws' import { WebSocketServer } from 'ws' import type { LogConfig, LogLevelAliasType, LoggerInterface, UseDispose } from 'zeed' import { Channel, LogLevelInfo, LoggerFromConfig, equalBinary, uname, useDispose, uuid } from 'zeed' -import { pingMessage, pongMessage, websocketName, wsReadyStateConnecting, wsReadyStateOpen } from './_types' -import '@zerva/http' +import { pingMessage, pongMessage, websocketName, wsReadyStateOpen } from './_types' +import { useSingletonFlag } from './singleton' const moduleName = 'websocket' @@ -219,6 +218,9 @@ export function useWebSocket(config: ZWebSocketConfig = {}) { path = `/${path}` config.path = path + const dispose = useDispose() + dispose.add(useSingletonFlag(`_zerva_websocket_server_${config.path}`)) + on('httpInit', ({ http }) => { log(`init path=${path}`) @@ -274,4 +276,6 @@ export function useWebSocket(config: ZWebSocketConfig = {}) { log.info('server stop done') }) }) + + return dispose } diff --git a/zerva-websocket/src/singleton.spec.ts b/zerva-websocket/src/singleton.spec.ts new file mode 100644 index 00000000..088a613f --- /dev/null +++ b/zerva-websocket/src/singleton.spec.ts @@ -0,0 +1,8 @@ +import { useSingletonFlag } from './singleton' + +describe('singleton.spec', () => { + it('should only once', async () => { + const dispose = useSingletonFlag('test') + dispose() + }) +}) diff --git a/zerva-websocket/src/singleton.ts b/zerva-websocket/src/singleton.ts new file mode 100644 index 00000000..d03012af --- /dev/null +++ b/zerva-websocket/src/singleton.ts @@ -0,0 +1,25 @@ +import type { LoggerInterface } from 'zeed' + +/** Make sure the flag is only in use once globally. */ +export function useSingletonFlag(name: string, log?: LoggerInterface) { + const _global = globalThis as any + if (_global._zerva_singleton_flags == null) + _global._zerva_singleton_flags = {} + + if (_global._zerva_singleton_flags[name] === true) { + const msg = `Singleton named '${name}' called twice!` + log?.error(msg) + throw new Error(msg) + } + + _global._zerva_singleton_flags[name] = true + + return () => { + if (_global._zerva_singleton_flags[name] !== true) { + const msg = `Singleton named '${name}' has been disposed more than once!` + log?.error(msg) + throw new Error(msg) + } + _global._zerva_singleton_flags[name] = false + } +} From 827d89adba638e4044a2702a825c57c6e7a24b0e Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Wed, 3 Jul 2024 16:08:16 +0200 Subject: [PATCH 2/5] release websocket --- zerva-websocket/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zerva-websocket/package.json b/zerva-websocket/package.json index 418d021e..fb9c37f2 100644 --- a/zerva-websocket/package.json +++ b/zerva-websocket/package.json @@ -1,7 +1,7 @@ { "name": "@zerva/websocket", "type": "module", - "version": "0.55.3", + "version": "0.55.4", "description": "🌱 Zerva websocket module", "author": { "name": "Dirk Holtwick", From 3e8d2cf86c077f5c05a67fbcdc3d62f4518fb3d1 Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Fri, 5 Jul 2024 10:01:02 +0200 Subject: [PATCH 3/5] feat: pass through DEBUG env via define --- zerva-bin/src/main.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zerva-bin/src/main.ts b/zerva-bin/src/main.ts index 87033132..bd6b9f3e 100644 --- a/zerva-bin/src/main.ts +++ b/zerva-bin/src/main.ts @@ -9,6 +9,7 @@ import type { BuildOptions, Plugin } from 'esbuild' import { context } from 'esbuild' import { yamlPlugin } from 'esbuild-plugin-yaml' import displayNotification from 'display-notification' +import { valueToBoolean } from 'zeed' import type { ZervaConf } from './config' const DEFAULT_EXCLUDE = [ @@ -247,6 +248,7 @@ const __dirname = (await import("node:path")).dirname(__filename)` 'process.env.ZERVA_DEVELOPMENT': String(!config.build), 'process.env.ZERVA_PRODUCTION': String(config.build), 'process.env.ZERVA_VERSION': `"${config.version}"`, + 'DEBUG': valueToBoolean(process.env.DEFINE, false), ...config.define, } as any, minify: config.build, From faf5d730e9e748cc32a66797edd60a3235fa3233 Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Fri, 5 Jul 2024 10:03:07 +0200 Subject: [PATCH 4/5] fix: DEBUG define --- zerva-bin/package.json | 2 +- zerva-bin/src/main.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zerva-bin/package.json b/zerva-bin/package.json index fb0475ec..23548261 100644 --- a/zerva-bin/package.json +++ b/zerva-bin/package.json @@ -1,7 +1,7 @@ { "name": "@zerva/bin", "type": "module", - "version": "0.55.3", + "version": "0.55.5", "description": "🌱 Zerva Command Line Tool", "author": { "email": "dirk.holtwick@gmail.com", diff --git a/zerva-bin/src/main.ts b/zerva-bin/src/main.ts index bd6b9f3e..cc9c07e8 100644 --- a/zerva-bin/src/main.ts +++ b/zerva-bin/src/main.ts @@ -248,7 +248,7 @@ const __dirname = (await import("node:path")).dirname(__filename)` 'process.env.ZERVA_DEVELOPMENT': String(!config.build), 'process.env.ZERVA_PRODUCTION': String(config.build), 'process.env.ZERVA_VERSION': `"${config.version}"`, - 'DEBUG': valueToBoolean(process.env.DEFINE, false), + 'DEBUG': String(valueToBoolean(process.env.DEFINE, false)), ...config.define, } as any, minify: config.build, From 7913e6e184f075bea301b3e4e5f81e5d6cf7e54d Mon Sep 17 00:00:00 2001 From: Dirk Holtwick Date: Fri, 5 Jul 2024 10:59:57 +0200 Subject: [PATCH 5/5] 0.55.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a57db91..3e691d12 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@zerva/monorepo", - "version": "0.55.4", + "version": "0.55.5", "private": true, "scripts": { "build": "pnpm -r --filter=@zerva/* build",