#!/usr/bin/env node
"use strict";
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __import_meta_url = typeof document === "undefined" ? new (require("url".replace("", ""))).URL("file:" + __filename).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
var import_path = require("path");
var import_zwave_js = require("zwave-js");
var import_server = require("../lib/server.js");
var import_mock = require("../mock/index.js");
var import_parse_args = require("../util/parse-args.js");
var import_node_module = require("node:module");
const require2 = (0, import_node_module.createRequire)(__import_meta_url);
const normalizeKey = /* @__PURE__ */ __name((key, keyName) => {
  if (Buffer.isBuffer(key))
    return key;
  if (key.length === 32)
    return Buffer.from(key, "hex");
  key = key.toLowerCase();
  if (key.includes("0x"))
    return Buffer.from(key.replace(/0x/g, "").replace(/, /g, ""), "hex");
  throw new Error(`Invalid key format for ${keyName} option`);
}, "normalizeKey");
const getDriverParams = /* @__PURE__ */ __name(() => {
  const args = (0, import_parse_args.parseArgs)([
    "_",
    "config",
    "mock-driver",
    "port",
    "host",
    "disable-dns-sd",
    "reconnect"
  ]);
  if (args.port) {
    if (typeof args["port"] !== "number") {
      throw new Error("port must be a valid integer");
    }
  }
  if (!args["mock-driver"] && args._.length < 1) {
    console.error("Error: Missing path to serial port");
    return;
  }
  const serialPort = args._[0];
  let configPath = args.config;
  if (configPath && configPath.substring(0, 1) !== "/") {
    configPath = (0, import_path.resolve)(process.cwd(), configPath);
  }
  let options;
  let presetNames;
  if (configPath) {
    try {
      ({ presets: presetNames, ...options } = require2(configPath));
      if (options.securityKeys?.S0_Legacy && options.networkKey) {
        throw new Error("Both `networkKey` and `securityKeys.S0_Legacy` options are present in the config. Remove `networkKey`.");
      }
      const securityKeyNames = [
        "S0_Legacy",
        "S2_AccessControl",
        "S2_Authenticated",
        "S2_Unauthenticated"
      ];
      if (options.securityKeys) {
        for (const key of securityKeyNames) {
          if (key in options.securityKeys) {
            options.securityKeys[key] = normalizeKey(options.securityKeys[key], `securityKeys.${key}`);
          }
        }
      }
      if (options.networkKey) {
        if (!options.securityKeys)
          options.securityKeys = {};
        options.securityKeys.S0_Legacy = normalizeKey(options.networkKey, "networkKey");
        console.warn("The `networkKey` option is deprecated in favor of `securityKeys` option. To eliminate this warning, move your networkKey into the securityKeys.S0_Legacy option. Refer to the Z-Wave JS docs for more information");
        delete options.networkKey;
      } else if (!options.securityKeys?.S0_Legacy)
        throw new Error("Error: `securityKeys.S0_Legacy` key is missing.");
      const securityKeysLongRangeNames = [
        "S2_AccessControl",
        "S2_Authenticated"
      ];
      if (options.securityKeysLongRange) {
        for (const key of securityKeysLongRangeNames) {
          if (key in options.securityKeysLongRange) {
            options.securityKeysLongRange[key] = normalizeKey(options.securityKeysLongRange[key], `securityKeysLongRange.${key}`);
          }
        }
      }
    } catch (err) {
      console.error(`Error: failed loading config file ${configPath}`);
      console.error(err);
      return;
    }
  }
  if (!options) {
    options = { emitValueUpdateAfterSetValue: true };
  } else if (!("emitValueUpdateAfterSetValue" in options)) {
    options["emitValueUpdateAfterSetValue"] = true;
  } else if (!options["emitValueUpdateAfterSetValue"]) {
    console.warn("Because `emitValueUpdateAfterSetValue` is set to false, multi-client setups will not work as expected. In particular, clients will not see value updates that are initiated by another client.");
  }
  let presets;
  if (presetNames !== void 0) {
    if (typeof presetNames === "string") {
      presetNames = [presetNames];
    } else if (!Array.isArray(presetNames) || !presetNames.every((p) => typeof p === "string")) {
      throw new Error("presets must be an array of strings or a string if provided");
    }
    presets = presetNames.map((name) => import_zwave_js.driverPresets[name]).filter((preset) => preset !== void 0);
  }
  return {
    args,
    serialPort,
    options,
    presets
  };
}, "getDriverParams");
const logMessage = /* @__PURE__ */ __name((...message) => {
  const now = /* @__PURE__ */ new Date();
  const hours = now.getHours().toString().padStart(2, "0");
  const minutes = now.getMinutes().toString().padStart(2, "0");
  const seconds = now.getSeconds().toString().padStart(2, "0");
  const milliseconds = now.getMilliseconds().toString().padStart(3, "0");
  console.log(`${hours}:${minutes}:${seconds}.${milliseconds} SERVER   ${message.join(" ")}`);
}, "logMessage");
const debug = false;
const logger = {
  debug: /* @__PURE__ */ __name((msg) => debug ? logMessage("[DEBUG]", msg) : void 0, "debug"),
  info: /* @__PURE__ */ __name((msg) => logMessage(msg), "info"),
  warn: /* @__PURE__ */ __name((msg) => logMessage("[WARNING]", msg), "warn"),
  error: /* @__PURE__ */ __name((msg) => logMessage("[ERROR]", msg.toString()), "error")
};
(() => {
  const params = getDriverParams();
  if (!params) {
    process.exit(1);
  }
  let driver;
  let server;
  let retryCount = 0;
  let retryTimer;
  const getRetryDelay = /* @__PURE__ */ __name(() => Math.min(Math.pow(2, retryCount) * 1e3, 6e4), "getRetryDelay");
  const startDriverWithRetry = /* @__PURE__ */ __name(async () => {
    if (retryCount > 0 && (!params.options.logConfig || params.options.logConfig.showLogo)) {
      if (!params.options.logConfig) {
        params.options.logConfig = {
          showLogo: false
        };
      } else {
        params.options.logConfig.showLogo = false;
      }
    }
    if (retryTimer) {
      clearTimeout(retryTimer);
      retryTimer = void 0;
    }
    if (driver) {
      logger.info("stopping driver");
      if (server) {
        await server.destroy();
      }
      if (driver) {
        await driver.destroy();
      }
    }
    driver = params.args["mock-driver"] ? (0, import_mock.createMockDriver)() : new import_zwave_js.Driver(params.serialPort, params.options, ...params.presets ?? []);
    driver.on("error", (e) => {
      logger.error("error in driver", e);
      if (e instanceof import_zwave_js.ZWaveError && e.code === import_zwave_js.ZWaveErrorCodes.Driver_Failed) {
        if (params.args["reconnect"]) {
          startDriverWithRetry();
        } else {
          logger.error("driver failure is unrecoverable, exiting...");
          process.exit(1);
        }
      }
    });
    driver.once("driver ready", async () => {
      logger.info("driver ready - starting server");
      retryCount = 0;
      server = new import_server.ZwavejsServer(driver, {
        port: params.args.port,
        host: params.args.host,
        enableDNSServiceDiscovery: !params.args["disable-dns-sd"],
        logger
      });
      await server.start(true);
    });
    try {
      await driver.start();
    } catch (e) {
      await driver.destroy();
      driver = void 0;
      if (!params.args["reconnect"]) {
        logger.error("failed starting driver.");
        throw e;
      }
      retryCount++;
      const retryDelay = getRetryDelay();
      logger.error(`failed ${retryCount > 1 ? `attempt ${retryCount} ` : ""}starting driver. Retrying in ${Math.round(retryDelay / 1e3)}s...`);
      setTimeout(() => {
        startDriverWithRetry();
      }, retryDelay);
    }
  }, "startDriverWithRetry");
  let closing = false;
  const handleShutdown = /* @__PURE__ */ __name(async (exitCode = 0) => {
    if (closing) {
      process.exit(exitCode);
    }
    closing = true;
    console.log();
    logger.info("shutting down");
    if (retryTimer) {
      clearTimeout(retryTimer);
      retryTimer = void 0;
    }
    if (server) {
      await server.destroy();
    }
    if (driver) {
      await driver.destroy();
    }
    process.exit(exitCode);
  }, "handleShutdown");
  process.on("SIGINT", () => handleShutdown(0));
  process.on("SIGTERM", () => handleShutdown(0));
  startDriverWithRetry();
})();
//# sourceMappingURL=server.js.map
