prettierrc, websockets, fix in frontend

Summary: Ref T2992

Reviewers: kuba-orlik

Reviewed By: kuba-orlik

Subscribers: kuba-orlik

Maniphest Tasks: T2992

Differential Revision: https://hub.sealcode.org/D1570
This commit is contained in:
migueldar 2025-01-29 15:00:28 +01:00
parent 40cb7397b0
commit ff7e32a3d5
14 changed files with 221 additions and 164 deletions

28
.prettierrc Normal file
View File

@ -0,0 +1,28 @@
{
"useTabs": true,
"tabWidth": 4,
"trailingComma": "es5",
"overrides": [
{
"files": "*.yml",
"options": {
"tabWidth": 2,
"useTabs": false
}
},
{
"files": "*.html",
"options": {
"tabWidth": 2,
"useTabs": false
}
},
{
"files": "*.json",
"options": {
"tabWidth": 2,
"useTabs": false
}
}
]
}

View File

@ -1,55 +0,0 @@
const net = require("net");
const child_process = require("child_process");
const fs = require("fs");
const server = net.createServer();
async function spawnPromise(program, args) {
return new Promise((resolve, reject) => {
const process = child_process.spawn(program, args);
process.on("close", (_) => {
resolve();
});
});
}
//maybe check output of child processe and send errors in some way
server.on("connection", (socket) => {
socket.on("data", async (dataBuf) => {
data = dataBuf.toString();
if (data === "screenshot") {
socket.write("start");
await spawnPromise("bash", ["/conf/screenshot.sh"]);
socket.write(fs.readFileSync("/screenshot.png"));
socket.write("ENDOFMSG");
} else if (data.includes("touch")) {
const dataSplit = data.split(" ");
await spawnPromise("bash", [
"/conf/touch.sh",
dataSplit[1],
dataSplit[2],
]);
} else if (data === "back") {
await spawnPromise("bash", ["/conf/back.sh"]);
} else if (data === "home") {
await spawnPromise("bash", ["/conf/home.sh"]);
} else if (data.includes("drag")) {
const dataSplit = data.split(" ");
await spawnPromise("bash", [
"/conf/drag.sh",
dataSplit[1],
dataSplit[2],
dataSplit[3],
dataSplit[4],
]);
}
});
socket.on("close", (_) => {
socket.end();
});
});
server.listen(3000, () => {
console.log("listening on 3000");
});

49
android/code/index.mjs Normal file
View File

@ -0,0 +1,49 @@
import { WebSocketServer } from "ws";
import child_process from "child_process";
import fs from "fs";
async function spawnPromise(program, args) {
return new Promise((resolve, reject) => {
const process = child_process.spawn(program, args);
process.on("close", (_) => {
resolve();
});
});
}
const wss = new WebSocketServer({ port: 3000 });
//maybe check output of child processes and send errors in some way
wss.on("connection", (ws) => {
ws.on("message", async (dataBuf) => {
let data = dataBuf.toString();
if (data === "screenshot") {
await spawnPromise("bash", ["/conf/screenshot.sh"]);
ws.send(fs.readFileSync("/screenshot.png"));
} else if (data.includes("touch")) {
const dataSplit = data.split(" ");
await spawnPromise("bash", [
"/conf/touch.sh",
dataSplit[1],
dataSplit[2],
]);
} else if (data === "back") {
await spawnPromise("bash", ["/conf/back.sh"]);
} else if (data === "home") {
await spawnPromise("bash", ["/conf/home.sh"]);
} else if (data.includes("drag")) {
const dataSplit = data.split(" ");
await spawnPromise("bash", [
"/conf/drag.sh",
dataSplit[1],
dataSplit[2],
dataSplit[3],
dataSplit[4],
]);
}
});
ws.on("close", (_) => {
ws.close();
});
});

View File

