-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
147 lines (121 loc) · 3.69 KB
/
index.ts
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import { isIPInRangeOrPrivate } from "range_check";
import config from "./config.ts";
import fs from "fs";
import path from "path";
import pkg from "./package.json";
if (!fs.existsSync(path.resolve(__dirname, config.logFolder))) {
fs.mkdirSync(path.resolve(__dirname, config.logFolder));
}
let calculateLogName = () => {
return `${config.logFolder}/${new Date().toISOString().split("T")[0]}-${
config.whoami
}.log`;
};
let logStream = fs.createWriteStream(
path.resolve(__dirname, calculateLogName()),
{
flags: "a", // 'a' means appending (old data will be preserved)
}
);
initLogMessage(logStream);
function initLogMessage(logStream: fs.WriteStream) {
let nodeInfo = config.nodes
.map((node) => `${node.name}:${node.ip}:${node.port}`)
.join("!");
logStream.write(
`---\n${pkg.logVersion}|${new Date().toISOString()}|${
config.offlineThreshold
}|${config.whoami}|${nodeInfo}\n`
);
}
function writeNodeLog(
logStream: fs.WriteStream,
nodeName: string,
timeouts: number
) {
logStream.write(`${new Date().toISOString()}|${nodeName}|${timeouts}\n`);
}
function resetLogStream() {
logStream.end();
logStream = fs.createWriteStream(
path.resolve(__dirname, calculateLogName()),
{
flags: "a", // 'a' means appending (old data will be preserved)
}
);
initLogMessage(logStream);
}
interface NodeStatus {
timeouts: number;
online: boolean;
}
const nodeStatus: Record<string, NodeStatus> = {};
for (const node of config.nodes) {
nodeStatus[node.name] = { timeouts: 0, online: true };
}
function handleTimeout(node: string) {
nodeStatus[node].timeouts += 1;
if (nodeStatus[node].timeouts >= config.offlineThreshold) {
if (nodeStatus[node].online) {
console.error(`Node ${node} marked as offline`);
writeNodeLog(logStream, node, config.offlineThreshold);
}
nodeStatus[node].online = false;
console.log("Nodes status:");
} else {
writeNodeLog(logStream, node, nodeStatus[node].timeouts);
}
}
setInterval(async () => {
for (const node of config.nodes) {
if (node.name === config.whoami) {
continue;
}
console.log(`Pinging ${node.name} on port ${node.port}`);
const controller = new AbortController();
const nodeTimeoutTimer = setTimeout(() => {
console.error(`Request to ${node.name} timed out`);
controller.abort();
handleTimeout(node.name);
}, config.timeout);
try {
await fetch(`http://${node.ip}:${node.port}`, {
signal: controller.signal,
});
console.log(`Successfully pinged ${node.name}`);
if (!nodeStatus[node.name].online) {
console.log(`Node ${node.name} marked as online`);
}
if (nodeStatus[node.name].timeouts !== 0) {
writeNodeLog(logStream, node.name, 0);
}
nodeStatus[node.name].timeouts = 0;
nodeStatus[node.name].online = true;
} catch (err: any) {
if (err.name === "AbortError") {
continue;
}
console.error(`Error pinging ${node.name}: ${err}`);
handleTimeout(node.name);
} finally {
clearTimeout(nodeTimeoutTimer);
}
}
console.table(nodeStatus);
}, config.interval);
Bun.serve({
port: config.nodes.find((node) => node.name === config.whoami)!.port,
fetch(req, server) {
const ip = server.requestIP(req)?.address;
if (!ip) throw new Error("IP address cannot be determined");
if (isIPInRangeOrPrivate(ip)) return new Response("hello world");
if (!config.nodes.find((node) => node.ip === ip))
return new Response("Unauthorized", { status: 401 });
return new Response("still online");
},
});
console.log(
`Serving on port ${
config.nodes.find((node) => node.name === config.whoami)!.port
}`
);