IKHSAN
EN Read in EnglishID

homeio

Publik

Fork dari doctor-io/homeio

Branch
main
Commit terakhir
958d74616 Oktober 2026

protocol.mjs

Buka raw
const ALLOWED_METHODS = new Set([
  "network.getStatus",
  "network.scan",
  "network.connect",
  "network.disconnect",
]);

class HelperProtocolError extends Error {
  constructor(message, options = {}) {
    super(message, {
      cause: options.cause,
    });
    this.name = "HelperProtocolError";
    this.code = options.code ?? "invalid_request";
    this.statusCode = options.statusCode ?? 400;
  }
}

function isRecord(value) {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

function asOptionalString(value) {
  if (typeof value !== "string") return null;
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : null;
}

function validateConnectParams(params) {
  if (!isRecord(params)) {
    throw new HelperProtocolError("Invalid connect parameters");
  }

  const ssid = asOptionalString(params.ssid);
  if (!ssid || ssid.length > 128) {
    throw new HelperProtocolError("Invalid ssid");
  }

  const password = params.password;
  if (password !== undefined && (typeof password !== "string" || password.length < 1 || password.length > 128)) {
    throw new HelperProtocolError("Invalid password");
  }

  return {
    ssid,
    password,
  };
}

function validateDisconnectParams(params) {
  if (params === undefined || params === null) {
    return {};
  }

  if (!isRecord(params)) {
    throw new HelperProtocolError("Invalid disconnect parameters");
  }

  const iface = asOptionalString(params.iface);
  if (params.iface !== undefined && (!iface || iface.length > 64)) {
    throw new HelperProtocolError("Invalid iface");
  }

  return iface ? { iface } : {};
}

function validateMethodParams(method, params) {
  if (method === "network.getStatus" || method === "network.scan") {
    return {};
  }

  if (method === "network.connect") {
    return validateConnectParams(params);
  }

  if (method === "network.disconnect") {
    return validateDisconnectParams(params);
  }

  throw new HelperProtocolError("Method not allowed");
}

function parseRpcRequest(line) {
  let parsed;
  try {
    parsed = JSON.parse(line);
  } catch {
    throw new HelperProtocolError("Invalid JSON request");
  }

  if (!isRecord(parsed)) {
    throw new HelperProtocolError("Request payload must be an object");
  }

  const id = asOptionalString(parsed.id);
  const method = asOptionalString(parsed.method);
  const requestId = asOptionalString(parsed.requestId);

  if (!id || id.length > 128) {
    throw new HelperProtocolError("Missing or invalid request id");
  }

  if (!method || !ALLOWED_METHODS.has(method)) {
    throw new HelperProtocolError("Method not allowed");
  }

  return {
    id,
    method,
    requestId,
    params: validateMethodParams(method, parsed.params),
  };
}

function toErrorPayload(error) {
  if (
    error &&
    typeof error === "object" &&
    "code" in error &&
    "message" in error &&
    typeof error.code === "string" &&
    typeof error.message === "string"
  ) {
    return {
      code: error.code,
      message: error.message,
    };
  }

  if (error instanceof HelperProtocolError) {
    return {
      code: error.code,
      message: error.message,
    };
  }

  if (error instanceof Error) {
    return {
      code: "internal_error",
      message: error.message,
    };
  }

  return {
    code: "internal_error",
    message: "Unknown error",
  };
}

export { ALLOWED_METHODS, HelperProtocolError, parseRpcRequest, toErrorPayload };
byte
3.442
baris
151
Jenis
mjs
Commit terakhir
16 Oktober 2026