mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
fix: resolve Windows compilation errors and warnings
- Add Manager trait import for windows_startup_cmd.rs - Add explicit type annotations for PathBuf in windows_startup_cmd.rs - Fix unused import warning in screenshot_capture_service.rs - Prefix unused variables with underscore in runner.rs and aster_agent_cmd.rs - Update package.json with Node.js engine requirement
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import process from 'node:process';
|
||||
import { randomUUID } from "node:crypto";
|
||||
import process from "node:process";
|
||||
|
||||
const DEFAULTS = {
|
||||
server: 'ws://127.0.0.1:8787',
|
||||
key: '',
|
||||
profile: 'default',
|
||||
server: "ws://127.0.0.1:8787",
|
||||
key: "",
|
||||
profile: "default",
|
||||
timeoutMs: 15000,
|
||||
};
|
||||
|
||||
@@ -14,27 +14,27 @@ function parseArgs(argv) {
|
||||
const args = { ...DEFAULTS };
|
||||
for (let i = 0; i < argv.length; i += 1) {
|
||||
const arg = argv[i];
|
||||
if (arg === '--server' && argv[i + 1]) {
|
||||
if (arg === "--server" && argv[i + 1]) {
|
||||
args.server = argv[i + 1];
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === '--key' && argv[i + 1]) {
|
||||
if (arg === "--key" && argv[i + 1]) {
|
||||
args.key = argv[i + 1];
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === '--profile' && argv[i + 1]) {
|
||||
if (arg === "--profile" && argv[i + 1]) {
|
||||
args.profile = argv[i + 1];
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === '--timeout-ms' && argv[i + 1]) {
|
||||
if (arg === "--timeout-ms" && argv[i + 1]) {
|
||||
args.timeoutMs = Number(argv[i + 1]);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (arg === '--help' || arg === '-h') {
|
||||
if (arg === "--help" || arg === "-h") {
|
||||
printHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
@@ -62,23 +62,26 @@ Proxycast Chrome Bridge E2E 联调脚本
|
||||
}
|
||||
|
||||
function assertGlobalWebSocket() {
|
||||
if (typeof WebSocket !== 'undefined') {
|
||||
if (typeof WebSocket !== "undefined") {
|
||||
return;
|
||||
}
|
||||
throw new Error(
|
||||
'当前 Node 运行时不支持全局 WebSocket,请使用 Node 20+ 或安装支持 WebSocket 的运行环境。',
|
||||
"当前 Node 运行时不支持全局 WebSocket,请使用 Node 22+ 或安装支持 WebSocket 的运行环境。",
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeServer(server) {
|
||||
return String(server || '').trim().replace(/\/$/, '');
|
||||
return String(server || "")
|
||||
.trim()
|
||||
.replace(/\/$/, "");
|
||||
}
|
||||
|
||||
function toText(data) {
|
||||
if (typeof data === 'string') return data;
|
||||
if (Buffer.isBuffer(data)) return data.toString('utf8');
|
||||
if (data instanceof ArrayBuffer) return Buffer.from(data).toString('utf8');
|
||||
if (ArrayBuffer.isView(data)) return Buffer.from(data.buffer).toString('utf8');
|
||||
if (typeof data === "string") return data;
|
||||
if (Buffer.isBuffer(data)) return data.toString("utf8");
|
||||
if (data instanceof ArrayBuffer) return Buffer.from(data).toString("utf8");
|
||||
if (ArrayBuffer.isView(data))
|
||||
return Buffer.from(data.buffer).toString("utf8");
|
||||
return String(data);
|
||||
}
|
||||
|
||||
@@ -108,7 +111,11 @@ function createClient(url, label, timeoutMs) {
|
||||
|
||||
ws.onerror = (event) => {
|
||||
clearTimeout(timer);
|
||||
reject(new Error(`[${label}] WebSocket 连接失败: ${event?.message || 'unknown error'}`));
|
||||
reject(
|
||||
new Error(
|
||||
`[${label}] WebSocket 连接失败: ${event?.message || "unknown error"}`,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
@@ -117,7 +124,7 @@ function createClient(url, label, timeoutMs) {
|
||||
try {
|
||||
payload = JSON.parse(text);
|
||||
} catch (_) {
|
||||
payload = { type: 'raw_text', data: text };
|
||||
payload = { type: "raw_text", data: text };
|
||||
}
|
||||
state.messages.push(payload);
|
||||
|
||||
@@ -184,154 +191,157 @@ async function main() {
|
||||
|
||||
if (!args.key) {
|
||||
printHelp();
|
||||
throw new Error('缺少必填参数: --key');
|
||||
throw new Error("缺少必填参数: --key");
|
||||
}
|
||||
if (!Number.isFinite(args.timeoutMs) || args.timeoutMs < 1000) {
|
||||
throw new Error('--timeout-ms 必须是 >= 1000 的数字');
|
||||
throw new Error("--timeout-ms 必须是 >= 1000 的数字");
|
||||
}
|
||||
|
||||
const server = normalizeServer(args.server);
|
||||
const key = encodeURIComponent(args.key);
|
||||
const profile = encodeURIComponent(args.profile || 'default');
|
||||
const profile = encodeURIComponent(args.profile || "default");
|
||||
const observerUrl = `${server}/proxycast-chrome-observer/Proxycast_Key=${key}?profileKey=${profile}`;
|
||||
const controlUrl = `${server}/proxycast-chrome-control/Proxycast_Key=${key}`;
|
||||
|
||||
console.log('[E2E] observer:', observerUrl);
|
||||
console.log('[E2E] control :', controlUrl);
|
||||
console.log("[E2E] observer:", observerUrl);
|
||||
console.log("[E2E] control :", controlUrl);
|
||||
|
||||
let observer;
|
||||
let control;
|
||||
|
||||
try {
|
||||
observer = await createClient(observerUrl, 'observer', args.timeoutMs);
|
||||
control = await createClient(controlUrl, 'control', args.timeoutMs);
|
||||
observer = await createClient(observerUrl, "observer", args.timeoutMs);
|
||||
control = await createClient(controlUrl, "control", args.timeoutMs);
|
||||
|
||||
await waitForMessage(
|
||||
observer,
|
||||
(msg) => msg.type === 'connection_ack',
|
||||
(msg) => msg.type === "connection_ack",
|
||||
args.timeoutMs,
|
||||
'observer connection_ack',
|
||||
"observer connection_ack",
|
||||
);
|
||||
await waitForMessage(
|
||||
control,
|
||||
(msg) => msg.type === 'connection_ack',
|
||||
(msg) => msg.type === "connection_ack",
|
||||
args.timeoutMs,
|
||||
'control connection_ack',
|
||||
"control connection_ack",
|
||||
);
|
||||
console.log('[E2E] 连接握手通过');
|
||||
console.log("[E2E] 连接握手通过");
|
||||
|
||||
send(observer, { type: 'heartbeat', timestamp: Date.now() });
|
||||
send(control, { type: 'heartbeat', timestamp: Date.now() });
|
||||
send(observer, { type: "heartbeat", timestamp: Date.now() });
|
||||
send(control, { type: "heartbeat", timestamp: Date.now() });
|
||||
|
||||
await waitForMessage(
|
||||
observer,
|
||||
(msg) => msg.type === 'heartbeat_ack',
|
||||
(msg) => msg.type === "heartbeat_ack",
|
||||
args.timeoutMs,
|
||||
'observer heartbeat_ack',
|
||||
"observer heartbeat_ack",
|
||||
);
|
||||
await waitForMessage(
|
||||
control,
|
||||
(msg) => msg.type === 'heartbeat_ack',
|
||||
(msg) => msg.type === "heartbeat_ack",
|
||||
args.timeoutMs,
|
||||
'control heartbeat_ack',
|
||||
"control heartbeat_ack",
|
||||
);
|
||||
console.log('[E2E] 心跳通道通过');
|
||||
console.log("[E2E] 心跳通道通过");
|
||||
|
||||
const requestId1 = `e2e-${randomUUID()}`;
|
||||
send(control, {
|
||||
type: 'command',
|
||||
type: "command",
|
||||
data: {
|
||||
requestId: requestId1,
|
||||
command: 'get_page_info',
|
||||
command: "get_page_info",
|
||||
wait_for_page_info: true,
|
||||
},
|
||||
});
|
||||
|
||||
const cmdFromServer1 = await waitForMessage(
|
||||
observer,
|
||||
(msg) => msg.type === 'command' && msg.data?.requestId === requestId1,
|
||||
(msg) => msg.type === "command" && msg.data?.requestId === requestId1,
|
||||
args.timeoutMs,
|
||||
'observer 收到 get_page_info 命令',
|
||||
"observer 收到 get_page_info 命令",
|
||||
);
|
||||
console.log('[E2E] observer 收到命令:', cmdFromServer1.data?.command);
|
||||
console.log("[E2E] observer 收到命令:", cmdFromServer1.data?.command);
|
||||
|
||||
send(observer, {
|
||||
type: 'command_result',
|
||||
type: "command_result",
|
||||
data: {
|
||||
requestId: requestId1,
|
||||
status: 'success',
|
||||
message: 'get_page_info executed by e2e observer',
|
||||
status: "success",
|
||||
message: "get_page_info executed by e2e observer",
|
||||
},
|
||||
});
|
||||
send(observer, {
|
||||
type: 'pageInfoUpdate',
|
||||
type: "pageInfoUpdate",
|
||||
data: {
|
||||
markdown: '# E2E Page\nURL: https://example.com/e2e\n\n## 内容\nbridge e2e test',
|
||||
markdown:
|
||||
"# E2E Page\nURL: https://example.com/e2e\n\n## 内容\nbridge e2e test",
|
||||
},
|
||||
});
|
||||
|
||||
await waitForMessage(
|
||||
control,
|
||||
(msg) =>
|
||||
msg.type === 'command_result' &&
|
||||
msg.type === "command_result" &&
|
||||
msg.data?.requestId === requestId1 &&
|
||||
msg.data?.status === 'success',
|
||||
msg.data?.status === "success",
|
||||
args.timeoutMs,
|
||||
'control 收到 command_result(success)',
|
||||
"control 收到 command_result(success)",
|
||||
);
|
||||
await waitForMessage(
|
||||
control,
|
||||
(msg) =>
|
||||
msg.type === 'page_info_update' &&
|
||||
msg.type === "page_info_update" &&
|
||||
msg.data?.requestId === requestId1 &&
|
||||
typeof msg.data?.markdown === 'string' &&
|
||||
msg.data.markdown.includes('E2E Page'),
|
||||
typeof msg.data?.markdown === "string" &&
|
||||
msg.data.markdown.includes("E2E Page"),
|
||||
args.timeoutMs,
|
||||
'control 收到 page_info_update',
|
||||
"control 收到 page_info_update",
|
||||
);
|
||||
console.log('[E2E] wait_for_page_info 命令链路通过');
|
||||
console.log("[E2E] wait_for_page_info 命令链路通过");
|
||||
|
||||
const requestId2 = `e2e-${randomUUID()}`;
|
||||
send(control, {
|
||||
type: 'command',
|
||||
type: "command",
|
||||
data: {
|
||||
requestId: requestId2,
|
||||
command: 'scroll',
|
||||
text: 'down:300',
|
||||
command: "scroll",
|
||||
text: "down:300",
|
||||
wait_for_page_info: false,
|
||||
},
|
||||
});
|
||||
|
||||
const cmdFromServer2 = await waitForMessage(
|
||||
observer,
|
||||
(msg) => msg.type === 'command' && msg.data?.requestId === requestId2,
|
||||
(msg) => msg.type === "command" && msg.data?.requestId === requestId2,
|
||||
args.timeoutMs,
|
||||
'observer 收到 scroll 命令',
|
||||
"observer 收到 scroll 命令",
|
||||
);
|
||||
if (cmdFromServer2.data?.command !== 'scroll') {
|
||||
throw new Error(`期望 scroll,实际为 ${cmdFromServer2.data?.command || 'unknown'}`);
|
||||
if (cmdFromServer2.data?.command !== "scroll") {
|
||||
throw new Error(
|
||||
`期望 scroll,实际为 ${cmdFromServer2.data?.command || "unknown"}`,
|
||||
);
|
||||
}
|
||||
send(observer, {
|
||||
type: 'command_result',
|
||||
type: "command_result",
|
||||
data: {
|
||||
requestId: requestId2,
|
||||
status: 'success',
|
||||
message: 'scroll executed by e2e observer',
|
||||
status: "success",
|
||||
message: "scroll executed by e2e observer",
|
||||
},
|
||||
});
|
||||
|
||||
await waitForMessage(
|
||||
control,
|
||||
(msg) =>
|
||||
msg.type === 'command_result' &&
|
||||
msg.type === "command_result" &&
|
||||
msg.data?.requestId === requestId2 &&
|
||||
msg.data?.status === 'success',
|
||||
msg.data?.status === "success",
|
||||
args.timeoutMs,
|
||||
'control 收到 scroll command_result',
|
||||
"control 收到 scroll command_result",
|
||||
);
|
||||
console.log('[E2E] 非 wait_for_page_info 命令链路通过');
|
||||
console.log("[E2E] 非 wait_for_page_info 命令链路通过");
|
||||
|
||||
console.log('\n[E2E] ✅ Chrome Bridge 联调通过');
|
||||
console.log("\n[E2E] ✅ Chrome Bridge 联调通过");
|
||||
} finally {
|
||||
await closeClient(control);
|
||||
await closeClient(observer);
|
||||
@@ -339,7 +349,7 @@ async function main() {
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error('\n[E2E] ❌ Chrome Bridge 联调失败');
|
||||
console.error("\n[E2E] ❌ Chrome Bridge 联调失败");
|
||||
console.error(error?.stack || error?.message || String(error));
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"fast-check": "^3.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=22.0.0"
|
||||
},
|
||||
"author": "ProxyCast",
|
||||
"license": "MIT"
|
||||
|
||||
Reference in New Issue
Block a user