Files
SteelCheck/server.js
T

163 lines
4.9 KiB
JavaScript

import http from 'http';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PORT = process.env.PORT || 8080;
const DIST_DIR = path.join(__dirname, 'dist');
const CONFIG_DIR = path.join(__dirname, 'data');
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
// Ensure config dir exists
if (!fs.existsSync(CONFIG_DIR)) {
fs.mkdirSync(CONFIG_DIR, { recursive: true });
}
const MIME_TYPES = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript',
'.json': 'application/json',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon',
};
const server = http.createServer((req, res) => {
// CORS headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
// API Config GET
if (req.url === '/api/config' && req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
if (fs.existsSync(CONFIG_FILE)) {
try {
const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
res.end(data);
return;
} catch (err) {
// Fallback
}
}
res.end(JSON.stringify({}));
return;
}
// API Config POST
if (req.url === '/api/config' && req.method === 'POST') {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
try {
const parsed = JSON.parse(body);
fs.writeFileSync(CONFIG_FILE, JSON.stringify(parsed, null, 2), 'utf-8');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ success: true }));
} catch (err) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Invalid JSON or write error' }));
}
});
return;
}
// --- CATEGORIES CRUD ---
const CATEGORIES_FILE = path.join(CONFIG_DIR, 'categories.json');
const readCategories = () => {
if (fs.existsSync(CATEGORIES_FILE)) {
try { return JSON.parse(fs.readFileSync(CATEGORIES_FILE, 'utf-8')); } catch (e) {}
}
return [];
};
if (req.url.startsWith('/api/categories')) {
if (req.method === 'GET') {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(readCategories()));
return;
}
if (req.method === 'POST' || req.method === 'PUT') {
let body = '';
req.on('data', chunk => body += chunk.toString());
req.on('end', () => {
try {
const category = JSON.parse(body);
let categories = readCategories();
if (req.method === 'POST') {
category.id = Date.now().toString();
categories.push(category);
} else {
const index = categories.findIndex(c => c.id === category.id);
if (index !== -1) categories[index] = { ...categories[index], ...category };
}
fs.writeFileSync(CATEGORIES_FILE, JSON.stringify(categories, null, 2));
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(category));
} catch (err) {
res.writeHead(400); res.end(JSON.stringify({ error: 'Invalid payload' }));
}
});
return;
}
if (req.method === 'DELETE') {
const urlParams = new URL(req.url, `http://${req.headers.host}`);
const id = urlParams.searchParams.get('id');
if (id) {
let categories = readCategories();
categories = categories.filter(c => c.id !== id);
fs.writeFileSync(CATEGORIES_FILE, JSON.stringify(categories, null, 2));
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ success: true }));
} else {
res.writeHead(400); res.end(JSON.stringify({ error: 'Missing id' }));
}
return;
}
}
// --- END CATEGORIES CRUD ---
// Serve static files
let filePath = path.join(DIST_DIR, req.url === '/' ? 'index.html' : req.url);
// If path doesn't exist, fallback to index.html (SPA routing)
if (!fs.existsSync(filePath) || fs.statSync(filePath).isDirectory()) {
filePath = path.join(DIST_DIR, 'index.html');
}
const ext = path.extname(filePath);
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
fs.readFile(filePath, (err, content) => {
if (err) {
res.writeHead(500);
res.end('Server Error');
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content);
}
});
});
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});