@gmickel/gno 1.10.0 → 1.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/file-lock.ts +38 -3
package/package.json
CHANGED
package/src/core/file-lock.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* @module src/core/file-lock
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
// node:fs/promises for mkdir (no Bun equivalent for
|
|
8
|
-
import { mkdir } from "node:fs/promises";
|
|
7
|
+
// node:fs/promises for mkdir/rm (no Bun equivalent for filesystem structure ops)
|
|
8
|
+
import { mkdir, rm } from "node:fs/promises";
|
|
9
9
|
// node:path for dirname (no Bun path utils)
|
|
10
10
|
import { dirname } from "node:path";
|
|
11
11
|
|
|
@@ -13,6 +13,8 @@ import { MCP_ERRORS } from "./errors";
|
|
|
13
13
|
const DEFAULT_TIMEOUT_MS = 5000;
|
|
14
14
|
const HOLD_SECONDS = 60 * 60 * 24 * 365;
|
|
15
15
|
const READY_TOKEN = "READY";
|
|
16
|
+
const DIRECTORY_LOCK_SUFFIX = ".dir";
|
|
17
|
+
const DIRECTORY_LOCK_POLL_MS = 50;
|
|
16
18
|
|
|
17
19
|
export interface WriteLockHandle {
|
|
18
20
|
release: () => Promise<void>;
|
|
@@ -65,6 +67,10 @@ function buildHoldCommand(): string {
|
|
|
65
67
|
return `printf '${READY_TOKEN}\\n'; exec sleep ${HOLD_SECONDS}`;
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
function delay(ms: number): Promise<void> {
|
|
71
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
async function waitForReady(
|
|
69
75
|
proc: ReturnType<typeof Bun.spawn>
|
|
70
76
|
): Promise<boolean> {
|
|
@@ -90,13 +96,42 @@ async function waitForReady(
|
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
|
|
99
|
+
async function acquireDirectoryLock(
|
|
100
|
+
lockPath: string,
|
|
101
|
+
timeoutMs: number
|
|
102
|
+
): Promise<WriteLockHandle | null> {
|
|
103
|
+
const directoryLockPath = `${lockPath}${DIRECTORY_LOCK_SUFFIX}`;
|
|
104
|
+
await mkdir(dirname(directoryLockPath), { recursive: true });
|
|
105
|
+
|
|
106
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
107
|
+
while (true) {
|
|
108
|
+
try {
|
|
109
|
+
await mkdir(directoryLockPath);
|
|
110
|
+
return {
|
|
111
|
+
release: async () => {
|
|
112
|
+
await rm(directoryLockPath, { force: true, recursive: true });
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const code = (error as { code?: string }).code;
|
|
117
|
+
if (code !== "EEXIST") {
|
|
118
|
+
throw error;
|
|
119
|
+
}
|
|
120
|
+
if (Date.now() >= deadline) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
await delay(Math.min(DIRECTORY_LOCK_POLL_MS, deadline - Date.now()));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
93
128
|
export async function acquireWriteLock(
|
|
94
129
|
lockPath: string,
|
|
95
130
|
timeoutMs: number = DEFAULT_TIMEOUT_MS
|
|
96
131
|
): Promise<WriteLockHandle | null> {
|
|
97
132
|
const cmd = resolveLockCommand();
|
|
98
133
|
if (!cmd) {
|
|
99
|
-
|
|
134
|
+
return acquireDirectoryLock(lockPath, timeoutMs);
|
|
100
135
|
}
|
|
101
136
|
|
|
102
137
|
await mkdir(dirname(lockPath), { recursive: true });
|