"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.upScoped = exports.up = exports.socketLocation = exports.setConfig = exports.getNextAvailableInterface = exports.getConfig = exports.execCommand = exports.down = exports.WireguardGoExecutablePath = exports.WindowsInterfaceNameRegExp = exports.WgQuickExecutablePath = exports.SupportedPlatforms = exports.SupportedArchitectures = exports.OpenBSDInterfaceNameRegExp = exports.LinuxInterfaceNameRegExp = exports.InterfaceRegExpForPlatform = exports.FreeBSDInterfaceNameRegExp = exports.DarwinInterfaceNameRegExp = void 0;
var Platform = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/platform"));
var Socket = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/platform-node/NodeSocket"));
var Schema = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Schema"));
var sudoPrompt = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@vscode/sudo-prompt"));
var Chunk = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Chunk"));
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect"));
var Function = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Function"));
var Match = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Match"));
var Number = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Number"));
var Option = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Option"));
var Predicate = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Predicate"));
var ReadonlyArray = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/ReadonlyArray"));
var ReadonlyRecord = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/ReadonlyRecord"));
var Sink = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Sink"));
var Stream = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Stream"));
var String = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/String"));
var Tuple = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Tuple"));
var execa = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("execa"));
var os = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("node:os"));
var WireguardConfig = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardConfig.js"));
var WireguardErrors = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardErrors.js"));
var WireguardInterface = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardInterface.js"));
function _getRequireWildcardCache(e) {
  if ("function" != typeof WeakMap) return null;
  var r = new WeakMap(),
    t = new WeakMap();
  return (_getRequireWildcardCache = function (e) {
    return e ? t : r;
  })(e);
}
function _interopRequireWildcard(e, r) {
  if (!r && e && e.__esModule) return e;
  if (null === e || "object" != typeof e && "function" != typeof e) return {
    default: e
  };
  var t = _getRequireWildcardCache(r);
  if (t && t.has(e)) return t.get(e);
  var n = {
      __proto__: null
    },
    a = Object.defineProperty && Object.getOwnPropertyDescriptor;
  for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
    var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;
    i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];
  }
  return n.default = e, t && t.set(e, n), n;
}
/** @internal */
const SupportedArchitectures = exports.SupportedArchitectures = ["x64", "arm64"];
/** @internal */
const SupportedPlatforms = exports.SupportedPlatforms = ["linux", "win32", "darwin", "openbsd", "freebsd"];
/** @internal */
const LinuxInterfaceNameRegExp = exports.LinuxInterfaceNameRegExp = /^wg\d+$/;
/** @internal */
const DarwinInterfaceNameRegExp = exports.DarwinInterfaceNameRegExp = /^utun\d+$/;
/** @internal */
const OpenBSDInterfaceNameRegExp = exports.OpenBSDInterfaceNameRegExp = /^tun\d+$/;
/** @internal */
const WindowsInterfaceNameRegExp = exports.WindowsInterfaceNameRegExp = /^eth\d+$/;
/** @internal */
const FreeBSDInterfaceNameRegExp = exports.FreeBSDInterfaceNameRegExp = /^eth\d+$/;
/** @internal */
const WireguardGoExecutablePath = exports.WireguardGoExecutablePath = /*#__PURE__*/Effect.gen(function* (λ) {
  const path = yield* λ(Platform.Path.Path);
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const arch = process.arch === "x64" ? "amd64" : process.arch;
  const url = new URL(`./${process.platform}-${arch}-wireguard-go`, import.meta.url);
  const pathString = yield* λ(path.fromFileUrl(url));
  yield* λ(fs.access(pathString, {
    ok: true
  }));
  return pathString;
});
/** @internal */
const WgQuickExecutablePath = exports.WgQuickExecutablePath = /*#__PURE__*/Effect.gen(function* (λ) {
  const path = yield* λ(Platform.Path.Path);
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const url = new URL(`./${process.platform}-wg-quick`, import.meta.url);
  const pathString = yield* λ(path.fromFileUrl(url));
  yield* λ(fs.access(pathString, {
    ok: true
  }));
  return pathString;
});
/** @internal */
const InterfaceRegExpForPlatform = exports.InterfaceRegExpForPlatform = /*#__PURE__*/Function.pipe( /*#__PURE__*/Match.value(`${process.arch}:${process.platform}`), /*#__PURE__*/Match.not( /*#__PURE__*/Predicate.some( /*#__PURE__*/ReadonlyArray.map(SupportedArchitectures, arch => String.startsWith(`${arch}:`))), bad => Effect.fail(new WireguardErrors.WireguardError({
  message: `Unsupported architecture ${bad}`
}))), /*#__PURE__*/Match.when( /*#__PURE__*/String.endsWith(":linux"), () => Effect.succeed(LinuxInterfaceNameRegExp)), /*#__PURE__*/Match.when( /*#__PURE__*/String.endsWith(":win32"), () => Effect.succeed(WindowsInterfaceNameRegExp)), /*#__PURE__*/Match.when( /*#__PURE__*/String.endsWith(":darwin"), () => Effect.succeed(DarwinInterfaceNameRegExp)), /*#__PURE__*/Match.when( /*#__PURE__*/String.endsWith(":openbsd"), () => Effect.succeed(OpenBSDInterfaceNameRegExp)), /*#__PURE__*/Match.when( /*#__PURE__*/String.endsWith(":freebsd"), () => Effect.succeed(FreeBSDInterfaceNameRegExp)), /*#__PURE__*/Match.orElse(bad => Effect.fail(new WireguardErrors.WireguardError({
  message: `Unsupported platform ${bad}`
}))));
/** @internal */
const getNextAvailableInterface = exports.getNextAvailableInterface = /*#__PURE__*/Effect.gen(function* (λ) {
  // Determine all the used interface indexes
  const regex = yield* λ(InterfaceRegExpForPlatform);
  const usedInterfaceIndexes = Function.pipe(os.networkInterfaces(), ReadonlyRecord.keys, ReadonlyArray.filter(name => regex.test(name)), ReadonlyArray.map(String.replaceAll(/\D/g, "")), ReadonlyArray.map(Number.parse), ReadonlyArray.filterMap(Function.identity));
  // Find the next available interface index
  const nextAvailableInterfaceIndex = yield* λ(Function.pipe(Stream.iterate(0, x => x + 1), Stream.find(x => !ReadonlyArray.contains(usedInterfaceIndexes, x)), Stream.take(1), Stream.runCollect, Effect.map(Chunk.head), Effect.map(Option.getOrThrow)));
  // We know this will be a supported platform now because otherwise
  // the WireguardInterface.InterfaceRegExpForPlatform would have failed
  const platform = Function.unsafeCoerce(process.platform);
  // Construct the next available interface name
  const fromString = Schema.decodeSync(WireguardInterface.WireguardInterface);
  switch (platform) {
    case "win32":
    case "freebsd":
      return fromString({
        Name: `eth${nextAvailableInterfaceIndex}`
      });
    case "linux":
      return fromString({
        Name: `wg${nextAvailableInterfaceIndex}`
      });
    case "openbsd":
      return fromString({
        Name: `tun${nextAvailableInterfaceIndex}`
      });
    case "darwin":
      return fromString({
        Name: `utun${nextAvailableInterfaceIndex}`
      });
    default:
      return Function.absurd(platform);
  }
});
/** @internal */
const socketLocation = interfaceObject => Function.pipe(Match.type(), Match.when("win32", () => `\\\\.\\pipe\\wireguard\\${interfaceObject.Name}`), Match.when("linux", () => `/var/run/wireguard/${interfaceObject.Name}.sock`), Match.when("darwin", () => `/var/run/wireguard/${interfaceObject.Name}.sock`), Match.when("freebsd", () => `/var/run/wireguard/${interfaceObject.Name}.sock`), Match.when("openbsd", () => `/var/run/wireguard/${interfaceObject.Name}.sock`), Match.orElseAbsurd)(Function.unsafeCoerce(process.platform));
/** @internal */
exports.socketLocation = socketLocation;
const execCommand = (withSudo, command, env) => withSudo === "ask" ? Effect.try({
  try: () => sudoPrompt.exec(`${command}`, {
    name: "The-WireGuard-Effect",
    env: env ?? {}
  }),
  catch: error => new WireguardErrors.WireguardError({
    message: `${error}`
  })
}) : Effect.tryPromise({
  try: () => {
    const subprocess = execa.execaCommand(`${withSudo === true ? "sudo " : ""}${command}`, {
      env: env ?? {},
      cleanup: false,
      detached: true,
      stdio: "ignore"
    });
    subprocess.unref();
    return subprocess;
  },
  catch: error => new WireguardErrors.WireguardError({
    message: `${error}`
  })
});
/** @internal */
exports.execCommand = execCommand;
const upScoped = exports.upScoped = /*#__PURE__*/Function.dual(args => Schema.is(WireguardInterface.WireguardInterface)(args[0]), (interfaceObject, config, options) => {
  const downControlOptions = Function.pipe(Match.value(options?.how), Match.when(Predicate.isUndefined, () => ({
    how: "userspace-api"
  })), Match.whenOr("bundled-wireguard-go+userspace-api", "system-wireguard-go+userspace-api", () => ({
    how: "userspace-api"
  })), Match.whenOr("bundled-wireguard-go+bundled-wg-quick", "system-wireguard+bundled-wg-quick", "system-wireguard-go+bundled-wg-quick", () => ({
    how: "bundled-wg-quick"
  })), Match.whenOr("bundled-wireguard-go+system-wg-quick", "system-wireguard+system-wg-quick", "system-wireguard-go+system-wg-quick", () => ({
    how: "system-wg-quick"
  })), Match.exhaustive);
  return Effect.acquireRelease(up(interfaceObject, config, options), Function.flow(Function.constant(down(interfaceObject, downControlOptions)), Effect.orDie));
});
/** @internal */
const up = exports.up = /*#__PURE__*/Function.dual(args => Schema.is(WireguardInterface.WireguardInterface)(args[0]), (interfaceObject, config, options) => Effect.gen(function* (λ) {
  const path = yield* λ(Platform.Path.Path);
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const tempDirectory = yield* λ(fs.makeTempDirectory());
  // Write the configuration to a temporary file
  const file = path.join(tempDirectory, `${interfaceObject.Name}.conf`);
  yield* λ(config.writeToFile(file));
  // Find bundled executables and scripts
  const bundledWgQuickExecutablePath = yield* λ(WgQuickExecutablePath);
  const bundledWireguardGoExecutablePath = yield* λ(WireguardGoExecutablePath);
  switch (options?.how) {
    // Bring up the interface using the bundled wireguard-go and userspace API
    case undefined:
    case "bundled-wireguard-go+userspace-api":
      const command2_1 = `${bundledWireguardGoExecutablePath} ${interfaceObject.Name}`;
      yield* λ(execCommand(options?.sudo ?? "ask", command2_1));
      yield* λ(setConfig(config, interfaceObject));
      return interfaceObject;
    // Bring up the interface using the bundled wireguard-go and the bundled wg-quick script
    case "bundled-wireguard-go+bundled-wg-quick":
      const env3 = {
        WG_QUICK_USERSPACE_IMPLEMENTATION: bundledWireguardGoExecutablePath
      };
      const command3 = `${bundledWgQuickExecutablePath} up ${file}`;
      yield* λ(execCommand(options.sudo ?? "ask", command3, env3));
      return interfaceObject;
    // Bring up the interface using the bundled wireguard-go and the system wg-quick script
    case "bundled-wireguard-go+system-wg-quick":
      const env4 = {
        WG_QUICK_USERSPACE_IMPLEMENTATION: bundledWireguardGoExecutablePath
      };
      const command4 = `wg-quick up ${file}`;
      yield* λ(execCommand(options.sudo ?? "ask", command4, env4));
      return interfaceObject;
    // Bring up the interface using the system wireguard-go and the userspace API
    case "system-wireguard-go+userspace-api":
      const command5_1 = `wireguard-go ${interfaceObject.Name}`;
      yield* λ(execCommand(options.sudo ?? "ask", command5_1));
      yield* λ(setConfig(config, interfaceObject));
      return interfaceObject;
    // Bring up the interface using the system wireguard-go and the bundled wg-quick script
    case "system-wireguard-go+bundled-wg-quick":
      const env6 = {
        WG_QUICK_USERSPACE_IMPLEMENTATION: "wireguard-go"
      };
      const command6 = `${bundledWgQuickExecutablePath} up ${file}`;
      yield* λ(execCommand(options.sudo ?? "ask", command6, env6));
      return interfaceObject;
    // Bring up the interface using the system wireguard-go and the system wg-quick script
    case "system-wireguard-go+system-wg-quick":
      const env7 = {
        WG_QUICK_USERSPACE_IMPLEMENTATION: "wireguard-go"
      };
      const command7 = `wg-quick up ${file}`;
      yield* λ(execCommand(options.sudo ?? "ask", command7, env7));
      return interfaceObject;
    // Bring up the interface using the system wireguard and the bundled wg-quick script
    case "system-wireguard+bundled-wg-quick":
      const command8 = `${bundledWgQuickExecutablePath} up ${file}`;
      yield* λ(execCommand(options.sudo ?? "ask", command8));
      return interfaceObject;
    // Bring up the interface using the system wireguard and the system wg quick script
    case "system-wireguard+system-wg-quick":
      const command9 = `wg-quick up ${file}`;
      yield* λ(execCommand(options.sudo ?? "ask", command9));
      return interfaceObject;
  }
}));
/** @internal */
const down = (interfaceObject, options) => Effect.map(Platform.FileSystem.FileSystem, fs => fs.remove(socketLocation(interfaceObject)));
/** @internal */
exports.down = down;
const setConfig = (config, interfaceObject) => Effect.gen(function* (λ) {
  const configDecoded = yield* λ(Schema.encode(WireguardConfig.WireguardConfig)(config));
  const [uapiConfig, _address] = yield* λ(Schema.decode(WireguardConfig.WireguardUapiConfig)(configDecoded));
  return Function.pipe(Stream.make(`set=1\n\n${uapiConfig}`), Stream.encodeText, Stream.pipeThroughChannelOrFail(Socket.makeNetChannel({
    path: socketLocation(interfaceObject)
  })), Stream.decodeText(), Stream.run(Sink.last()), Effect.map(Option.getOrThrow), Effect.map(String.trimEnd), Effect.flatMap(Schema.decodeUnknown(WireguardErrors.SuccessErrno)), Effect.catchAll(error => Effect.fail(new WireguardErrors.WireguardError({
    message: error.message
  }))));
});
/** @internal */
exports.setConfig = setConfig;
const getConfig = (address, interfaceObject) => Function.pipe(Stream.make("get=1\n\n"), Stream.encodeText, Stream.pipeThroughChannelOrFail(Socket.makeNetChannel({
  path: socketLocation(interfaceObject)
})), Stream.decodeText(), Stream.flatMap(Function.compose(String.linesIterator, Stream.fromIterable)), Stream.map(String.trimEnd), Stream.filter(String.isNonEmpty), Stream.run(Sink.collectAll()), Effect.tap(Function.flow(Chunk.last, Option.getOrThrow, Schema.decodeUnknown(WireguardErrors.SuccessErrno))), Effect.map(Chunk.join("\n")), Effect.map(uapiData => Tuple.make(uapiData, address)), Effect.flatMap(Schema.encode(WireguardConfig.WireguardUapiConfig)), Effect.flatMap(Schema.decode(WireguardConfig.WireguardConfig)), Effect.catchAll(error => Effect.fail(new WireguardErrors.WireguardError({
  message: error.message
}))));
exports.getConfig = getConfig;
//# sourceMappingURL=wireguardInterface.js.map