summary refs log tree commit diff
path: root/slowcord/status/src/index.ts
blob: 112986993c379ab99a18a722237db3af56eda7ee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import "dotenv/config";
import https from "https";
import Fosscord from "fosscord-gopnik";
import mysql from "mysql2";

const dbConn = mysql.createConnection(process.env.DATABASE as string);
const executePromise = (sql: string, args: any[]) => new Promise((resolve, reject) => dbConn.execute(sql, args, (err, res) => { if (err) reject(err); else resolve(res); }));

const instance = {
	app: process.env.INSTANCE_WEB_APP as string,
	api: process.env.INSTANCE_API as string,
	cdn: process.env.INSTANCE_CDN as string,
	token: process.env.INSTANCE_TOKEN as string,
};

const client = new Fosscord.Client({
	intents: [],
	http: {
		api: instance.api,
		cdn: instance.cdn
	}
});

const gatewayMeasure = async (name: string) => {
	const time = Math.max(client.ws.ping, 0);
	await savePerf(time, name, '');
	console.log(`${name} took ${time}ms`);
};

client.on("ready", () => {
	console.log(`Ready on gateway as ${client.user!.tag}`);
});

client.on("error", (error) => {
	console.log(`Gateway error`, error);
});

client.on("warn", (msg) => {
	console.log(`Gateway warning:`, msg);
});

const savePerf = async (time: number, name: string, error?: string | Error) => {
	if (error && typeof error != "string") error = error.message;
	try {
		await executePromise("INSERT INTO performance (value, endpoint, timestamp, error) VALUES (?, ?, ?, ?)", [time ?? 0, name, new Date(), error ?? null]);
		await executePromise("DELETE FROM performance WHERE DATE(timestamp) < now() - interval ? DAY", [process.env.RETENTION_DAYS]);
	}
	catch (e) {
		console.error(e);
	}
};

const makeTimedRequest = (path: string, body?: object): Promise<number> => new Promise((resolve, reject) => {
	const opts = {
		hostname: new URL(path).hostname,
		port: 443,
		path: new URL(path).pathname,
		method: "GET",
		headers: {
			"Content-Type": "application/json",
			"Authorization": instance.token,
		},
		timeout: 1000,
	};

	let start: number, end: number;
	const req = https.request(opts, res => {
		if (res.statusCode! < 200 || res.statusCode! > 300) {
			return reject(`${res.statusCode} ${res.statusMessage}`);
		}

		res.on("data", (data) => {
		});

		res.on("end", () => {
			end = Date.now();
			resolve(end - start);
		})
	});

	req.on("finish", () => {
		if (body) req.write(JSON.stringify(body));
		start = Date.now();
	});

	req.on("error", (error) => {
		reject(error);
	});

	req.end();
});

const measureApi = async (name: string, path: string, body?: object) => {
	let error, time = -1;
	try {
		time = await makeTimedRequest(path, body);
	}
	catch (e) {
		error = e as Error | string;
	}

	console.log(`${name} took ${time}ms ${(error ? "with error" : "")}`, error ?? "");

	await savePerf(time, name, error);
};

const app = async () => {
	await new Promise((resolve) => dbConn.connect(resolve));
	console.log("Connected to db");
	// await client.login(instance.token);

	console.log(`Monitoring performance for instance at ${new URL(instance.api).hostname}`);

	const doMeasurements = async () => {
		await measureApi("ping", `${instance.api}/ping`);
		await measureApi("users/@me", `${instance.api}/users/@me`);
		await measureApi("login", `${instance.app}/login`);
		// await gatewayMeasure("websocketPing");

		setTimeout(doMeasurements, parseInt(process.env.MEASURE_INTERVAL as string));
	};

	doMeasurements();
};

app();