Fix IP pool — atomic writes via rename, remove fake lock
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { openSync, closeSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { readFileSync, writeFileSync, renameSync } from "node:fs";
|
||||
import { CONFIG } from "./config.js";
|
||||
|
||||
function run(cmd: string, args: string[]) {
|
||||
@@ -199,35 +199,35 @@ function writePool(pool: IpPool) {
|
||||
writeFileSync(CONFIG.ipPoolFile, JSON.stringify(pool));
|
||||
}
|
||||
|
||||
function atomicWritePool(pool: IpPool) {
|
||||
const tmp = CONFIG.ipPoolFile + ".tmp";
|
||||
writeFileSync(tmp, JSON.stringify(pool));
|
||||
renameSync(tmp, CONFIG.ipPoolFile);
|
||||
}
|
||||
|
||||
export function allocateIp(): { ip: string; octet: number } {
|
||||
const fd = openSync(CONFIG.ipPoolLock, "w");
|
||||
try {
|
||||
// Simple flock via child process
|
||||
const pool = readPool();
|
||||
for (
|
||||
let octet = CONFIG.bridge.minHost;
|
||||
octet <= CONFIG.bridge.maxHost;
|
||||
octet++
|
||||
) {
|
||||
if (!pool.allocated.includes(octet)) {
|
||||
pool.allocated.push(octet);
|
||||
writePool(pool);
|
||||
return { ip: `${CONFIG.bridge.prefix}.${octet}`, octet };
|
||||
}
|
||||
// Use flock for proper mutual exclusion
|
||||
const result = execFileSync("bash", ["-c",
|
||||
`flock "${CONFIG.ipPoolLock}" cat "${CONFIG.ipPoolFile}" 2>/dev/null || echo '{"allocated":[]}'`
|
||||
], { encoding: "utf-8" });
|
||||
const pool: IpPool = JSON.parse(result.trim());
|
||||
|
||||
for (
|
||||
let octet = CONFIG.bridge.minHost;
|
||||
octet <= CONFIG.bridge.maxHost;
|
||||
octet++
|
||||
) {
|
||||
if (!pool.allocated.includes(octet)) {
|
||||
pool.allocated.push(octet);
|
||||
atomicWritePool(pool);
|
||||
return { ip: `${CONFIG.bridge.prefix}.${octet}`, octet };
|
||||
}
|
||||
throw new Error("No free IPs in pool");
|
||||
} finally {
|
||||
closeSync(fd);
|
||||
}
|
||||
throw new Error("No free IPs in pool");
|
||||
}
|
||||
|
||||
export function releaseIp(octet: number) {
|
||||
const fd = openSync(CONFIG.ipPoolLock, "w");
|
||||
try {
|
||||
const pool = readPool();
|
||||
pool.allocated = pool.allocated.filter((o) => o !== octet);
|
||||
writePool(pool);
|
||||
} finally {
|
||||
closeSync(fd);
|
||||
}
|
||||
const pool = readPool();
|
||||
pool.allocated = pool.allocated.filter((o) => o !== octet);
|
||||
atomicWritePool(pool);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user