Ctrl K
ComunidadGuías…

lib/ipc.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var net = require("net");
var fs = require("fs");

/**
 * Create IPC server on a Unix domain socket.
 * handler(msg) should return a response object (or a Promise of one).
 */
function createIPCServer(sockPath, handler) {
  // Remove stale socket file (not needed for Windows named pipes)
  if (process.platform !== "win32") {
    try { fs.unlinkSync(sockPath); } catch (e) {}
  }

  var server = net.createServer(function (conn) {
    var buffer = "";
    conn.setEncoding("utf8");

    conn.on("data", function (chunk) {
      buffer += chunk;
      var lines = buffer.split("\n");
      buffer = lines.pop(); // keep incomplete line

      for (var i = 0; i < lines.length; i++) {
        if (!lines[i].trim()) continue;
        try {
          var msg = JSON.parse(lines[i]);
          var result = handler(msg);
          // Support both sync and async handlers
          if (result && typeof result.then === "function") {
            (function (c) {
              result.then(function (res) {
                try { c.write(JSON.stringify(res) + "\n"); } catch (e) {}
              }).catch(function (err) {
                try { c.write(JSON.stringify({ ok: false, error: err.message }) + "\n"); } catch (e) {}
              });
            })(conn);
          } else {
            conn.write(JSON.stringify(result) + "\n");
          }
        } catch (e) {
          try { conn.write(JSON.stringify({ ok: false, error: "parse error" }) + "\n"); } catch (e2) {}
        }
      }
    });

    conn.on("error", function () {});
  });

  var retried = false;
  server.on("error", function (err) {
    if (err.code === "EADDRINUSE" && !retried) {
      retried = true;
      console.log("[ipc] Socket in use, removing stale socket and retrying...");
      try { fs.unlinkSync(sockPath); } catch (e) {}
      server.listen(sockPath);
    } else {
      console.error("[ipc] Failed to bind socket:", err.message);
      process.exit(1);
    }
  });
  server.listen(sockPath);

  return {
    close: function () {
      server.close();
      if (process.platform !== "win32") {
        try { fs.unlinkSync(sockPath); } catch (e) {}
      }
    },
  };
}

/**
 * Send a command to the daemon IPC server and wait for response.
 * Returns a Promise resolving to the parsed response.
 */
function sendIPCCommand(sockPath, message, timeout) {
  var timeoutMs = timeout || 3000;
  return new Promise(function (resolve) {
    var client = net.connect(sockPath);
    var buffer = "";
    var done = false;

    var timer = setTimeout(function () {
      if (!done) {
        done = true;
        client.destroy();
        resolve({ ok: false, error: "timeout" });
      }
    }, timeoutMs);

    client.on("connect", function () {
      client.write(JSON.stringify(message) + "\n");
    });

    client.on("data", function (chunk) {
      buffer += chunk;
      var idx = buffer.indexOf("\n");
      if (idx !== -1 && !done) {
        done = true;
        clearTimeout(timer);
        try {
          var resp = JSON.parse(buffer.substring(0, idx));
          resolve(resp);
        } catch (e) {
          resolve({ ok: false, error: "invalid response" });
        }
        client.destroy();
      }
    });

    client.on("error", function (err) {
      if (!done) {
        done = true;
        clearTimeout(timer);
        resolve({ ok: false, error: err.code === "ECONNREFUSED" ? "daemon not responding" : err.message });
      }
    });
  });
}

module.exports = {
  createIPCServer: createIPCServer,
  sendIPCCommand: sendIPCCommand,
};