@ -5,20 +5,36 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"net": "^1.0.2" "ws": "^8.18.0"
} }
}, },
"node_modules/net": { "node_modules/ws": {
"version": "1.0.2", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ==" "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
} }
}, },
"dependencies": { "dependencies": {
"net": { "ws": {
"version": "1.0.2", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ==" "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"requires": {}
} }
} }
} }

View File

@ -1,5 +1,5 @@
{ {
"dependencies": { "dependencies": {
"net": "^1.0.2" "ws": "^8.18.0"
} }
} }

View File

@ -3,6 +3,6 @@ npm i -C /code
bash /conf/iptables_conf.sh bash /conf/iptables_conf.sh
redsocks -c /conf/redsocks.conf & redsocks -c /conf/redsocks.conf &
bash /conf/wait_for_sd.sh bash /conf/wait_for_sd.sh
node /code/index.js node /code/index.mjs
#tail -f /dev/null #tail -f /dev/null

View File

@ -36,7 +36,7 @@ RENTGEN_ANDROID docker structure
| :3000 | | :3000 |
+---------------------------------+--------------------+ +---------------------------------+--------------------+
| |
| SOCKETS | WEBSOCKETS
| |
+---------------------------------+--------------------+ +---------------------------------+--------------------+
| HTTP_SERVER | | | HTTP_SERVER | |

View File

