mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
feat(termux): Android/Termux headless support (#2273)
- Move wreq-js and tls-client-node to optionalDependencies - Lazy-load wreq-js WS proxy with graceful 503 when unavailable - Auto-detect Android platform for headless mode (no browser open) - Set GYP_DEFINES for better-sqlite3 build on Android/ARM - Extended build timeout to 600s for ARM compilation - Skip wreq-js binary fix on Android (unsupported platform) - Platform warnings for unsupported features (WS proxy, TLS, Electron, MITM) Co-authored-by: t-way666 <t-way666@users.noreply.github.com>
This commit is contained in:
@@ -386,7 +386,8 @@ if (portIdx !== -1 && args[portIdx + 1]) {
|
||||
|
||||
const apiPort = parsePort(process.env.API_PORT || String(port), port);
|
||||
const dashboardPort = parsePort(process.env.DASHBOARD_PORT || String(port), port);
|
||||
const noOpen = args.includes("--no-open");
|
||||
const isAndroid = process.platform === 'android';
|
||||
let noOpen = args.includes("--no-open") || isAndroid;
|
||||
|
||||
console.log(`
|
||||
\x1b[36m ____ _ ____ _
|
||||
@@ -397,6 +398,16 @@ console.log(`
|
||||
\\\\____/|_| |_| |_|_| |_|_|_| \\\\_\\\\___/ \\\\__,_|\\\\__\\\\___|
|
||||
\x1b[0m`);
|
||||
|
||||
if (isAndroid) {
|
||||
console.log(`\x1b[33m[OmniRoute] Running on Android/Termux — headless mode enabled automatically\x1b[0m`);
|
||||
console.log(`\x1b[33m[OmniRoute] Platform: android/${process.arch} — unsupported features:\x1b[0m
|
||||
- Codex Responses WebSocket (wreq-js unavailable)
|
||||
- ChatGPT Web TLS impersonation (tls-client-node unavailable)
|
||||
- Electron desktop app
|
||||
- MITM proxy / system certificate install
|
||||
`);
|
||||
}
|
||||
|
||||
const nodeSupport = getNodeRuntimeSupport();
|
||||
if (!nodeSupport.nodeCompatible) {
|
||||
const runtimeWarning = getNodeRuntimeWarning() || "Unsupported Node.js runtime detected.";
|
||||
|
||||
@@ -165,18 +165,18 @@
|
||||
"react-markdown": "^10.1.0",
|
||||
"recharts": "^3.8.1",
|
||||
"selfsigned": "^5.5.0",
|
||||
"tls-client-node": "^0.1.13",
|
||||
"tsx": "^4.21.1",
|
||||
"undici": "^8.2.0",
|
||||
"uuid": "^14.0.0",
|
||||
"wreq-js": "^2.3.0",
|
||||
"xxhash-wasm": "^1.1.0",
|
||||
"yazl": "^3.3.1",
|
||||
"zod": "^4.4.3",
|
||||
"zustand": "^5.0.13"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"keytar": "^7.9.0"
|
||||
"keytar": "^7.9.0",
|
||||
"tls-client-node": "^0.1.13",
|
||||
"wreq-js": "^2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.60.0",
|
||||
|
||||
@@ -141,10 +141,16 @@ async function fixBetterSqliteBinary() {
|
||||
? "npm install better-sqlite3 --build-from-source --force"
|
||||
: "npm rebuild better-sqlite3";
|
||||
|
||||
const env = { ...process.env };
|
||||
if (isAndroid) {
|
||||
env.GYP_DEFINES = "android_ndk_path=''";
|
||||
}
|
||||
|
||||
execSync(rebuildCmd, {
|
||||
cwd: join(ROOT, "app"),
|
||||
stdio: "inherit",
|
||||
timeout: 300_000, // 5 minutes for source builds
|
||||
timeout: isAndroid ? 600_000 : 300_000, // ARM compilation is slower
|
||||
env,
|
||||
});
|
||||
|
||||
process.dlopen({ exports: {} }, appBinary);
|
||||
@@ -153,7 +159,8 @@ async function fixBetterSqliteBinary() {
|
||||
} catch (err) {
|
||||
const isTimeout = err.killed || err.signal === "SIGTERM";
|
||||
if (isTimeout) {
|
||||
console.warn(" ⚠️ npm rebuild timed out after 300s.");
|
||||
const secs = isAndroid ? 600 : 300;
|
||||
console.warn(` ⚠️ npm rebuild timed out after ${secs}s.`);
|
||||
} else {
|
||||
console.warn(` ⚠️ npm rebuild failed: ${err.message}`);
|
||||
}
|
||||
@@ -189,6 +196,11 @@ async function fixBetterSqliteBinary() {
|
||||
* Fixes: https://github.com/diegosouzapw/OmniRoute/issues/1634
|
||||
*/
|
||||
async function fixWreqJsBinary() {
|
||||
if (process.platform === "android") {
|
||||
console.log(" [postinstall] wreq-js: skipped on android (unsupported platform)");
|
||||
return;
|
||||
}
|
||||
|
||||
const appWreqDir = join(ROOT, "app", "node_modules", "wreq-js", "rust");
|
||||
const rootWreqDir = join(ROOT, "node_modules", "wreq-js", "rust");
|
||||
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
import { createHash, randomUUID } from "node:crypto";
|
||||
import { createRequire } from "node:module";
|
||||
import { STATUS_CODES } from "node:http";
|
||||
import { websocket } from "wreq-js";
|
||||
|
||||
const _wreqRequire = createRequire(import.meta.url);
|
||||
|
||||
let _websocketFn = null;
|
||||
let _wreqChecked = false;
|
||||
|
||||
function getWebSocketTransport() {
|
||||
if (_wreqChecked) return _websocketFn;
|
||||
_wreqChecked = true;
|
||||
try {
|
||||
const mod = _wreqRequire("wreq-js");
|
||||
_websocketFn = typeof mod.websocket === "function" ? mod.websocket : null;
|
||||
} catch {
|
||||
_websocketFn = null;
|
||||
}
|
||||
return _websocketFn;
|
||||
}
|
||||
|
||||
export const RESPONSES_WS_PUBLIC_PATHS = new Set([
|
||||
"/responses",
|
||||
@@ -562,7 +579,7 @@ export function createResponsesWsProxy({
|
||||
baseUrl,
|
||||
bridgeSecret,
|
||||
fetchImpl = fetch,
|
||||
wsFactory = websocket,
|
||||
wsFactory = getWebSocketTransport(),
|
||||
pingIntervalMs = 25000,
|
||||
idleTimeoutMs = 90000,
|
||||
maxBufferBytes = DEFAULT_MAX_WS_BUFFER_BYTES,
|
||||
@@ -583,6 +600,21 @@ export function createResponsesWsProxy({
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wsFactory) {
|
||||
writeHttpError(
|
||||
socket,
|
||||
503,
|
||||
JSON.stringify({
|
||||
error: {
|
||||
message:
|
||||
"Responses WebSocket proxy unavailable: wreq-js is not installed on this platform",
|
||||
code: "wreq_js_unavailable",
|
||||
},
|
||||
})
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
const upgradeHeader = String(req.headers.upgrade || "").toLowerCase();
|
||||
if (upgradeHeader !== "websocket") {
|
||||
writeHttpError(
|
||||
|
||||
Reference in New Issue
Block a user