/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var download_lock_exports = {};
__export(download_lock_exports, {
  downloadWithLock: () => downloadWithLock
});
module.exports = __toCommonJS(download_lock_exports);
var import_node_fs = require("node:fs");
var import_promises = require("node:fs/promises");
var import_node_path = require("node:path");
var import_http_request = require("./http-request");
function getLockFilePath(destPath, locksDir) {
  const dir = locksDir || `${(0, import_node_path.dirname)(destPath)}/.locks`;
  const filename = `${destPath.replace(/[^\w.-]/g, "_")}.lock`;
  return (0, import_node_path.join)(dir, filename);
}
function isLockStale(lockInfo, staleTimeout) {
  const age = Date.now() - lockInfo.startTime;
  if (age > staleTimeout) {
    return true;
  }
  try {
    process.kill(lockInfo.pid, 0);
    return false;
  } catch {
    return true;
  }
}
async function acquireLock(destPath, url, options) {
  const { lockTimeout, locksDir, pollInterval, staleTimeout } = options;
  const lockPath = getLockFilePath(destPath, locksDir);
  const lockDir = (0, import_node_path.dirname)(lockPath);
  await (0, import_promises.mkdir)(lockDir, { recursive: true });
  const startTime = Date.now();
  while (true) {
    try {
      if ((0, import_node_fs.existsSync)(lockPath)) {
        const lockContent = await (0, import_promises.readFile)(lockPath, "utf8");
        const lockInfo2 = JSON.parse(lockContent);
        if (isLockStale(lockInfo2, staleTimeout)) {
          await (0, import_promises.rm)(lockPath, { force: true });
        } else {
          if (Date.now() - startTime > lockTimeout) {
            throw new Error(
              `Lock acquisition timed out after ${lockTimeout}ms (held by PID ${lockInfo2.pid})`
            );
          }
          await new Promise((resolve) => setTimeout(resolve, pollInterval));
          continue;
        }
      }
      const lockInfo = {
        pid: process.pid,
        startTime: Date.now(),
        url
      };
      await (0, import_promises.writeFile)(lockPath, JSON.stringify(lockInfo, null, 2), {
        // Use 'wx' flag to fail if file exists (atomic operation)
        flag: "wx"
      });
      return lockPath;
    } catch (e) {
      if (e.code === "EEXIST") {
        if (Date.now() - startTime > lockTimeout) {
          throw new Error(`Lock acquisition timed out after ${lockTimeout}ms`);
        }
        await new Promise((resolve) => setTimeout(resolve, pollInterval));
        continue;
      }
      throw e;
    }
  }
}
async function releaseLock(lockPath) {
  try {
    await (0, import_promises.rm)(lockPath, { force: true });
  } catch {
  }
}
async function downloadWithLock(url, destPath, options) {
  const {
    lockTimeout = 6e4,
    locksDir,
    pollInterval = 1e3,
    staleTimeout = 3e5,
    ...downloadOptions
  } = { __proto__: null, ...options };
  if ((0, import_node_fs.existsSync)(destPath)) {
    const statResult = await (0, import_promises.stat)(destPath).catch(() => null);
    if (statResult && statResult.size > 0) {
      return {
        path: destPath,
        size: statResult.size
      };
    }
  }
  const lockPath = await acquireLock(destPath, url, {
    lockTimeout,
    locksDir,
    pollInterval,
    staleTimeout
  });
  try {
    if ((0, import_node_fs.existsSync)(destPath)) {
      const statResult = await (0, import_promises.stat)(destPath).catch(() => null);
      if (statResult && statResult.size > 0) {
        return {
          path: destPath,
          size: statResult.size
        };
      }
    }
    const result = await (0, import_http_request.httpDownload)(url, destPath, downloadOptions);
    return result;
  } finally {
    await releaseLock(lockPath);
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  downloadWithLock
});
//# sourceMappingURL=download-lock.js.map
