dflockd-client 1.9.1 → 1.9.2
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.
- package/README.md +5 -5
- package/dist/client.cjs +16 -16
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +16 -16
- package/dist/client.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,8 +103,8 @@ without blocking. If the lock is contended, `enqueue()` returns `"queued"` and
|
|
|
103
103
|
| Option | Type | Default | Description |
|
|
104
104
|
|--------------------|-------------------------------|--------------------------|--------------------------------------------------|
|
|
105
105
|
| `key` | `string` | *(required)* | Lock name |
|
|
106
|
-
| `acquireTimeoutS` | `number` | `10` | Seconds to wait for the lock before giving up
|
|
107
|
-
| `leaseTtlS` | `number` | server default | Server-side lease duration in seconds
|
|
106
|
+
| `acquireTimeoutS` | `number` | `10` | Seconds to wait for the lock before giving up (integer ≥ 0) |
|
|
107
|
+
| `leaseTtlS` | `number` | server default | Server-side lease duration in seconds (integer ≥ 1) |
|
|
108
108
|
| `servers` | `Array<[string, number]>` | `[["127.0.0.1", 6388]]` | List of `[host, port]` pairs |
|
|
109
109
|
| `shardingStrategy` | `ShardingStrategy` | `stableHashShard` | Function mapping `(key, numServers)` to a server index |
|
|
110
110
|
| `host` | `string` | `127.0.0.1` | Server host *(deprecated — use `servers`)* |
|
|
@@ -233,9 +233,9 @@ try {
|
|
|
233
233
|
| Option | Type | Default | Description |
|
|
234
234
|
|--------------------|-------------------------------|--------------------------|--------------------------------------------------|
|
|
235
235
|
| `key` | `string` | *(required)* | Semaphore name |
|
|
236
|
-
| `limit` | `number` | *(required)* | Max concurrent holders
|
|
237
|
-
| `acquireTimeoutS` | `number` | `10` | Seconds to wait before giving up
|
|
238
|
-
| `leaseTtlS` | `number` | server default | Server-side lease duration in seconds
|
|
236
|
+
| `limit` | `number` | *(required)* | Max concurrent holders (integer ≥ 1) |
|
|
237
|
+
| `acquireTimeoutS` | `number` | `10` | Seconds to wait before giving up (integer ≥ 0) |
|
|
238
|
+
| `leaseTtlS` | `number` | server default | Server-side lease duration in seconds (integer ≥ 1) |
|
|
239
239
|
| `servers` | `Array<[string, number]>` | `[["127.0.0.1", 6388]]` | List of `[host, port]` pairs |
|
|
240
240
|
| `shardingStrategy` | `ShardingStrategy` | `stableHashShard` | Function mapping `(key, numServers)` to a server index |
|
|
241
241
|
| `host` | `string` | `127.0.0.1` | Server host *(deprecated — use `servers`)* |
|
package/dist/client.cjs
CHANGED
|
@@ -261,14 +261,14 @@ function stableHashShard(key, numServers) {
|
|
|
261
261
|
}
|
|
262
262
|
async function protoAcquire(sock, cmd, label, key, acquireTimeoutS, leaseTtlS, limit) {
|
|
263
263
|
validateKey(key);
|
|
264
|
-
if (!Number.
|
|
265
|
-
throw new LockError("acquireTimeoutS must be
|
|
264
|
+
if (!Number.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {
|
|
265
|
+
throw new LockError("acquireTimeoutS must be an integer >= 0");
|
|
266
266
|
}
|
|
267
267
|
if (limit != null && (!Number.isInteger(limit) || limit < 1)) {
|
|
268
268
|
throw new LockError("limit must be an integer >= 1");
|
|
269
269
|
}
|
|
270
|
-
if (leaseTtlS != null && (!Number.
|
|
271
|
-
throw new LockError("leaseTtlS must be
|
|
270
|
+
if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {
|
|
271
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
272
272
|
}
|
|
273
273
|
const parts = [acquireTimeoutS];
|
|
274
274
|
if (limit != null) parts.push(limit);
|
|
@@ -291,8 +291,8 @@ async function protoAcquire(sock, cmd, label, key, acquireTimeoutS, leaseTtlS, l
|
|
|
291
291
|
async function protoRenew(sock, cmd, label, key, token, leaseTtlS) {
|
|
292
292
|
validateKey(key);
|
|
293
293
|
validateToken(token);
|
|
294
|
-
if (leaseTtlS != null && (!Number.
|
|
295
|
-
throw new LockError("leaseTtlS must be
|
|
294
|
+
if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {
|
|
295
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
296
296
|
}
|
|
297
297
|
const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;
|
|
298
298
|
await writeAll(sock, encodeLines(cmd, key, arg));
|
|
@@ -308,8 +308,8 @@ async function protoEnqueue(sock, cmd, label, key, leaseTtlS, limit) {
|
|
|
308
308
|
if (limit != null && (!Number.isInteger(limit) || limit < 1)) {
|
|
309
309
|
throw new LockError("limit must be an integer >= 1");
|
|
310
310
|
}
|
|
311
|
-
if (leaseTtlS != null && (!Number.
|
|
312
|
-
throw new LockError("leaseTtlS must be
|
|
311
|
+
if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {
|
|
312
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
313
313
|
}
|
|
314
314
|
const parts = [];
|
|
315
315
|
if (limit != null) parts.push(limit);
|
|
@@ -331,8 +331,8 @@ async function protoEnqueue(sock, cmd, label, key, leaseTtlS, limit) {
|
|
|
331
331
|
}
|
|
332
332
|
async function protoWait(sock, cmd, label, key, waitTimeoutS) {
|
|
333
333
|
validateKey(key);
|
|
334
|
-
if (!Number.
|
|
335
|
-
throw new LockError("waitTimeoutS must be
|
|
334
|
+
if (!Number.isInteger(waitTimeoutS) || waitTimeoutS < 0) {
|
|
335
|
+
throw new LockError("waitTimeoutS must be an integer >= 0");
|
|
336
336
|
}
|
|
337
337
|
await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));
|
|
338
338
|
const resp = await readline(sock);
|
|
@@ -439,11 +439,11 @@ var DistributedPrimitive = class {
|
|
|
439
439
|
this.onLockLost = opts.onLockLost;
|
|
440
440
|
this.connectTimeoutMs = opts.connectTimeoutMs;
|
|
441
441
|
this.socketTimeoutMs = opts.socketTimeoutMs;
|
|
442
|
-
if (!Number.
|
|
443
|
-
throw new LockError("acquireTimeoutS must be
|
|
442
|
+
if (!Number.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {
|
|
443
|
+
throw new LockError("acquireTimeoutS must be an integer >= 0");
|
|
444
444
|
}
|
|
445
|
-
if (this.leaseTtlS != null && (!Number.
|
|
446
|
-
throw new LockError("leaseTtlS must be
|
|
445
|
+
if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {
|
|
446
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
447
447
|
}
|
|
448
448
|
if (opts.servers) {
|
|
449
449
|
if (opts.servers.length === 0) {
|
|
@@ -546,7 +546,7 @@ var DistributedPrimitive = class {
|
|
|
546
546
|
if (this.renewInFlight) {
|
|
547
547
|
await Promise.race([
|
|
548
548
|
this.renewInFlight,
|
|
549
|
-
new Promise((r) => setTimeout(r, 5e3))
|
|
549
|
+
new Promise((r) => setTimeout(r, 5e3).unref())
|
|
550
550
|
]);
|
|
551
551
|
this.stopRenew();
|
|
552
552
|
}
|
|
@@ -584,9 +584,9 @@ var DistributedPrimitive = class {
|
|
|
584
584
|
if (result.status === "acquired") {
|
|
585
585
|
this.token = result.token;
|
|
586
586
|
this.lease = result.lease ?? 0;
|
|
587
|
+
this.restoreSocketTimeout(this.sock);
|
|
587
588
|
this.startRenew();
|
|
588
589
|
}
|
|
589
|
-
this.restoreSocketTimeout(this.sock);
|
|
590
590
|
return result.status;
|
|
591
591
|
} catch (err) {
|
|
592
592
|
this.close();
|
package/dist/client.cjs.map
CHANGED
|
@@ -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// 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"]}
|
|
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.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 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.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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.isInteger(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be an integer >= 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.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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).unref()),\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.restoreSocketTimeout(this.sock);\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 / 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/dist/client.js
CHANGED
|
@@ -211,14 +211,14 @@ function stableHashShard(key, numServers) {
|
|
|
211
211
|
}
|
|
212
212
|
async function protoAcquire(sock, cmd, label, key, acquireTimeoutS, leaseTtlS, limit) {
|
|
213
213
|
validateKey(key);
|
|
214
|
-
if (!Number.
|
|
215
|
-
throw new LockError("acquireTimeoutS must be
|
|
214
|
+
if (!Number.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {
|
|
215
|
+
throw new LockError("acquireTimeoutS must be an integer >= 0");
|
|
216
216
|
}
|
|
217
217
|
if (limit != null && (!Number.isInteger(limit) || limit < 1)) {
|
|
218
218
|
throw new LockError("limit must be an integer >= 1");
|
|
219
219
|
}
|
|
220
|
-
if (leaseTtlS != null && (!Number.
|
|
221
|
-
throw new LockError("leaseTtlS must be
|
|
220
|
+
if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {
|
|
221
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
222
222
|
}
|
|
223
223
|
const parts = [acquireTimeoutS];
|
|
224
224
|
if (limit != null) parts.push(limit);
|
|
@@ -241,8 +241,8 @@ async function protoAcquire(sock, cmd, label, key, acquireTimeoutS, leaseTtlS, l
|
|
|
241
241
|
async function protoRenew(sock, cmd, label, key, token, leaseTtlS) {
|
|
242
242
|
validateKey(key);
|
|
243
243
|
validateToken(token);
|
|
244
|
-
if (leaseTtlS != null && (!Number.
|
|
245
|
-
throw new LockError("leaseTtlS must be
|
|
244
|
+
if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {
|
|
245
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
246
246
|
}
|
|
247
247
|
const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;
|
|
248
248
|
await writeAll(sock, encodeLines(cmd, key, arg));
|
|
@@ -258,8 +258,8 @@ async function protoEnqueue(sock, cmd, label, key, leaseTtlS, limit) {
|
|
|
258
258
|
if (limit != null && (!Number.isInteger(limit) || limit < 1)) {
|
|
259
259
|
throw new LockError("limit must be an integer >= 1");
|
|
260
260
|
}
|
|
261
|
-
if (leaseTtlS != null && (!Number.
|
|
262
|
-
throw new LockError("leaseTtlS must be
|
|
261
|
+
if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {
|
|
262
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
263
263
|
}
|
|
264
264
|
const parts = [];
|
|
265
265
|
if (limit != null) parts.push(limit);
|
|
@@ -281,8 +281,8 @@ async function protoEnqueue(sock, cmd, label, key, leaseTtlS, limit) {
|
|
|
281
281
|
}
|
|
282
282
|
async function protoWait(sock, cmd, label, key, waitTimeoutS) {
|
|
283
283
|
validateKey(key);
|
|
284
|
-
if (!Number.
|
|
285
|
-
throw new LockError("waitTimeoutS must be
|
|
284
|
+
if (!Number.isInteger(waitTimeoutS) || waitTimeoutS < 0) {
|
|
285
|
+
throw new LockError("waitTimeoutS must be an integer >= 0");
|
|
286
286
|
}
|
|
287
287
|
await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));
|
|
288
288
|
const resp = await readline(sock);
|
|
@@ -389,11 +389,11 @@ var DistributedPrimitive = class {
|
|
|
389
389
|
this.onLockLost = opts.onLockLost;
|
|
390
390
|
this.connectTimeoutMs = opts.connectTimeoutMs;
|
|
391
391
|
this.socketTimeoutMs = opts.socketTimeoutMs;
|
|
392
|
-
if (!Number.
|
|
393
|
-
throw new LockError("acquireTimeoutS must be
|
|
392
|
+
if (!Number.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {
|
|
393
|
+
throw new LockError("acquireTimeoutS must be an integer >= 0");
|
|
394
394
|
}
|
|
395
|
-
if (this.leaseTtlS != null && (!Number.
|
|
396
|
-
throw new LockError("leaseTtlS must be
|
|
395
|
+
if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {
|
|
396
|
+
throw new LockError("leaseTtlS must be an integer >= 1");
|
|
397
397
|
}
|
|
398
398
|
if (opts.servers) {
|
|
399
399
|
if (opts.servers.length === 0) {
|
|
@@ -496,7 +496,7 @@ var DistributedPrimitive = class {
|
|
|
496
496
|
if (this.renewInFlight) {
|
|
497
497
|
await Promise.race([
|
|
498
498
|
this.renewInFlight,
|
|
499
|
-
new Promise((r) => setTimeout(r, 5e3))
|
|
499
|
+
new Promise((r) => setTimeout(r, 5e3).unref())
|
|
500
500
|
]);
|
|
501
501
|
this.stopRenew();
|
|
502
502
|
}
|
|
@@ -534,9 +534,9 @@ var DistributedPrimitive = class {
|
|
|
534
534
|
if (result.status === "acquired") {
|
|
535
535
|
this.token = result.token;
|
|
536
536
|
this.lease = result.lease ?? 0;
|
|
537
|
+
this.restoreSocketTimeout(this.sock);
|
|
537
538
|
this.startRenew();
|
|
538
539
|
}
|
|
539
|
-
this.restoreSocketTimeout(this.sock);
|
|
540
540
|
return result.status;
|
|
541
541
|
} catch (err) {
|
|
542
542
|
this.close();
|
package/dist/client.js.map
CHANGED
|
@@ -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// 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"]}
|
|
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.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 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.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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.isInteger(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be an integer >= 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.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\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).unref()),\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.restoreSocketTimeout(this.sock);\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 / 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"]}
|