getting things going

This commit is contained in:
metacryst
2026-01-29 08:20:27 -06:00
parent c09b08a474
commit 6d50337e3b
9 changed files with 377 additions and 2 deletions

View File

@@ -0,0 +1,38 @@
const IS_NODE =
typeof process !== "undefined" &&
process.versions?.node != null
async function bridgeSend(name, args) {
// Example browser implementation: send function call to server
const res = await global.Socket.send({
name: name,
args: args
})
const json = await res.json()
if (!res.ok) throw new Error(json.error)
return json.result
}
/**
* Wraps an object of functions so that:
* - Node calls the real function
* - Browser calls bridgeSend
*/
export function createBridge(funcs) {
return new Proxy(funcs, {
get(target, prop) {
const orig = target[prop]
if (typeof orig !== "function") return orig
return function (...args) {
if (IS_NODE) {
return orig(...args)
} else {
return bridgeSend(prop, args)
}
}
}
})
}

View File

@@ -0,0 +1,11 @@
import fs from "fs"
import { createBridge } from "./bridge.js"
const handlers = {
getProfile(one, two) {
fs.writeFileSync("output.txt", `${one} ${two}`)
return "written to disk"
},
}
export const { getProfile } = createBridge(handlers)

View File

@@ -0,0 +1,61 @@
class Connection {
connectionTries = 0;
ws;
receiveCB;
constructor(receiveCB) {
this.receiveCB = receiveCB;
}
init = async () => {
return new Promise((resolve, reject) => {
const url = window.location.hostname.includes("local")
? "ws://" + window.location.host
: "wss://" + window.location.hostname + window.location.pathname;
this.ws = new WebSocket(url);
this.ws.addEventListener('open', () => {
this.connectionTries = 0;
console.log("WebSocket connection established.");
this.ws.addEventListener('message', this.receiveCB);
resolve(this.ws); // resolve when open
});
this.ws.addEventListener('close', () => {
console.log('WebSocket closed');
this.checkOpen(); // attempt reconnection
});
this.ws.addEventListener('error', (err) => {
console.error('WebSocket error', err);
reject(err); // reject if error occurs
});
});
}
checkOpen = async () => {
if (this.ws.readyState === WebSocket.OPEN) {
return true;
} else {
await this.sleep(this.connectionTries < 20 ? 5000 : 60000);
this.connectionTries++;
console.log('Reestablishing connection');
await this.init();
}
}
sleep = (time) => new Promise(resolve => setTimeout(resolve, time));
send = (msg) => {
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(msg);
} else if (this.connectionTries === 0) {
setTimeout(() => this.send(msg), 100);
} else {
console.error('No WebSocket connection: Cannot send message');
}
}
}
export default Connection;

49
src/_/code/ws/Socket.js Normal file
View File

@@ -0,0 +1,49 @@
import Connection from "./Connection.js";
export default class Socket {
connection;
disabled = true;
requestID = 1;
pending = new Map();
constructor() {
this.connection = new Connection(this.receive);
}
async init() {
await this.connection.init()
}
isOpen() {
if(this.connection.checkOpen()) {
return true;
} else {
return false;
}
}
send(msg) {
return new Promise(resolve => {
const id = (++this.requestID).toString();
this.pending.set(id, resolve);
this.connection.send(JSON.stringify({ id, ...msg }));
});
}
receive = (event) => {
const msg = JSON.parse(event.data);
if (msg.id && this.pending.has(msg.id)) {
this.pending.get(msg.id)(msg);
this.pending.delete(msg.id);
return;
} else {
this.onBroadcast(msg)
}
}
onBroadcast(msg) {
window.dispatchEvent(new CustomEvent(msg.event, {
detail: msg.msg
}));
}
}

1
src/_/code/ws/shim/fs.js Normal file
View File

@@ -0,0 +1 @@
export default {}