@ -131,7 +131,7 @@
let startDraggingPosY = 0; let startDraggingPosY = 0;
let endDraggingPosY = 0; let endDraggingPosY = 0;
const screenSize = [320, 640] const screenSize = [320, 640];
const handleDraggStart = (e) => { const handleDraggStart = (e) => {
e.preventDefault(); e.preventDefault();
@ -146,15 +146,16 @@
endDraggingPosX = e.offsetX; endDraggingPosX = e.offsetX;
endDraggingPosY = e.offsetY; endDraggingPosY = e.offsetY;
if ( if (
isDragging && (Math.abs(endDraggingPosY - startDraggingPosY) > 10 || isDragging &&
Math.abs(endDraggingPosX - startDraggingPosX) > 10) (Math.abs(endDraggingPosY - startDraggingPosY) > 10 ||
Math.abs(endDraggingPosX - startDraggingPosX) > 10)
) { ) {
registerClick({ registerClick({
path: "drag", path: "drag",
logText: `await drag({x:${startDraggingPosX},y:${startDraggingPosY}},{x:${e.offsetX},y:${e.offsetY}});`, logText: `await drag({x:${startDraggingPosX},y:${startDraggingPosY}},{x:${e.offsetX},y:${e.offsetY}});`,
body: `startX=${startDraggingPosX}&startY=${startDraggingPosY}&endX=${e.offsetX}&endY=${e.offsetY}`, body: `startX=${startDraggingPosX}&startY=${startDraggingPosY}&endX=${e.offsetX}&endY=${e.offsetY}`,
}); });
} else { } else if (e.target === screen) {
const phoneX = event.offsetX; const phoneX = event.offsetX;
const phoneY = event.offsetY; const phoneY = event.offsetY;
if (phoneX <= screenSize[0] && phoneY <= screenSize[1]) if (phoneX <= screenSize[0] && phoneY <= screenSize[1])

View File

@ -1,6 +1,10 @@
import express from "express"; import express from "express";
import { readFile } from "node:fs/promises"; import { readFile } from "node:fs/promises";
import { guardedScreenshot, socket_client, waitFullBoot } from "./screenshot.mjs"; import {
guardedScreenshot,
android_websocket,
waitFullBoot,
} from "./screenshot.mjs";
const device_size_x = 320; const device_size_x = 320;
const device_size_y = 640; const device_size_y = 640;
@ -14,69 +18,70 @@ console.log("Boot detected! activating endpoints");
//GET //GET
app.get("/favicon.ico", function (req, res) { app.get("/favicon.ico", function (req, res) {
res.sendFile("/code/favicon.ico"); res.sendFile("/code/favicon.ico");
}); });
app.get("/trafficLog.js", function (req, res) { app.get("/trafficLog.js", function (req, res) {
res.sendFile("/code/dist/trafficLog.js"); res.sendFile("/code/dist/trafficLog.js");
}); });
app.get("/trafficLog", async function (req, res) { app.get("/trafficLog", async function (req, res) {
res.sendFile("/log/trafficLog"); res.sendFile("/log/trafficLog");
}); });
app.get("/screen", async function (req, res) { app.get("/screen", async function (req, res) {
await guardedScreenshot(); await guardedScreenshot();
res.sendFile("/code/screenshot.png"); res.sendFile("/code/screenshot.png");
}); });
app.get("/", async function (req, res) { app.get("/", async function (req, res) {
let fileData = (await readFile("/code/index.html")).toString(); let fileData = (await readFile("/code/index.html")).toString();
fileData = fileData.replace( fileData = fileData.replace(
"___screenshotDelayMs___", "___screenshotDelayMs___",
process.env.screenshotDelayMs process.env.screenshotDelayMs
); );
res.setHeader("Content-Type", "text/html"); res.setHeader("Content-Type", "text/html");
res.setHeader("Content-Disposition", "inline"); res.setHeader("Content-Disposition", "inline");
res.send(fileData); res.send(fileData);
}); });
//POST //POST
app.post("/back", function (req, res) { app.post("/back", function (req, res) {
socket_client.write(`back`); android_websocket.send(`back`);
res.sendStatus(200); res.sendStatus(200);
}); });
app.post("/home", function (req, res) { app.post("/home", function (req, res) {
socket_client.write(`home`); android_websocket.send(`home`);
res.sendStatus(200); res.sendStatus(200);
}); });
app.post("/touch", function (req, res) { app.post("/touch", function (req, res) {
const x = parseInt(req.body.x); const x = parseInt(req.body.x);
const y = parseInt(req.body.y); const y = parseInt(req.body.y);
if (isNaN(x) || isNaN(y) || x > device_size_x || y > device_size_y) { if (isNaN(x) || isNaN(y) || x > device_size_x || y > device_size_y) {
res.send( res.send(
`the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n` `the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n`
); );
} else { } else {
socket_client.write(`touch ${x} ${y}`); android_websocket.send(`touch ${x} ${y}`);
res.sendStatus(200); res.sendStatus(200);
} }
}); });
app.post("/drag", function (req, res) { app.post("/drag", function (req, res) {
const body = req.body; const body = req.body;
const startX = Number(body.startX); const startX = Number(body.startX);
const startY = Number(body.startY); const startY = Number(body.startY);
const endX = Number(body.endX); const endX = Number(body.endX);
const endY = Number(body.endY); const endY = Number(body.endY);
socket_client.write(`drag ${startX} ${startY} ${endX} ${endY}`); android_websocket.send(`drag ${startX} ${startY} ${endX} ${endY}`);
res.sendStatus(200); res.sendStatus(200);
}); });
app.listen(8080, () => console.log("Listening in port 8080")); app.listen(8080, () => console.log("Listening in port 8080"));

View File

@ -6,8 +6,8 @@
"": { "": {
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"net": "^1.0.2", "preact": "^10.18.1",
"preact": "^10.18.1" "ws": "^8.18.0"
}, },
"devDependencies": { "devDependencies": {
"esbuild": "^0.19.5" "esbuild": "^0.19.5"
@ -774,11 +774,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/net": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/net/-/net-1.0.2.tgz",
"integrity": "sha512-kbhcj2SVVR4caaVnGLJKmlk2+f+oLkjqdKeQlmUtz6nGzOpbcobwVIeSURNgraV/v3tlmGIX82OcPCl0K6RbHQ=="
},
"node_modules/object-inspect": { "node_modules/object-inspect": {
"version": "1.12.3", "version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
@ -1003,6 +998,26 @@
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
},
"node_modules/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
} }
} }
} }

View File

