mirror of
https://github.com/tale/headplane.git
synced 2026-08-12 22:56:53 +00:00
feat: respect context in server
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
export function hpServer_loadLogger(debug: boolean) {
|
||||
if (debug) {
|
||||
log.debug = (category: string, message: string, ...args: unknown[]) => {
|
||||
defaultLog('DEBG', category, message, ...args);
|
||||
};
|
||||
|
||||
log.info('CFGX', 'Debug logging enabled');
|
||||
log.info(
|
||||
'CFGX',
|
||||
'This is very verbose and should only be used for debugging purposes',
|
||||
);
|
||||
log.info(
|
||||
'CFGX',
|
||||
'If you run this in production, your storage COULD fill up quickly',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const log = {
|
||||
info: (category: string, message: string, ...args: unknown[]) => {
|
||||
defaultLog('INFO', category, message, ...args);
|
||||
},
|
||||
|
||||
warn: (category: string, message: string, ...args: unknown[]) => {
|
||||
defaultLog('WARN', category, message, ...args);
|
||||
},
|
||||
|
||||
error: (category: string, message: string, ...args: unknown[]) => {
|
||||
defaultLog('ERRO', category, message, ...args);
|
||||
},
|
||||
|
||||
debug: (category: string, message: string, ...args: unknown[]) => {},
|
||||
};
|
||||
|
||||
function defaultLog(
|
||||
level: string,
|
||||
category: string,
|
||||
message: string,
|
||||
...args: unknown[]
|
||||
) {
|
||||
const date = new Date().toISOString();
|
||||
console.log(`${date} (${level}) [${category}] ${message}`, ...args);
|
||||
}
|
||||
|
||||
export default log;
|
||||
@@ -0,0 +1,32 @@
|
||||
class Mutex {
|
||||
private locked = false;
|
||||
private queue: (() => void)[] = [];
|
||||
|
||||
constructor(locked: boolean) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
acquire() {
|
||||
return new Promise<void>((resolve) => {
|
||||
if (!this.locked) {
|
||||
this.locked = true;
|
||||
resolve();
|
||||
} else {
|
||||
this.queue.push(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
release() {
|
||||
if (this.queue.length > 0) {
|
||||
const next = this.queue.shift();
|
||||
next?.();
|
||||
} else {
|
||||
this.locked = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function mutex(locked = false) {
|
||||
return new Mutex(locked);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import WebSocket, { WebSocketServer } from 'ws';
|
||||
import log from '~server/utils/log';
|
||||
|
||||
const server = new WebSocketServer({ noServer: true });
|
||||
export function initWebsocket() {
|
||||
// TODO: Finish this and make public
|
||||
return;
|
||||
|
||||
const key = process.env.LOCAL_AGENT_AUTHKEY;
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info('CACH', 'Initializing agent WebSocket');
|
||||
server.on('connection', (ws, req) => {
|
||||
// biome-ignore lint: this file is not USED
|
||||
const auth = req.headers['authorization'];
|
||||
if (auth !== `Bearer ${key}`) {
|
||||
log.warn('CACH', 'Invalid agent WebSocket connection');
|
||||
ws.close(1008, 'ERR_INVALID_AUTH');
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeID = req.headers['x-headplane-ts-node-id'];
|
||||
if (!nodeID) {
|
||||
log.warn('CACH', 'Invalid agent WebSocket connection');
|
||||
ws.close(1008, 'ERR_INVALID_NODE_ID');
|
||||
return;
|
||||
}
|
||||
|
||||
const pinger = setInterval(() => {
|
||||
if (ws.readyState !== WebSocket.OPEN) {
|
||||
clearInterval(pinger);
|
||||
return;
|
||||
}
|
||||
|
||||
ws.ping();
|
||||
}, 30000);
|
||||
|
||||
ws.on('close', () => {
|
||||
clearInterval(pinger);
|
||||
});
|
||||
|
||||
ws.on('error', (error) => {
|
||||
clearInterval(pinger);
|
||||
log.error('CACH', 'Closing agent WebSocket connection');
|
||||
log.error('CACH', 'Agent WebSocket error: %s', error);
|
||||
ws.close(1011, 'ERR_INTERNAL_ERROR');
|
||||
});
|
||||
});
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
export function appContext() {
|
||||
return {
|
||||
ws: server,
|
||||
wsAuthKey: process.env.LOCAL_AGENT_AUTHKEY,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user