dflockd-client 1.8.3 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import * as net from \"net\";\nimport * as tls from \"tls\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 6388;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class LockError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LockError\";\n }\n}\n\nexport class AcquireTimeoutError extends LockError {\n constructor(key: string) {\n super(`timeout acquiring '${key}'`);\n this.name = \"AcquireTimeoutError\";\n }\n}\n\nexport class AuthError extends LockError {\n constructor() {\n super(\"authentication failed\");\n this.name = \"AuthError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Low-level helpers\n// ---------------------------------------------------------------------------\n\nfunction encodeLines(...lines: string[]): Buffer {\n return Buffer.from(lines.map((l) => l + \"\\n\").join(\"\"), \"utf-8\");\n}\n\nfunction writeAll(sock: net.Socket, data: Buffer): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n sock.write(data, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Read one newline-terminated line from the socket.\n * Resolves with the line (without trailing \\r\\n).\n * Rejects if the connection closes before a full line arrives.\n */\nconst _readlineBuf = new WeakMap<net.Socket, string>();\n\nfunction readline(sock: net.Socket): Promise<string> {\n return new Promise((resolve, reject) => {\n let buf = _readlineBuf.get(sock) ?? \"\";\n\n // Check if a complete line is already buffered from a previous read.\n const existing = buf.indexOf(\"\\n\");\n if (existing !== -1) {\n const line = buf.slice(0, existing).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(existing + 1));\n resolve(line);\n return;\n }\n\n const onData = (chunk: Buffer) => {\n buf += chunk.toString(\"utf-8\");\n const idx = buf.indexOf(\"\\n\");\n if (idx !== -1) {\n cleanup();\n const line = buf.slice(0, idx).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(idx + 1));\n resolve(line);\n }\n };\n\n const onError = (err: Error) => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const cleanup = () => {\n sock.removeListener(\"data\", onData);\n sock.removeListener(\"error\", onError);\n sock.removeListener(\"close\", onClose);\n };\n\n sock.on(\"data\", onData);\n sock.on(\"error\", onError);\n sock.on(\"close\", onClose);\n });\n}\n\nasync function connect(\n host: string,\n port: number,\n tlsOptions?: tls.ConnectionOptions,\n auth?: string,\n): Promise<net.Socket> {\n const sock = await new Promise<net.Socket>((resolve, reject) => {\n if (tlsOptions) {\n const s = tls.connect({ host, port, ...tlsOptions }, () => {\n s.removeListener(\"error\", reject);\n resolve(s);\n });\n s.on(\"error\", reject);\n } else {\n const s = net.createConnection({ host, port }, () => {\n s.removeListener(\"error\", reject);\n resolve(s);\n });\n s.on(\"error\", reject);\n }\n });\n\n // Disable Nagle's algorithm for lower latency on small lock commands.\n sock.setNoDelay(true);\n\n // Prevent unhandled 'error' events from crashing the process.\n // Errors are detected through readline's close handler.\n sock.on(\"error\", () => {});\n\n if (auth != null && auth !== \"\") {\n await writeAll(sock, encodeLines(\"auth\", \"_\", auth));\n const resp = await readline(sock);\n if (resp === \"ok\") {\n return sock;\n }\n sock.destroy();\n if (resp === \"error_auth\") {\n throw new AuthError();\n }\n throw new LockError(`auth failed: '${resp}'`);\n }\n\n return sock;\n}\n\n// ---------------------------------------------------------------------------\n// CRC32 (same algorithm as Python's zlib.crc32)\n// ---------------------------------------------------------------------------\n\nconst CRC32_TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let j = 0; j < 8; j++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n CRC32_TABLE[i] = c;\n}\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n// ---------------------------------------------------------------------------\n// Sharding\n// ---------------------------------------------------------------------------\n\nexport type ShardingStrategy = (key: string, numServers: number) => number;\n\nexport function stableHashShard(key: string, numServers: number): number {\n return (crc32(Buffer.from(key, \"utf-8\")) >>> 0) % numServers;\n}\n\n// ---------------------------------------------------------------------------\n// Stats types\n// ---------------------------------------------------------------------------\n\nexport interface StatsLock {\n key: string;\n owner_conn_id: number;\n lease_expires_in_s: number;\n waiters: number;\n}\n\nexport interface StatsSemaphore {\n key: string;\n limit: number;\n holders: number;\n waiters: number;\n}\n\nexport interface StatsIdleLock {\n key: string;\n idle_s: number;\n}\n\nexport interface StatsIdleSemaphore {\n key: string;\n idle_s: number;\n}\n\nexport interface Stats {\n connections: number;\n locks: StatsLock[];\n semaphores: StatsSemaphore[];\n idle_locks: StatsIdleLock[];\n idle_semaphores: StatsIdleSemaphore[];\n}\n\n// ---------------------------------------------------------------------------\n// Protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function acquire(\n sock: net.Socket,\n key: string,\n acquireTimeoutS: number,\n leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n const arg =\n leaseTtlS == null\n ? String(acquireTimeoutS)\n : `${acquireTimeoutS} ${leaseTtlS}`;\n\n await writeAll(sock, encodeLines(\"l\", key, arg));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`acquire failed: '${resp}'`);\n }\n\n const parts = resp.split(\" \");\n const token = parts[1];\n const lease = parts.length >= 3 ? parseInt(parts[2], 10) : 30;\n return { token, lease };\n}\n\nexport async function renew(\n sock: net.Socket,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(\"n\", key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`renew failed: '${resp}'`);\n }\n\n const parts = resp.split(\" \");\n if (parts.length >= 2 && /^\\d+$/.test(parts[1])) {\n return parseInt(parts[1], 10);\n }\n throw new LockError(`renew: malformed response: '${resp}'`);\n}\n\nexport async function enqueue(\n sock: net.Socket,\n key: string,\n leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n const arg = leaseTtlS == null ? \"\" : String(leaseTtlS);\n await writeAll(sock, encodeLines(\"e\", key, arg));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const parts = resp.split(\" \");\n const token = parts[1];\n const lease = parts.length >= 3 ? parseInt(parts[2], 10) : 30;\n return { status: \"acquired\", token, lease };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`enqueue failed: '${resp}'`);\n}\n\nexport async function waitForLock(\n sock: net.Socket,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n await writeAll(sock, encodeLines(\"w\", key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`wait failed: '${resp}'`);\n }\n\n const parts = resp.split(\" \");\n const token = parts[1];\n const lease = parts.length >= 3 ? parseInt(parts[2], 10) : 30;\n return { token, lease };\n}\n\nexport async function release(\n sock: net.Socket,\n key: string,\n token: string,\n): Promise<void> {\n await writeAll(sock, encodeLines(\"r\", key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`release failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Semaphore protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function semAcquire(\n sock: net.Socket,\n key: string,\n acquireTimeoutS: number,\n limit: number,\n leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n const arg =\n leaseTtlS == null\n ? `${acquireTimeoutS} ${limit}`\n : `${acquireTimeoutS} ${limit} ${leaseTtlS}`;\n\n await writeAll(sock, encodeLines(\"sl\", key, arg));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`sem_acquire failed: '${resp}'`);\n }\n\n const parts = resp.split(\" \");\n const token = parts[1];\n const lease = parts.length >= 3 ? parseInt(parts[2], 10) : 30;\n return { token, lease };\n}\n\nexport async function semRenew(\n sock: net.Socket,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(\"sn\", key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`sem_renew failed: '${resp}'`);\n }\n\n const parts = resp.split(\" \");\n if (parts.length >= 2 && /^\\d+$/.test(parts[1])) {\n return parseInt(parts[1], 10);\n }\n throw new LockError(`sem_renew: malformed response: '${resp}'`);\n}\n\nexport async function semEnqueue(\n sock: net.Socket,\n key: string,\n limit: number,\n leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n const arg = leaseTtlS == null ? String(limit) : `${limit} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(\"se\", key, arg));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const parts = resp.split(\" \");\n const token = parts[1];\n const lease = parts.length >= 3 ? parseInt(parts[2], 10) : 30;\n return { status: \"acquired\", token, lease };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`sem_enqueue failed: '${resp}'`);\n}\n\nexport async function semWaitForLock(\n sock: net.Socket,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n await writeAll(sock, encodeLines(\"sw\", key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`sem_wait failed: '${resp}'`);\n }\n\n const parts = resp.split(\" \");\n const token = parts[1];\n const lease = parts.length >= 3 ? parseInt(parts[2], 10) : 30;\n return { token, lease };\n}\n\nexport async function semRelease(\n sock: net.Socket,\n key: string,\n token: string,\n): Promise<void> {\n await writeAll(sock, encodeLines(\"sr\", key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`sem_release failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Stats protocol function\n// ---------------------------------------------------------------------------\n\nasync function statsProto(sock: net.Socket): Promise<Stats> {\n await writeAll(sock, encodeLines(\"stats\", \"_\", \"\"));\n\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`stats failed: '${resp}'`);\n }\n\n const json = resp.slice(3);\n try {\n return JSON.parse(json) as Stats;\n } catch {\n throw new LockError(`stats: malformed JSON response: '${json}'`);\n }\n}\n\n/**\n * Query server runtime statistics.\n *\n * Opens a short-lived connection, sends the `stats` command, and returns\n * the parsed response.\n *\n * ```ts\n * const s = await stats();\n * console.log(s.connections, s.locks.length);\n * ```\n */\nexport async function stats(\n options?: { host?: string; port?: number; tls?: tls.ConnectionOptions; auth?: string },\n): Promise<Stats> {\n const host = options?.host ?? DEFAULT_HOST;\n const port = options?.port ?? DEFAULT_PORT;\n const sock = await connect(host, port, options?.tls, options?.auth);\n try {\n return await statsProto(sock);\n } finally {\n sock.destroy();\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedLock\n// ---------------------------------------------------------------------------\n\nexport interface DistributedLockOptions {\n key: string;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n}\n\nexport class DistributedLock {\n readonly key: string;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n\n constructor(opts: DistributedLockOptions) {\n this.key = opts.key;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n this.renewRatio = opts.renewRatio ?? 0.5;\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire the lock. Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\"already connected; call release() or close() first, or pass { force: true }\");\n }\n this.close();\n }\n this.closed = false;\n const [host, port] = this.pickServer();\n this.sock = await connect(host, port, this.tls, this.auth);\n try {\n const result = await acquire(\n this.sock,\n this.key,\n this.acquireTimeoutS,\n this.leaseTtlS,\n );\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /** Release the lock and close the connection. */\n async release(): Promise<void> {\n try {\n this.stopRenew();\n if (this.sock && this.token) {\n await release(this.sock, this.key, this.token);\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path, lock is already held) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\"already connected; call release() or close() first, or pass { force: true }\");\n }\n this.close();\n }\n this.closed = false;\n const [host, port] = this.pickServer();\n this.sock = await connect(host, port, this.tls, this.auth);\n try {\n const result = await enqueue(this.sock, this.key, this.leaseTtlS);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.startRenew();\n }\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until the lock is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n // Already acquired during enqueue (fast path)\n return true;\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n const result = await waitForLock(this.sock, this.key, timeout);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding the lock, then release automatically.\n *\n * ```ts\n * const lock = new DistributedLock({ key: \"my-resource\" });\n * await lock.withLock(async () => {\n * // critical section\n * });\n * ```\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n try {\n return await fn();\n } finally {\n await this.release();\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n }\n\n // -- internals --\n\n private startRenew(): void {\n const loop = async () => {\n const savedToken = this.token;\n if (!this.sock || !savedToken) return;\n const start = Date.now();\n try {\n this.lease = await renew(this.sock, this.key, savedToken, this.leaseTtlS);\n } catch {\n // Only signal lock-lost if we still own this token (close() may have cleared it)\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n this.onLockLost(this.key, savedToken);\n }\n }\n return;\n }\n const elapsed = Date.now() - start;\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedSemaphore\n// ---------------------------------------------------------------------------\n\nexport interface DistributedSemaphoreOptions {\n key: string;\n limit: number;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n}\n\nexport class DistributedSemaphore {\n readonly key: string;\n readonly limit: number;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private closed = false;\n\n constructor(opts: DistributedSemaphoreOptions) {\n this.key = opts.key;\n this.limit = opts.limit;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n this.renewRatio = opts.renewRatio ?? 0.5;\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire a semaphore slot. Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\"already connected; call release() or close() first, or pass { force: true }\");\n }\n this.close();\n }\n this.closed = false;\n const [host, port] = this.pickServer();\n this.sock = await connect(host, port, this.tls, this.auth);\n try {\n const result = await semAcquire(\n this.sock,\n this.key,\n this.acquireTimeoutS,\n this.limit,\n this.leaseTtlS,\n );\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /** Release the semaphore slot and close the connection. */\n async release(): Promise<void> {\n try {\n this.stopRenew();\n if (this.sock && this.token) {\n await semRelease(this.sock, this.key, this.token);\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path, slot granted immediately) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\"already connected; call release() or close() first, or pass { force: true }\");\n }\n this.close();\n }\n this.closed = false;\n const [host, port] = this.pickServer();\n this.sock = await connect(host, port, this.tls, this.auth);\n try {\n const result = await semEnqueue(this.sock, this.key, this.limit, this.leaseTtlS);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.startRenew();\n }\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until a semaphore slot is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n return true;\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n const result = await semWaitForLock(this.sock, this.key, timeout);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding a semaphore slot, then release automatically.\n *\n * ```ts\n * const sem = new DistributedSemaphore({ key: \"my-resource\", limit: 5 });\n * await sem.withLock(async () => {\n * // critical section (up to 5 concurrent holders)\n * });\n * ```\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n try {\n return await fn();\n } finally {\n await this.release();\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n }\n\n // -- internals --\n\n private startRenew(): void {\n const loop = async () => {\n const savedToken = this.token;\n if (!this.sock || !savedToken) return;\n const start = Date.now();\n try {\n this.lease = await semRenew(this.sock, this.key, savedToken, this.leaseTtlS);\n } catch {\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n this.onLockLost(this.key, savedToken);\n }\n }\n return;\n }\n const elapsed = Date.now() - start;\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n"],"mappings":"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","names":["connect","interval"]}
1
+ {"version":3,"sources":["../src/client.ts"],"sourcesContent":["import * as net from \"net\";\nimport * as tls from \"tls\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 6388;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class LockError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LockError\";\n }\n}\n\nexport class AcquireTimeoutError extends LockError {\n constructor(key: string) {\n super(`timeout acquiring '${key}'`);\n this.name = \"AcquireTimeoutError\";\n }\n}\n\nexport class AuthError extends LockError {\n constructor() {\n super(\"authentication failed\");\n this.name = \"AuthError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateKey(key: string): void {\n if (key === \"\") {\n throw new LockError(\"key must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(key)) {\n throw new LockError(\n \"key must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateAuth(auth: string): void {\n if (/[\\0\\n\\r]/.test(auth)) {\n throw new LockError(\n \"auth token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateToken(token: string): void {\n if (token === \"\") {\n throw new LockError(\"token must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(token)) {\n throw new LockError(\n \"token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Low-level helpers\n// ---------------------------------------------------------------------------\n\nfunction encodeLines(...lines: string[]): Buffer {\n return Buffer.from(lines.map((l) => l + \"\\n\").join(\"\"), \"utf-8\");\n}\n\nfunction writeAll(sock: net.Socket, data: Buffer): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n sock.write(data, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Parse a lease value from a server response part.\n * Returns `fallback` when the value is missing, empty, or non-numeric.\n */\nfunction parseLease(value: string | undefined, fallback: number = 30): number {\n if (value == null || value === \"\") return fallback;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/**\n * Read one newline-terminated line from the socket.\n * Resolves with the line (without trailing \\r\\n).\n * Rejects if the connection closes before a full line arrives.\n *\n * NOTE: Concurrent calls to readline() on the same socket are unsafe —\n * callers must serialize reads (the request-response protocol naturally\n * enforces this).\n */\nconst _readlineBuf = new WeakMap<net.Socket, string>();\nconst MAX_LINE_LENGTH = 1024 * 1024; // 1 MB\n\nfunction readline(sock: net.Socket): Promise<string> {\n return new Promise((resolve, reject) => {\n let buf = _readlineBuf.get(sock) ?? \"\";\n\n // Check if a complete line is already buffered from a previous read.\n const existing = buf.indexOf(\"\\n\");\n if (existing !== -1) {\n const line = buf.slice(0, existing).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(existing + 1));\n resolve(line);\n return;\n }\n\n const onData = (chunk: Buffer) => {\n buf += chunk.toString(\"utf-8\");\n const idx = buf.indexOf(\"\\n\");\n if (idx !== -1) {\n cleanup();\n const line = buf.slice(0, idx).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(idx + 1));\n resolve(line);\n } else if (buf.length > MAX_LINE_LENGTH) {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server response exceeded maximum line length\"));\n }\n };\n\n const onError = (err: Error) => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const onEnd = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const cleanup = () => {\n sock.removeListener(\"data\", onData);\n sock.removeListener(\"error\", onError);\n sock.removeListener(\"close\", onClose);\n sock.removeListener(\"end\", onEnd);\n };\n\n // If the readable side already ended (e.g. the server closed before we\n // started reading), the 'end'/'close' events won't fire again.\n if (sock.readableEnded || sock.destroyed) {\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n return;\n }\n\n sock.on(\"data\", onData);\n sock.on(\"error\", onError);\n sock.on(\"close\", onClose);\n sock.on(\"end\", onEnd);\n });\n}\n\nasync function connect(\n host: string,\n port: number,\n tlsOptions?: tls.ConnectionOptions,\n auth?: string,\n connectTimeoutMs?: number,\n): Promise<net.Socket> {\n const sock = await new Promise<net.Socket>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n // tls.connect() registers the callback on \"secureConnect\", not \"connect\".\n const connectEvent = tlsOptions ? \"secureConnect\" : \"connect\";\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(\"error\", onError);\n resolve(s);\n };\n\n const onError = (err: Error) => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(err);\n };\n\n let s: net.Socket;\n if (tlsOptions) {\n s = tls.connect({ ...tlsOptions, host, port }, onConnect);\n } else {\n s = net.createConnection({ host, port }, onConnect);\n }\n s.on(\"error\", onError);\n\n if (connectTimeoutMs != null && connectTimeoutMs > 0) {\n timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n s.removeListener(\"error\", onError);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(\n new LockError(\n `connect timed out after ${connectTimeoutMs}ms to ${host}:${port}`,\n ),\n );\n }, connectTimeoutMs);\n }\n });\n\n // Disable Nagle's algorithm for lower latency on small lock commands.\n sock.setNoDelay(true);\n\n // Prevent unhandled 'error' events from crashing the process.\n // Errors are detected through readline's close handler.\n sock.on(\"error\", () => {});\n\n if (auth != null && auth !== \"\") {\n validateAuth(auth);\n let resp: string;\n try {\n await writeAll(sock, encodeLines(\"auth\", \"_\", auth));\n resp = await readline(sock);\n } catch (err) {\n sock.destroy();\n throw err;\n }\n if (resp === \"ok\") {\n return sock;\n }\n sock.destroy();\n if (resp === \"error_auth\") {\n throw new AuthError();\n }\n throw new LockError(`auth failed: '${resp}'`);\n }\n\n return sock;\n}\n\n// ---------------------------------------------------------------------------\n// CRC32 (same algorithm as Python's zlib.crc32)\n// ---------------------------------------------------------------------------\n\nconst CRC32_TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let j = 0; j < 8; j++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n CRC32_TABLE[i] = c;\n}\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n// ---------------------------------------------------------------------------\n// Sharding\n// ---------------------------------------------------------------------------\n\nexport type ShardingStrategy = (key: string, numServers: number) => number;\n\nexport function stableHashShard(key: string, numServers: number): number {\n if (numServers <= 0) {\n throw new LockError(\"numServers must be greater than 0\");\n }\n return crc32(Buffer.from(key, \"utf-8\")) % numServers;\n}\n\n// ---------------------------------------------------------------------------\n// Stats types\n// ---------------------------------------------------------------------------\n\nexport interface StatsLock {\n key: string;\n owner_conn_id: number;\n lease_expires_in_s: number;\n waiters: number;\n}\n\nexport interface StatsSemaphore {\n key: string;\n limit: number;\n holders: number;\n waiters: number;\n}\n\nexport interface StatsIdleLock {\n key: string;\n idle_s: number;\n}\n\nexport interface StatsIdleSemaphore {\n key: string;\n idle_s: number;\n}\n\nexport interface Stats {\n connections: number;\n locks: StatsLock[];\n semaphores: StatsSemaphore[];\n idle_locks: StatsIdleLock[];\n idle_semaphores: StatsIdleSemaphore[];\n}\n\n// ---------------------------------------------------------------------------\n// Protocol helpers (shared by lock and semaphore functions)\n// ---------------------------------------------------------------------------\n\nasync function protoAcquire(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n acquireTimeoutS: number,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isFinite(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be a finite number >= 0\");\n }\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isFinite(leaseTtlS) || leaseTtlS <= 0)) {\n throw new LockError(\"leaseTtlS must be a finite number > 0\");\n }\n\n const parts: (string | number)[] = [acquireTimeoutS];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRenew(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n validateKey(key);\n validateToken(token);\n if (leaseTtlS != null && (!Number.isFinite(leaseTtlS) || leaseTtlS <= 0)) {\n throw new LockError(\"leaseTtlS must be a finite number > 0\");\n }\n\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(cmd, key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n // Bare \"ok\" — server confirmed renewal but didn't echo the lease.\n if (resp === \"ok\") return leaseTtlS ?? 30;\n return parseLease(resp.split(\" \")[1]);\n}\n\nasync function protoEnqueue(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n validateKey(key);\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isFinite(leaseTtlS) || leaseTtlS <= 0)) {\n throw new LockError(\"leaseTtlS must be a finite number > 0\");\n }\n\n const parts: (string | number)[] = [];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { status: \"acquired\", token, lease: parseLease(respParts[2]) };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`${label} failed: '${resp}'`);\n}\n\nasync function protoWait(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isFinite(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be a finite number >= 0\");\n }\n\n await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRelease(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n): Promise<void> {\n validateKey(key);\n validateToken(token);\n await writeAll(sock, encodeLines(cmd, key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lock protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function acquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"l\", \"acquire\", key, acquireTimeoutS, leaseTtlS);\n}\n\nexport async function renew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"n\", \"renew\", key, token, leaseTtlS);\n}\n\nexport async function enqueue(\n sock: net.Socket, key: string, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"e\", \"enqueue\", key, leaseTtlS);\n}\n\nexport async function waitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"w\", \"wait\", key, waitTimeoutS);\n}\n\nexport async function release(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"r\", \"release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Semaphore protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function semAcquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, limit: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"sl\", \"sem_acquire\", key, acquireTimeoutS, leaseTtlS, limit);\n}\n\nexport async function semRenew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"sn\", \"sem_renew\", key, token, leaseTtlS);\n}\n\nexport async function semEnqueue(\n sock: net.Socket, key: string, limit: number, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"se\", \"sem_enqueue\", key, leaseTtlS, limit);\n}\n\nexport async function semWaitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"sw\", \"sem_wait\", key, waitTimeoutS);\n}\n\nexport async function semRelease(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"sr\", \"sem_release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Stats protocol function\n// ---------------------------------------------------------------------------\n\nasync function statsProto(sock: net.Socket): Promise<Stats> {\n await writeAll(sock, encodeLines(\"stats\", \"_\", \"\"));\n\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`stats failed: '${resp}'`);\n }\n\n const json = resp.slice(3);\n try {\n return JSON.parse(json) as Stats;\n } catch {\n throw new LockError(`stats: malformed JSON response: '${json}'`);\n }\n}\n\n/**\n * Query server runtime statistics.\n *\n * Opens a short-lived connection, sends the `stats` command, and returns\n * the parsed response.\n *\n * ```ts\n * const s = await stats();\n * console.log(s.connections, s.locks.length);\n * ```\n */\nexport async function stats(\n options?: {\n host?: string;\n port?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n connectTimeoutMs?: number;\n },\n): Promise<Stats> {\n const host = options?.host ?? DEFAULT_HOST;\n const port = options?.port ?? DEFAULT_PORT;\n const sock = await connect(host, port, options?.tls, options?.auth, options?.connectTimeoutMs);\n try {\n return await statsProto(sock);\n } finally {\n sock.destroy();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Option interfaces\n// ---------------------------------------------------------------------------\n\ninterface BaseOptions {\n key: string;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n /** TCP connect timeout in milliseconds. Undefined means no timeout. */\n connectTimeoutMs?: number;\n /**\n * Socket idle timeout in milliseconds. If no data is received within this\n * period, the socket emits a 'timeout' event and is destroyed, causing any\n * pending `readline` to reject. Undefined means no timeout.\n */\n socketTimeoutMs?: number;\n}\n\nexport interface DistributedLockOptions extends BaseOptions {}\n\nexport interface DistributedSemaphoreOptions extends BaseOptions {\n limit: number;\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class\n// ---------------------------------------------------------------------------\n\nabstract class DistributedPrimitive {\n readonly key: string;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n readonly connectTimeoutMs: number | undefined;\n readonly socketTimeoutMs: number | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private renewInFlight: Promise<void> | null = null;\n private closed = false;\n\n constructor(opts: BaseOptions) {\n validateKey(opts.key);\n this.key = opts.key;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n this.connectTimeoutMs = opts.connectTimeoutMs;\n this.socketTimeoutMs = opts.socketTimeoutMs;\n\n if (!Number.isFinite(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be a finite number >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isFinite(this.leaseTtlS) || this.leaseTtlS <= 0)) {\n throw new LockError(\"leaseTtlS must be a finite number > 0\");\n }\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n\n const renewRatio = opts.renewRatio ?? 0.5;\n if (!Number.isFinite(renewRatio) || renewRatio <= 0 || renewRatio >= 1) {\n throw new LockError(\"renewRatio must be a finite number between 0 and 1 (exclusive)\");\n }\n this.renewRatio = renewRatio;\n }\n\n // -- abstract protocol hooks (implemented by subclasses) --\n\n protected abstract doAcquire(\n sock: net.Socket,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doEnqueue(\n sock: net.Socket,\n ): Promise<{\n status: \"acquired\" | \"queued\";\n token: string | null;\n lease: number | null;\n }>;\n\n protected abstract doWait(\n sock: net.Socket,\n timeoutS: number,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doRelease(\n sock: net.Socket,\n token: string,\n ): Promise<void>;\n\n protected abstract doRenew(\n sock: net.Socket,\n token: string,\n ): Promise<number>;\n\n // -- public API --\n\n private async openConnection(): Promise<net.Socket> {\n const [host, port] = this.pickServer();\n const sock = await connect(host, port, this.tls, this.auth, this.connectTimeoutMs);\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n // Register the listener once; use setTimeout(ms)/setTimeout(0) to\n // toggle without accumulating duplicate listeners.\n sock.on(\"timeout\", () => {\n sock.destroy(new LockError(\"socket idle timeout\"));\n });\n sock.setTimeout(this.socketTimeoutMs);\n }\n return sock;\n }\n\n /**\n * Suspend or restore the socket idle timeout. Only has effect when\n * `socketTimeoutMs` was set at construction time and a listener was\n * registered in `openConnection`.\n */\n private suspendSocketTimeout(sock: net.Socket): void {\n sock.setTimeout(0);\n }\n\n private restoreSocketTimeout(sock: net.Socket): void {\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n sock.setTimeout(this.socketTimeoutMs);\n }\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire the lock / semaphore slot.\n * Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection\n * before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n this.sock = await this.openConnection();\n try {\n // Suspend socket idle timeout during the blocking acquire — the server\n // won't send data until the lock is granted or the acquire times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doAcquire(this.sock);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Release the lock / semaphore slot and close the connection.\n *\n * Throws `LockError` if the instance is already closed (e.g. after a\n * previous `release()` or `close()` call).\n *\n * The server-side release itself is best-effort: if the underlying\n * connection is already dead the protocol-level release error is silently\n * ignored so that the method doesn't throw on transient network failures.\n */\n async release(): Promise<void> {\n if (this.closed) {\n throw new LockError(\"not connected; nothing to release\");\n }\n // Capture the token and socket before awaiting anything — a concurrent\n // renew failure can set this.token/this.sock to null (via onLockLost →\n // close()), which would cause us to skip the server-side release and\n // leave the lock held until lease expiry.\n const tokenToRelease = this.token;\n const sockToRelease = this.sock;\n try {\n this.stopRenew();\n // Wait for any in-flight renew to finish before sending the release\n // command — concurrent reads/writes on the same socket are unsafe.\n // Bound the wait to 5s so release() doesn't hang forever when the\n // network is unresponsive and no socketTimeoutMs is configured.\n if (this.renewInFlight) {\n await Promise.race([\n this.renewInFlight,\n new Promise<void>((r) => setTimeout(r, 5000)),\n ]);\n // The loop resumes before us (it registered its .then first) and may\n // have scheduled a new timer. Clear it so it cannot fire during\n // doRelease below.\n this.stopRenew();\n }\n if (sockToRelease != null && tokenToRelease != null) {\n try {\n await this.doRelease(sockToRelease, tokenToRelease);\n } catch {\n // Best-effort: connection may already be dead.\n }\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection\n * before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n this.sock = await this.openConnection();\n try {\n this.suspendSocketTimeout(this.sock);\n const result = await this.doEnqueue(this.sock);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.startRenew();\n }\n this.restoreSocketTimeout(this.sock);\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until the lock / slot is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n // Already acquired during enqueue (fast path)\n return true;\n }\n if (this.closed) {\n throw new LockError(\"connection closed; call enqueue() again\");\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n // Suspend socket idle timeout during the blocking wait — the server\n // won't send data until the lock/slot is granted or the wait times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doWait(this.sock, timeout);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding the lock / slot, then release automatically.\n *\n * If `fn()` throws, its error is always preserved — a concurrent\n * release failure will not mask it.\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n let threw = false;\n try {\n return await fn();\n } catch (err) {\n threw = true;\n throw err;\n } finally {\n try {\n await this.release();\n } catch (releaseErr) {\n // If fn() already threw, swallow the release error so it\n // doesn't mask the original error.\n if (!threw) throw releaseErr;\n }\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n this.renewInFlight = null;\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n this.lease = 0;\n }\n\n // -- internals --\n\n private startRenew(): void {\n this.stopRenew();\n const loop = async () => {\n const savedToken = this.token;\n const sock = this.sock;\n if (!sock || !savedToken) return;\n const start = Date.now();\n const p = (async () => {\n try {\n const newLease = await this.doRenew(sock, savedToken);\n // Guard: if close() ran while the renew was in-flight, don't\n // clobber the reset state (lease=0, token=null).\n if (this.token === savedToken && !this.closed) {\n this.lease = newLease;\n }\n } catch {\n // Only signal lock-lost if we still own this token (close() may have cleared it)\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n try {\n // Cast to unknown: the declared return type is void, but an\n // async callback will return a Promise at runtime.\n const result: unknown = this.onLockLost(this.key, savedToken);\n // Guard against async callbacks returning a rejected Promise.\n if (result instanceof Promise) {\n result.catch(() => {});\n }\n } catch {\n // Never let a user callback crash the process.\n }\n }\n // Tear down the connection so the instance is in a clean state\n // for re-acquisition. Without this the socket leaks and a\n // subsequent acquire() without { force: true } would throw\n // \"already connected\".\n this.close();\n }\n return;\n }\n })();\n this.renewInFlight = p;\n await p;\n this.renewInFlight = null;\n // Guard: if close() was called while the renew was in-flight, don't\n // schedule another iteration (avoids clobbering a new acquire's timer).\n if (this.closed || this.token !== savedToken) return;\n const elapsed = Date.now() - start;\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedLock\n// ---------------------------------------------------------------------------\n\nexport class DistributedLock extends DistributedPrimitive {\n constructor(opts: DistributedLockOptions) {\n super(opts);\n }\n\n protected doAcquire(sock: net.Socket) {\n return acquire(sock, this.key, this.acquireTimeoutS, this.leaseTtlS);\n }\n\n protected doEnqueue(sock: net.Socket) {\n return enqueue(sock, this.key, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return waitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return release(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return renew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedSemaphore\n// ---------------------------------------------------------------------------\n\nexport class DistributedSemaphore extends DistributedPrimitive {\n readonly limit: number;\n\n constructor(opts: DistributedSemaphoreOptions) {\n super(opts);\n if (!Number.isInteger(opts.limit) || opts.limit < 1) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n this.limit = opts.limit;\n }\n\n protected doAcquire(sock: net.Socket) {\n return semAcquire(\n sock,\n this.key,\n this.acquireTimeoutS,\n this.limit,\n this.leaseTtlS,\n );\n }\n\n protected doEnqueue(sock: net.Socket) {\n return semEnqueue(sock, this.key, this.limit, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return semWaitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return semRelease(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return semRenew(sock, this.key, token, this.leaseTtlS);\n }\n}\n"],"mappings":"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","names":["connect","interval"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dflockd-client",
3
- "version": "1.8.3",
3
+ "version": "1.9.1",
4
4
  "description": "TypeScript client for the dflockd distributed lock daemon",
5
5
  "type": "module",
6
6
  "exports": {