@ -4,8 +4,8 @@
}, },
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"net": "^1.0.2", "preact": "^10.18.1",
"preact": "^10.18.1" "ws": "^8.18.0"
}, },
"devDependencies": { "devDependencies": {
"esbuild": "^0.19.5" "esbuild": "^0.19.5"

View File

@ -1,62 +1,60 @@
import net from "net";
import fs from "fs"; import fs from "fs";
import { sleep } from "./utils.mjs"; import { sleep } from "./utils.mjs";
import { WebSocket } from "ws";
export const socket_client = net.createConnection({ port: 3000, host: "android" }); export const android_websocket = new WebSocket("ws://android:3000");
let doneWrite = 0; let doneWrite = 0;
let screenshotPromise = null; let screenshotPromise = null;
async function screenshot() { async function screenshot() {
const time_start = Date.now(); const time_start = Date.now();
socket_client.write("screenshot"); while (android_websocket.readyState != WebSocket.OPEN) {
while (!doneWrite) { await sleep(15);
await sleep(15); }
if (Date.now() - time_start > 2000) { android_websocket.send("screenshot");
console.error("Screenshot timed out after 2s"); while (!doneWrite) {
break; // timeout await sleep(15);
} if (Date.now() - time_start > 2000) {
} console.error("Screenshot timed out after 2s");
doneWrite = 0; break; // timeout
screenshotPromise = null; }
}
doneWrite = 0;
screenshotPromise = null;
} }
export async function guardedScreenshot() { export async function guardedScreenshot() {
console.log("Requesting a screenshot"); if (!screenshotPromise) {
if (!screenshotPromise) { screenshotPromise = screenshot();
console.log("no ongoing promise, starting a new one"); } else {
screenshotPromise = screenshot(); console.log("ongoing screenshot promise not taking a new one");
} }
return screenshotPromise; return screenshotPromise;
} }
export async function waitFullBoot() { export async function waitFullBoot() {
var start = performance.now(); var start = performance.now();
var counter = 0; var counter = 0;
//will timeout after 10 min //will timeout after 10 min
while (performance.now() - start < 600 * 1000) { while (performance.now() - start < 600 * 1000) {
var before = performance.now(); var before = performance.now();
await screenshot(); await screenshot();
var after = performance.now(); var after = performance.now();
if (after - before < process.env.screenshotDelayMs) counter++; if (after - before < process.env.screenshotDelayMs) counter++;
else counter = 0; else counter = 0;
if (counter === 10) return; if (counter === 10) return;
} }
throw new Error("wait for screenshot time to be less than 0.5s timed out"); throw new Error("wait for screenshot time to be less than 0.5s timed out");
} }
let fd; android_websocket.on("message", (dataBuf) => {
socket_client.on("data", (dataBuf) => { let fd;
if (dataBuf.toString() === "start") fd = fs.openSync("/code/screenshot.png", "w");
fd = fs.openSync("/code/screenshot.png", "w"); fs.writeSync(fd, dataBuf);
else { fs.close(fd);
if (dataBuf.toString().includes("ENDOFMSG")) { doneWrite = 1;
fs.writeSync(fd, dataBuf); });
fs.close(fd);
doneWrite = 1;
} else fs.writeSync(fd, dataBuf);
}
});

View File

@ -1,3 +1,3 @@
export async function sleep(time) { export async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time)); return new Promise((resolve) => setTimeout(resolve, time));
} }

View File

@ -1,14 +1,14 @@
import net from "net";
import { exit } from "process"; import { exit } from "process";
import { WebSocket } from "ws";
async function sleep(time) { async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time)); return new Promise((resolve) => setTimeout(resolve, time));
} }
while (true) { while (true) {
let socket = net.createConnection({ port: 3000, host: "android" }); let socket = new WebSocket("ws://android:3000");
socket.on("connect", () => { socket.on("open", () => {
exit(0); exit(0);
}); });
socket.on("error", () => {}); socket.on("error", () => {});