forked from VinokurovVE/tests
Map update
This commit is contained in:
0
monitor/.env.example
Normal file
0
monitor/.env.example
Normal file
279
monitor/index.ts
279
monitor/index.ts
@ -1,5 +1,6 @@
|
||||
import { serve } from 'bun';
|
||||
import { Database } from 'bun:sqlite';
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
const db = new Database('./data/servers.db');
|
||||
|
||||
@ -8,41 +9,157 @@ db.run(`
|
||||
CREATE TABLE IF NOT EXISTS servers (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
ip TEXT NOT NULL,
|
||||
ping_rate INTEGER NOT NULL
|
||||
hostname TEXT NOT NULL,
|
||||
port INTEGER NOT NULL,
|
||||
ping_rate INTEGER NOT NULL,
|
||||
status TEXT DEFAULT 'unknown',
|
||||
monitoring INTEGER DEFAULT 1
|
||||
)
|
||||
`);
|
||||
|
||||
// Function to check server availability
|
||||
async function checkServer(server: { name: string; ip: string; ping_rate: number; }) {
|
||||
try {
|
||||
const response = await Bun.spawn(['ping', '-c', '1', server.ip]);
|
||||
if (response.exitCode === 0) {
|
||||
console.log(`[${new Date().toISOString()}] ${server.name} (${server.ip}) is up.`);
|
||||
} else {
|
||||
console.error(`[${new Date().toISOString()}] ${server.name} (${server.ip}) is down!`);
|
||||
// In-memory state to store server details
|
||||
const serverStates: {
|
||||
[id: number]: {
|
||||
id: number;
|
||||
name: string;
|
||||
hostname: string;
|
||||
port: number;
|
||||
ping_rate: number;
|
||||
status: 'up' | 'down' | 'unknown';
|
||||
monitoring: number;
|
||||
}
|
||||
} = {};
|
||||
|
||||
// Event emitter to handle server updates
|
||||
const serverMonitor = new EventEmitter();
|
||||
const clients: Set<ReadableStreamDefaultController> = new Set()
|
||||
|
||||
class ServerState {
|
||||
id: number | undefined;
|
||||
name: string | undefined;
|
||||
hostname: string | undefined;
|
||||
port: number | undefined;
|
||||
ping_rate: number | undefined;
|
||||
status: 'up' | 'down' | 'unknown' | undefined;
|
||||
monitoring: number | undefined;
|
||||
}
|
||||
|
||||
// Function to initialize server states from the database
|
||||
async function initializeServerStates() {
|
||||
const servers = db.query('SELECT * FROM servers').as(ServerState).all();
|
||||
servers.forEach((server: ServerState) => {
|
||||
if (server.id && server.name && server.hostname && server.port && server.ping_rate && server.status) {
|
||||
serverStates[server.id] = {
|
||||
id: server.id,
|
||||
name: server.name,
|
||||
hostname: server.hostname,
|
||||
port: server.port,
|
||||
ping_rate: server.ping_rate,
|
||||
status: server.status,
|
||||
monitoring: server.monitoring || 0
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`[${new Date().toISOString()}] Error pinging ${server.name} (${server.ip}):`, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function to monitor servers based on their individual ping rates
|
||||
async function monitorServer(server: any) {
|
||||
// Start monitoring for a specific server by its ID
|
||||
async function monitorServer(serverId: number) {
|
||||
if (!serverStates[serverId]) return
|
||||
|
||||
while (true) {
|
||||
await checkServer(server);
|
||||
await new Promise(resolve => setTimeout(resolve, server.ping_rate));
|
||||
if (serverStates[serverId]) {
|
||||
await checkServer(serverId);
|
||||
await new Promise(resolve => setTimeout(resolve, serverStates[serverId].ping_rate * 1000));
|
||||
} else {
|
||||
console.log("Stopped monitoring ", serverId)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start monitoring all servers
|
||||
async function startMonitoring() {
|
||||
const servers = db.query(`SELECT * FROM servers`).all();
|
||||
servers.forEach(server => monitorServer(server));
|
||||
// Function to check the server availability
|
||||
async function checkServer(serverId: number) {
|
||||
const server = serverStates[serverId];
|
||||
if (!server) return;
|
||||
if (server.monitoring === 0) return
|
||||
|
||||
try {
|
||||
const checkSocket = await Bun.connect({
|
||||
hostname: server.hostname,
|
||||
port: server.port,
|
||||
socket: {
|
||||
data(socket, data) { },
|
||||
open(socket) {
|
||||
console.log(`[${new Date().toISOString()}] ${server.name} (${server.hostname}:${server.port}) is up.`);
|
||||
|
||||
if (serverStates[serverId].status !== 'up') {
|
||||
db.run('UPDATE servers SET status = ? WHERE id = ?', ['up', serverId]);
|
||||
serverStates[serverId].status = 'up';
|
||||
notifyClients()
|
||||
}
|
||||
socket.end();
|
||||
},
|
||||
connectError(socket, error) {
|
||||
console.error(`[${new Date().toISOString()}] ${server.name} (${server.hostname}:${server.port}) is down!`);
|
||||
|
||||
if (serverStates[serverId].status !== 'down') {
|
||||
db.run('UPDATE servers SET status = ? WHERE id = ?', ['down', serverId]);
|
||||
serverStates[serverId].status = 'down';
|
||||
notifyClients()
|
||||
}
|
||||
},
|
||||
error(socket, error) {
|
||||
console.error(`[${new Date().toISOString()}] Error connecting to ${server.name} (${server.hostname}:${server.port}):`, error);
|
||||
|
||||
if (serverStates[serverId].status !== 'down') {
|
||||
db.run('UPDATE servers SET status = ? WHERE id = ?', ['down', serverId]);
|
||||
serverStates[serverId].status = 'down';
|
||||
notifyClients()
|
||||
}
|
||||
},
|
||||
timeout(socket) {
|
||||
console.error(`[${new Date().toISOString()}] Connection to ${server.name} (${server.hostname}:${server.port}) timed out!`);
|
||||
|
||||
if (serverStates[serverId].status !== 'down') {
|
||||
db.run('UPDATE servers SET status = ? WHERE id = ?', ['down', serverId]);
|
||||
serverStates[serverId].status = 'down';
|
||||
notifyClients()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`[${new Date().toISOString()}] Unexpected error checking ${server.name} (${server.hostname}:${server.port}):`, error);
|
||||
|
||||
if (serverStates[serverId].status !== 'down') {
|
||||
db.run('UPDATE servers SET status = ? WHERE id = ?', ['down', serverId]);
|
||||
serverStates[serverId].status = 'down';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start monitoring in the background
|
||||
startMonitoring();
|
||||
// Notify all connected clients of server state changes
|
||||
function notifyClients() {
|
||||
const data = JSON.stringify(Object.values(serverStates));
|
||||
clients.forEach(client => client.enqueue(`data: ${data}\n\n`));
|
||||
}
|
||||
|
||||
// Start monitoring all servers from the initial state
|
||||
async function startMonitoring() {
|
||||
Object.keys(serverStates).forEach(serverId => {
|
||||
monitorServer(parseInt(serverId, 10));
|
||||
})
|
||||
console.log('Monitoring started for existing servers.');
|
||||
}
|
||||
|
||||
// Initialize states and start monitoring
|
||||
initializeServerStates().then(startMonitoring);
|
||||
|
||||
// Event listener for adding new servers
|
||||
serverMonitor.on('newServer', (serverId) => {
|
||||
if (!serverStates[serverId]) return;
|
||||
monitorServer(serverId);
|
||||
});
|
||||
|
||||
// API Server to manage servers
|
||||
const server = serve({
|
||||
@ -52,46 +169,122 @@ const server = serve({
|
||||
const pathname = url.pathname;
|
||||
const method = req.method;
|
||||
|
||||
if (pathname === '/watch' && method === 'GET') {
|
||||
const headers = {
|
||||
'Content-Type': 'text/event-stream',
|
||||
'Cache-Control': 'no-cache',
|
||||
'Connection': 'keep-alive',
|
||||
'Access-Control-Allow-Origin': '*'
|
||||
};
|
||||
const client = new Response(
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
clients.add(controller);
|
||||
controller.enqueue(`data: ${JSON.stringify(Object.values(serverStates))}\n\n`)
|
||||
},
|
||||
cancel(controller) {
|
||||
clients.delete(controller);
|
||||
}
|
||||
}),
|
||||
{ headers }
|
||||
);
|
||||
return client;
|
||||
}
|
||||
|
||||
if (pathname === '/servers' && method === 'GET') {
|
||||
const servers = db.query(`SELECT * FROM servers`).all();
|
||||
return new Response(JSON.stringify(servers), {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
return new Response(JSON.stringify(Object.values(serverStates)), {
|
||||
headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' },
|
||||
status: 200
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname === '/server' && method === 'POST') {
|
||||
const data = await req.json();
|
||||
const { name, ip, ping_rate } = data;
|
||||
const { name, hostname, port, ping_rate } = data;
|
||||
|
||||
if (!name || !ip || !ping_rate) {
|
||||
if (!name || !hostname || !port || !ping_rate) {
|
||||
return new Response('Missing fields', { status: 400 });
|
||||
}
|
||||
|
||||
db.run(
|
||||
`INSERT INTO servers (name, ip, ping_rate) VALUES (?, ?, ?)`,
|
||||
name, ip, ping_rate
|
||||
);
|
||||
return new Response('Server added', { status: 201 });
|
||||
db.run('INSERT INTO servers (name, hostname, port, ping_rate) VALUES (?, ?, ?, ?)', name, hostname, port, ping_rate);
|
||||
const newServer = db.query('SELECT * FROM servers WHERE id = last_insert_rowid()').as(ServerState).get();
|
||||
|
||||
if (newServer && newServer.id && newServer.name && newServer.hostname && newServer.port && newServer.ping_rate && newServer.status && newServer.monitoring) {
|
||||
serverStates[newServer.id] = {
|
||||
id: newServer.id,
|
||||
name: newServer.name,
|
||||
hostname: newServer.hostname,
|
||||
port: newServer.port,
|
||||
ping_rate: newServer.ping_rate,
|
||||
status: newServer.status || 'unknown',
|
||||
monitoring: newServer.monitoring
|
||||
};
|
||||
}
|
||||
|
||||
if (newServer && newServer.id) {
|
||||
serverMonitor.emit('newServer', newServer.id);
|
||||
return new Response('Server added', { status: 201, headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
}
|
||||
}
|
||||
|
||||
if (pathname.startsWith('/server/') && method === 'PUT') {
|
||||
const id = pathname.split('/').pop();
|
||||
const data = await req.json();
|
||||
const { name, ip, ping_rate } = data;
|
||||
const { searchParams } = new URL(req.url)
|
||||
const id = pathname.split('/').pop()
|
||||
|
||||
if (!id || !name || !ip || !ping_rate) {
|
||||
return new Response('Missing fields', { status: 400 });
|
||||
const name = searchParams.get('name')
|
||||
const hostname = searchParams.get('hostname')
|
||||
const port = searchParams.get('port')
|
||||
const ping_rate = searchParams.get('ping_rate')
|
||||
const status = searchParams.get('status')
|
||||
const monitoring = searchParams.get('monitoring')
|
||||
|
||||
if (!id) {
|
||||
return new Response('Invalid ID', { status: 400, headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
}
|
||||
|
||||
// Fetch the current state of the server
|
||||
const currentServer = serverStates[parseInt(id)];
|
||||
if (!currentServer) {
|
||||
return new Response('Server not found', { status: 404, headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
}
|
||||
|
||||
// Prepare the updated server data
|
||||
const updatedServer: any = {
|
||||
name: name || currentServer.name,
|
||||
hostname: hostname || currentServer.hostname,
|
||||
port: port || currentServer.port,
|
||||
ping_rate: ping_rate || currentServer.ping_rate,
|
||||
status: status || currentServer.status,
|
||||
monitoring: monitoring || currentServer.monitoring
|
||||
};
|
||||
|
||||
// Update the database
|
||||
db.run(
|
||||
`UPDATE servers SET name = ?, ip = ?, ping_rate = ? WHERE id = ?`,
|
||||
name, ip, ping_rate, id
|
||||
`UPDATE servers SET name = ?, hostname = ?, port = ?, ping_rate = ?, status = ?, monitoring = ? WHERE id = ?`,
|
||||
updatedServer.name, updatedServer.hostname, updatedServer.port, updatedServer.ping_rate, updatedServer.status, updatedServer.monitoring, id
|
||||
);
|
||||
return new Response('Server updated', { status: 200 });
|
||||
|
||||
// Update the in-memory state
|
||||
serverStates[parseInt(id)] = {
|
||||
...serverStates[parseInt(id)], // Retain existing fields
|
||||
...updatedServer // Apply updates
|
||||
};
|
||||
|
||||
return new Response('Server updated', { status: 200, headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
}
|
||||
|
||||
return new Response('Not Found', { status: 404 });
|
||||
},
|
||||
if (pathname.startsWith('/server/') && method === 'DELETE') {
|
||||
const id = pathname.split('/').pop();
|
||||
if (id) {
|
||||
db.run('DELETE FROM servers WHERE id = ?', [parseInt(id)])
|
||||
delete serverStates[parseInt(id)]
|
||||
|
||||
return new Response('Server deleted', { status: 200, headers: { 'Access-Control-Allow-Origin': '*' } })
|
||||
}
|
||||
}
|
||||
|
||||
return new Response('Not Found', { status: 404, headers: { 'Access-Control-Allow-Origin': '*' } });
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`API server and monitoring running on http://localhost:${server.port}`);
|
||||
|
Reference in New Issue
Block a user