cleanup, add comments, improve output

This commit is contained in:
marlon-erler
2024-07-07 18:16:28 +02:00
parent 600a86711c
commit 9a42fc047f
4 changed files with 60 additions and 47 deletions
+1
View File
@@ -18,6 +18,7 @@ export async function getConfig(): Promise<typeof defaultConfig> {
const configString = await Bun.file(configPath).text();
const configObject = JSON.parse(configString);
// validate config file
Object.keys(defaultConfig).forEach((key) => {
if (!configObject[key]) throw null;
});
+14 -10
View File
@@ -1,13 +1,13 @@
#!/usr/bin/env bun
import {
addConnection,
connectServers,
forgetConnection,
getWebSocketStats,
processMessage,
trackConnection,
} from "./websocket-handler";
import { writeInfo, writeStat, writeSuccess } from "./utility";
import { writeStatNumber, writeStatString, writeSuccess } from "./utility";
import Colors from "colors";
import IP from "ip";
@@ -16,8 +16,8 @@ import { ServerWebSocket } from "bun";
import { getConfig } from "./config-handler";
// CONFIG
const staticDir = Path.join(Path.dirname(import.meta.path), "static/dist");
const defaultPage = "index.html";
const STATIC_DIR = Path.join(Path.dirname(import.meta.path), "static/dist");
const DEFAULT_PAGE = "index.html";
// TYPES
export type WS = ServerWebSocket<unknown> | WebSocket;
@@ -39,7 +39,7 @@ async function main() {
const requestPath = new URL(request.url).pathname;
switch (requestPath) {
case "/":
return createFileResponse(defaultPage);
return createFileResponse(DEFAULT_PAGE);
case "/stats":
return new Response(JSON.stringify(getAllStats()));
default:
@@ -49,7 +49,7 @@ async function main() {
websocket: {
open(ws) {
addConnection(ws);
trackConnection(ws);
},
message(ws, message) {
processMessage(ws, message.toString(), config);
@@ -61,7 +61,7 @@ async function main() {
});
function createFileResponse(requestPath: string): Response {
const fullPath = Path.join(staticDir, requestPath);
const fullPath = Path.join(STATIC_DIR, requestPath);
return new Response(Bun.file(fullPath));
}
@@ -82,21 +82,25 @@ async function main() {
// CLI
writeSuccess(`###\nstarted up ${new Date().toLocaleString()}`);
console.log("relevant output available in the 'logs' file");
function updateCLI() {
console.clear();
console.log(Colors.bold.bgWhite("UNIVERSAL DECENTRALIZED NETWORK"));
console.log(Colors.yellow("relevant output is available in the 'logs' file"));
console.log();
console.log(new Date().toLocaleString());
console.log();
getServerStats().forEach((entry) => writeInfo(...entry));
getServerStats().forEach((entry) => writeStatString(...entry));
console.log();
getWebSocketStats().forEach((entry) => writeStatNumber(...entry));
console.log();
getWebSocketStats().forEach((entry) => writeStat(...entry));
}
setTimeout(updateCLI, 1000);
setInterval(updateCLI, 5000);
}
+11 -9
View File
@@ -3,10 +3,10 @@ import Fs from "fs/promises";
import { WebSocketMessage } from "./websocket-handler";
// CONFIG
const indent = 25;
const STAT_INDENT = 25;
// METHODS
export function guardStringNotEmpty(
// SAFETY
export function doIfIsString(
data: any,
cb: (data: string) => void
): void {
@@ -14,21 +14,23 @@ export function guardStringNotEmpty(
cb(data);
}
// writing
// OUTPUT
async function writeToLogFile(message: string): Promise<void> {
await Fs.appendFile("logs", `${message}\n`);
}
export function writeInfo(label: string, value: string): void {
console.log(`${label.padEnd(indent, " ")} ${Colors.bold.green(value)}`);
// stats
export function writeStatString(label: string, value: string): void {
console.log(`${label.padEnd(STAT_INDENT, " ")} ${Colors.bold.green(value)}`);
}
export function writeStat(label: string, value: number): void {
export function writeStatNumber(label: string, value: number): void {
console.log(
`${label.padEnd(indent, " ")} ${Colors.bold.blue(value.toString())}`
`${label.padEnd(STAT_INDENT, " ")} ${Colors.bold.blue(value.toString())}`
);
}
// logging
export function writeError(message: string): void {
console.log(Colors.bold.red(message));
writeToLogFile(message);
@@ -39,7 +41,7 @@ export function writeSuccess(message: string): void {
writeToLogFile(message);
}
// messages
// MESSAGES
export function stringifyMessage(messageObject: WebSocketMessage): string {
return JSON.stringify(messageObject);
}
+34 -28
View File
@@ -1,5 +1,5 @@
import {
guardStringNotEmpty,
doIfIsString,
parseMessage,
stringifyMessage,
writeError,
@@ -30,7 +30,7 @@ export interface WebSocketMessage {
// TRACKING
const knownMessageIds = new Set<string>();
export const subscriptions = new SubscriptionMap();
export const subscriptionMap = new SubscriptionMap();
export const clientsConnected = new Set<WS>();
export const serversConnectedAsClient = new Set<WS>();
export const serversConnected = new Set<WebSocket>();
@@ -39,28 +39,28 @@ export function getServerCount() {
return serversConnected.size + serversConnectedAsClient.size;
}
export function addConnection(ws: WS) {
export function trackConnection(ws: WS) {
clientsConnected.add(ws);
}
export function trackSubscription(ws: WS, channel: string): void {
subscriptions.set(ws, channel);
confirmSubscription(ws, channel);
}
export function removeSubscription(ws: WS, channel: string): void {
subscriptions.delete(ws, channel);
confirmSubscription(ws, channel);
}
export function forgetConnection(ws: WS): void {
clientsConnected.delete(ws);
const channels = subscriptions.getChannelList(ws);
const channels = subscriptionMap.getChannelList(ws);
channels?.forEach((channel) => {
subscriptions.delete(ws, channel);
subscriptionMap.delete(ws, channel);
});
}
export function trackSubscription(ws: WS, channel: string): void {
subscriptionMap.set(ws, channel);
confirmSubscription(ws, channel);
}
export function forgetSubscription(ws: WS, channel: string): void {
subscriptionMap.delete(ws, channel);
confirmSubscription(ws, channel);
}
// OTHER SERVERS
export function connectServers(config: typeof defaultConfig): void {
config.connectedServers.forEach((serverAddress) => {
@@ -73,9 +73,11 @@ export function connectServer(
config: typeof defaultConfig
): void {
try {
// connect
const ws = new WebSocket(address);
serversConnected.add(ws);
// listen
ws.addEventListener("open", () => {
writeSuccess(`connected to server at "${address}".`);
@@ -113,7 +115,7 @@ export function subscribeChannel(server: WS, channel: string): void {
// AUDIT
export function getWebSocketStats(): [string, number][] {
return [
["channels", subscriptions.clientsPerChannel.size],
["channels", subscriptionMap.clientsPerChannel.size],
["clients connected", clientsConnected.size],
["servers connected", getServerCount()],
];
@@ -125,27 +127,31 @@ export function processMessage(
messageString: string,
config: typeof defaultConfig
): void {
// check id
const messageObject: WebSocketMessage = parseMessage(messageString);
if (!messageObject.uuid) {
if (!messageObject.uuid) { // assign if no id
messageObject.uuid = Crypto.randomUUID();
} else {
} else { // ignore if already seen
if (knownMessageIds.has(messageObject.uuid)) return;
}
// remember message
knownMessageIds.add(messageObject.uuid);
guardStringNotEmpty(messageObject.subscribeChannel, (subscribeChannel) => {
// subscriptions
doIfIsString(messageObject.subscribeChannel, (subscribeChannel) => {
trackSubscription(ws, subscribeChannel);
});
guardStringNotEmpty(
messageObject.unsubscribeChannel,
(unsubscribeChannel) => {
removeSubscription(ws, unsubscribeChannel);
}
);
guardStringNotEmpty(messageObject.messageChannel, (messageChannel) => {
doIfIsString(messageObject.unsubscribeChannel, (unsubscribeChannel) => {
forgetSubscription(ws, unsubscribeChannel);
});
// message
doIfIsString(messageObject.messageChannel, (messageChannel) => {
if (messageObject.messageBody == undefined) return;
sendMessage(messageChannel, messageObject.messageBody, messageObject.uuid!);
});
// other server
if (messageObject.requestingServerConnection == true) {
clientsConnected.delete(ws);
serversConnectedAsClient.add(ws);
@@ -165,7 +171,7 @@ export function sendMessage(
const messageString = stringifyMessage(messageObject);
channels.forEach((channel) => {
const subscribers = subscriptions.getClientList(channel);
const subscribers = subscriptionMap.getClientList(channel);
subscribers?.forEach((ws) => ws.send(messageString));
});
}
@@ -181,7 +187,7 @@ function requestServerConnection(ws: WS): void {
function confirmSubscription(ws: WS, messageChannel: string): void {
const messageObject = {
messageChannel,
subscribed: subscriptions.getChannelList(ws) ? true : false,
subscribed: subscriptionMap.getChannelList(ws) ? true : false,
};
const messageString = stringifyMessage(messageObject);
ws.send(messageString);