Testing websocket client
This commit is contained in:
Generated
+33
-1
@@ -11,10 +11,12 @@
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/diff-match-patch": "^1.0.36",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/ws": "^8.18.1",
|
||||
"axios": "^1.13.5",
|
||||
"cors": "^2.8.6",
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"express": "^5.2.1"
|
||||
"express": "^5.2.1",
|
||||
"ws": "^8.19.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^10.0.6",
|
||||
@@ -407,6 +409,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
|
||||
@@ -4140,6 +4151,27 @@
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
||||
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
||||
"license": "MIT",
|
||||
"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
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
||||
+3
-1
@@ -91,9 +91,11 @@
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/diff-match-patch": "^1.0.36",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/ws": "^8.18.1",
|
||||
"axios": "^1.13.5",
|
||||
"cors": "^2.8.6",
|
||||
"diff-match-patch": "^1.0.5",
|
||||
"express": "^5.2.1"
|
||||
"express": "^5.2.1",
|
||||
"ws": "^8.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
+78
-37
@@ -1,16 +1,78 @@
|
||||
import axios from "axios";
|
||||
import { WebSocket } from "ws";
|
||||
import { LiveRunMove } from "./types";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
var cookies: string | undefined;
|
||||
let socket: WebSocket | null = null;
|
||||
let cookies: string | undefined;
|
||||
|
||||
type PendingResolver = {
|
||||
resolve: (value: any) => void;
|
||||
reject: (err: any) => void;
|
||||
};
|
||||
|
||||
const pending = new Map<string, PendingResolver>();
|
||||
|
||||
export function getCookies(): string | undefined {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
export function setCookies(c: string) {
|
||||
cookies = c;
|
||||
}
|
||||
function getOrigin(useLocalhost: boolean) {
|
||||
return useLocalhost ? "http://localhost:3000" : "https://dev-run.selimaj.dev";
|
||||
|
||||
function getWsOrigin(useLocalhost: boolean) {
|
||||
return useLocalhost
|
||||
? "ws://localhost:3000/api/run"
|
||||
: "wss://dev-run.selimaj.dev/api/run";
|
||||
}
|
||||
|
||||
function ensureSocket(useLocalhost: boolean): WebSocket {
|
||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||
return socket;
|
||||
}
|
||||
|
||||
socket = new WebSocket(getWsOrigin(useLocalhost));
|
||||
|
||||
socket.onmessage = (e) => {
|
||||
const msg = JSON.parse(e.data.toString());
|
||||
const { requestId, ok, data, error } = msg;
|
||||
|
||||
if (!requestId) return;
|
||||
|
||||
const pendingReq = pending.get(requestId);
|
||||
if (!pendingReq) return;
|
||||
|
||||
pending.delete(requestId);
|
||||
|
||||
ok ? pendingReq.resolve(data) : pendingReq.reject(error);
|
||||
};
|
||||
|
||||
socket.onclose = () => {
|
||||
socket = null;
|
||||
};
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
function send<T>(
|
||||
useLocalhost: boolean,
|
||||
payload: Record<string, any>,
|
||||
): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const ws = ensureSocket(useLocalhost);
|
||||
|
||||
const requestId = randomUUID();
|
||||
|
||||
pending.set(requestId, { resolve, reject });
|
||||
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
...payload,
|
||||
requestId,
|
||||
cookies, // optional: only needed if you authenticate via cookies manually
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export async function addRun(
|
||||
@@ -18,34 +80,20 @@ export async function addRun(
|
||||
problem: string,
|
||||
mode: string,
|
||||
): Promise<string> {
|
||||
return (
|
||||
await axios.put(
|
||||
getOrigin(useLocalhost) + "/api/run",
|
||||
{
|
||||
const data = await send<{ runId: string }>(useLocalhost, {
|
||||
type: "create",
|
||||
problem,
|
||||
category: mode,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: cookies,
|
||||
},
|
||||
},
|
||||
)
|
||||
).data.runId;
|
||||
});
|
||||
|
||||
return data.runId;
|
||||
}
|
||||
|
||||
export async function submitRun(useLocalhost: boolean, runId: string) {
|
||||
await axios.post(
|
||||
getOrigin(useLocalhost) + "/api/run",
|
||||
{
|
||||
await send(useLocalhost, {
|
||||
type: "submit",
|
||||
runId,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: cookies,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export async function addRunMoves(
|
||||
@@ -55,18 +103,11 @@ export async function addRunMoves(
|
||||
language: string | null,
|
||||
moves: LiveRunMove[],
|
||||
) {
|
||||
await axios.post(
|
||||
getOrigin(useLocalhost) + "/api/run/move",
|
||||
{
|
||||
await send(useLocalhost, {
|
||||
type: "move",
|
||||
runId,
|
||||
file,
|
||||
moves,
|
||||
language,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Cookie: cookies,
|
||||
},
|
||||
},
|
||||
);
|
||||
moves,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user