- Add package.json for project metadata and dependencies - Create server.js for API endpoints and server logic - Implement data persistence using JSON file for server information - Add HTML frontend (vps_manager.html) for server management interface - Include Leaflet for map visualization of server locations - Create start.bat for easy server startup on Windows
92 lines
2.7 KiB
JavaScript
92 lines
2.7 KiB
JavaScript
const express = require('express');
|
|
const fs = require('fs');
|
|
const https = require('https');
|
|
const path = require('path');
|
|
|
|
const app = express();
|
|
const PORT = process.env.PORT || 8095;
|
|
const DATA_FILE = path.join(__dirname, 'data', 'servers.json');
|
|
|
|
app.use(express.json());
|
|
app.use(express.static(__dirname));
|
|
|
|
app.get('/', (req, res) => {
|
|
res.sendFile(path.join(__dirname, 'vps_manager.html'));
|
|
});
|
|
|
|
if (!fs.existsSync(path.join(__dirname, 'data'))) {
|
|
fs.mkdirSync(path.join(__dirname, 'data'));
|
|
}
|
|
|
|
function readData() {
|
|
try { return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8')); }
|
|
catch { return []; }
|
|
}
|
|
|
|
function writeData(data) {
|
|
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
|
|
}
|
|
|
|
function geocode(location) {
|
|
return new Promise((resolve) => {
|
|
const q = encodeURIComponent(location);
|
|
const options = {
|
|
hostname: 'nominatim.openstreetmap.org',
|
|
path: `/search?q=${q}&format=json&limit=1`,
|
|
headers: { 'User-Agent': 'vps-fleet-manager/1.0' }
|
|
};
|
|
https.get(options, (res) => {
|
|
let data = '';
|
|
res.on('data', c => data += c);
|
|
res.on('end', () => {
|
|
try {
|
|
const r = JSON.parse(data);
|
|
resolve(r[0] ? { lat: parseFloat(r[0].lat), lng: parseFloat(r[0].lon) } : null);
|
|
} catch { resolve(null); }
|
|
});
|
|
}).on('error', () => resolve(null));
|
|
});
|
|
}
|
|
|
|
app.get('/api/servers', (req, res) => {
|
|
res.json(readData());
|
|
});
|
|
|
|
app.post('/api/servers', async (req, res) => {
|
|
const servers = readData();
|
|
const server = { ...req.body };
|
|
if (!server.id) server.id = 'srv_' + Date.now();
|
|
const existing = servers.find(s => s.id === server.id);
|
|
|
|
if (server.location && (!existing || existing.location !== server.location || !existing._lat)) {
|
|
const coords = await geocode(server.location);
|
|
if (coords) { server._lat = coords.lat; server._lng = coords.lng; }
|
|
} else if (existing && existing._lat) {
|
|
server._lat = existing._lat;
|
|
server._lng = existing._lng;
|
|
}
|
|
|
|
const idx = servers.findIndex(s => s.id === server.id);
|
|
if (idx > -1) servers[idx] = server;
|
|
else servers.push(server);
|
|
writeData(servers);
|
|
res.json(server);
|
|
});
|
|
|
|
app.delete('/api/servers/:id', (req, res) => {
|
|
writeData(readData().filter(s => s.id !== req.params.id));
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
app.listen(PORT, '0.0.0.0', () => {
|
|
const { networkInterfaces } = require('os');
|
|
const nets = networkInterfaces();
|
|
const localIPs = Object.values(nets).flat()
|
|
.filter(n => n.family === 'IPv4' && !n.internal)
|
|
.map(n => n.address);
|
|
console.log(`\nvps/fleet running`);
|
|
console.log(` local → http://localhost:${PORT}`);
|
|
localIPs.forEach(ip => console.log(` network → http://${ip}:${PORT}`));
|
|
console.log('');
|
|
});
|