[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
190
electron/capabilities/rpcTransport.cjs
Normal file
190
electron/capabilities/rpcTransport.cjs
Normal file
@@ -0,0 +1,190 @@
|
||||
"use strict";
|
||||
|
||||
const { CAPABILITY_SURFACES } = require("./constants.cjs");
|
||||
const { resolveRpcTimeoutMs } = require("./rpcTimeouts.cjs");
|
||||
|
||||
function createTaggedError(code, message) {
|
||||
const error = new Error(message);
|
||||
error.code = code;
|
||||
return error;
|
||||
}
|
||||
|
||||
function createUnavailableError(message) {
|
||||
return createTaggedError("RPC_UNAVAILABLE", message);
|
||||
}
|
||||
|
||||
function createRpcTimeoutError(method, timeoutMs, createError = createTaggedError) {
|
||||
return createError(
|
||||
"RPC_TIMEOUT",
|
||||
`Timed out waiting for RPC response to "${method}" after ${timeoutMs}ms.`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a newline-delimited JSON-RPC client over an existing TCP socket.
|
||||
*/
|
||||
function createNdjsonRpcClient({
|
||||
socket,
|
||||
surface = CAPABILITY_SURFACES.BUILTIN,
|
||||
setTimeoutImpl = setTimeout,
|
||||
clearTimeoutImpl = clearTimeout,
|
||||
onBridgeStatus,
|
||||
createError = createTaggedError,
|
||||
messages = {},
|
||||
}) {
|
||||
if (!socket) {
|
||||
throw new Error("socket is required");
|
||||
}
|
||||
|
||||
const connectionClosedMessage = messages.connectionClosed
|
||||
|| "RPC connection closed.";
|
||||
const connectionClosedWhileCallMessage = messages.connectionClosedWhileCall
|
||||
|| connectionClosedMessage;
|
||||
const connectionErrorMessage = messages.connectionError
|
||||
|| ((error) => `RPC connection failed: ${error?.message || error}`);
|
||||
const rpcTimeoutMessage = messages.rpcTimeout
|
||||
|| ((method, timeoutMs) => `Timed out waiting for RPC response to "${method}" after ${timeoutMs}ms.`);
|
||||
const writeFailedMessage = messages.writeFailed
|
||||
|| ((method, error) => `Failed to send RPC "${method}": ${error?.message || error}`);
|
||||
|
||||
let nextRpcId = 1;
|
||||
let buffer = "";
|
||||
const pending = new Map();
|
||||
let bridgeCommandTimeoutMs = null;
|
||||
let bridgePermissionMode = null;
|
||||
let bridgeApprovalTimeoutMs = null;
|
||||
|
||||
function settle(id, resolve, reject, payload) {
|
||||
pending.delete(id);
|
||||
clearTimeoutImpl(payload.timeoutId);
|
||||
if (payload.error) {
|
||||
reject(payload.error);
|
||||
return;
|
||||
}
|
||||
resolve(payload.result);
|
||||
}
|
||||
|
||||
function rejectAll(error) {
|
||||
for (const [id, entry] of pending) {
|
||||
settle(id, entry.resolve, entry.reject, { timeoutId: entry.timeoutId, error });
|
||||
}
|
||||
}
|
||||
|
||||
socket.on("data", (chunk) => {
|
||||
buffer += chunk;
|
||||
let newlineIndex;
|
||||
while ((newlineIndex = buffer.indexOf("\n")) !== -1) {
|
||||
const line = buffer.slice(0, newlineIndex);
|
||||
buffer = buffer.slice(newlineIndex + 1);
|
||||
if (!line.trim()) continue;
|
||||
|
||||
let message;
|
||||
try {
|
||||
message = JSON.parse(line);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (message?.id == null) continue;
|
||||
const entry = pending.get(message.id);
|
||||
if (!entry) continue;
|
||||
|
||||
if (message.error) {
|
||||
settle(message.id, entry.resolve, entry.reject, {
|
||||
timeoutId: entry.timeoutId,
|
||||
error: createError(
|
||||
"RPC_ERROR",
|
||||
message.error.message || JSON.stringify(message.error),
|
||||
),
|
||||
});
|
||||
} else {
|
||||
settle(message.id, entry.resolve, entry.reject, {
|
||||
timeoutId: entry.timeoutId,
|
||||
result: message.result,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("error", (error) => {
|
||||
rejectAll(createError("CONNECTION_ERROR", connectionErrorMessage(error)));
|
||||
});
|
||||
|
||||
socket.on("close", () => {
|
||||
rejectAll(createError("CONNECTION_CLOSED", connectionClosedMessage));
|
||||
});
|
||||
|
||||
async function call(method, params) {
|
||||
if (socket.destroyed || !socket.writable) {
|
||||
throw createError("CONNECTION_CLOSED", connectionClosedWhileCallMessage);
|
||||
}
|
||||
|
||||
const id = nextRpcId++;
|
||||
const timeoutMs = resolveRpcTimeoutMs(method, {
|
||||
surface,
|
||||
bridgeCommandTimeoutMs,
|
||||
bridgePermissionMode,
|
||||
bridgeApprovalTimeoutMs,
|
||||
});
|
||||
|
||||
return await new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeoutImpl(() => {
|
||||
pending.delete(id);
|
||||
reject(createError("RPC_TIMEOUT", rpcTimeoutMessage(method, timeoutMs)));
|
||||
}, timeoutMs);
|
||||
|
||||
pending.set(id, { resolve, reject, timeoutId });
|
||||
|
||||
const payload = `${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`;
|
||||
try {
|
||||
socket.write(payload, (writeError) => {
|
||||
if (!writeError) return;
|
||||
settle(id, resolve, reject, {
|
||||
timeoutId,
|
||||
error: createError("WRITE_FAILED", writeFailedMessage(method, writeError)),
|
||||
});
|
||||
});
|
||||
} catch (writeError) {
|
||||
settle(id, resolve, reject, {
|
||||
timeoutId,
|
||||
error: createError("WRITE_FAILED", writeFailedMessage(method, writeError)),
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function ingestBridgeStatus(statusResult) {
|
||||
if (Number.isFinite(statusResult?.commandTimeoutMs) && statusResult.commandTimeoutMs > 0) {
|
||||
bridgeCommandTimeoutMs = statusResult.commandTimeoutMs;
|
||||
}
|
||||
if (typeof statusResult?.permissionMode === "string") {
|
||||
bridgePermissionMode = statusResult.permissionMode;
|
||||
}
|
||||
if (Number.isFinite(statusResult?.approvalTimeoutMs) && statusResult.approvalTimeoutMs > 0) {
|
||||
bridgeApprovalTimeoutMs = statusResult.approvalTimeoutMs;
|
||||
}
|
||||
onBridgeStatus?.({
|
||||
bridgeCommandTimeoutMs,
|
||||
bridgePermissionMode,
|
||||
bridgeApprovalTimeoutMs,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
call,
|
||||
ingestBridgeStatus,
|
||||
close() {
|
||||
try {
|
||||
socket.end();
|
||||
} catch {
|
||||
// Ignore shutdown errors.
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
createTaggedError,
|
||||
createUnavailableError,
|
||||
createRpcTimeoutError,
|
||||
createNdjsonRpcClient,
|
||||
};
|
||||
Reference in New Issue
Block a user