Files
Nilai_Clock/backend/server.js
T
Edison 8e5fa5652e added current time(yellow ring) enhancement
follow server time instead of user computer local time.
2025-10-07 11:25:09 +08:00

111 lines
3.8 KiB
JavaScript

// server.js
import express from 'express';
import cors from 'cors';
import https from 'https';
import http from 'http';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
import mysql from 'mysql2/promise';
import managerRoutes from './managerRoutes.js';
import workerRoutes from './workerRoutes.js';
async function startServer() {
dotenv.config({ path: path.join(path.dirname(fileURLToPath(import.meta.url)), '.env') });
const app = express();
const db = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
port: process.env.DB_PORT,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
});
try {
const connection = await db.getConnection();
console.log('Database connected successfully!');
connection.release();
} catch (error) {
console.error('!!! DATABASE CONNECTION FAILED !!!');
console.error('Error:', error.message);
process.exit(1);
}
const allowedOriginsFromEnv = (process.env.CORS_ALLOWED_ORIGINS || '').split(',').filter(Boolean);
const defaultAllowedOrigins = ['http://localhost:5173', 'https://localhost:5173', 'capacitor://localhost', 'ionic://localhost', 'http://localhost', 'https://localhost'];
const allowedOrigins = [...new Set([...defaultAllowedOrigins, ...allowedOriginsFromEnv])];
const corsOptions = {
origin: (origin, callback) => {
// Allow requests with no origin (like mobile apps or curl requests)
if (!origin || allowedOrigins.includes(origin) || origin.startsWith('capacitor://') || origin.startsWith('ionic://')) {
callback(null, true);
} else {
console.log('CORS blocked origin:', origin);
callback(new Error('Not allowed by CORS'));
}
},
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'ngrok-skip-browser-warning'],
exposedHeaders: ['Content-Range', 'X-Content-Range'],
};
app.use(cors(corsOptions));
app.use(express.json());
// --- Public server time endpoints (no auth, no cache) ---
const timeHandler = (req, res) => {
const now = new Date();
const ymdKL = new Intl.DateTimeFormat('en-CA', {
timeZone: 'Asia/Kuala_Lumpur',
year: 'numeric', month: '2-digit', day: '2-digit'
}).format(now); // "YYYY-MM-DD"
res.set('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
res.set('Pragma', 'no-cache');
res.set('Expires', '0');
res.json({ nowIso: now.toISOString(), tz: 'Asia/Kuala_Lumpur', ymdKL });
};
app.get('/time', timeHandler); // public path
app.get('/api/time', timeHandler); // also under /api
app.use('/api/managers', managerRoutes(db));
app.use('/api', workerRoutes(db));
const httpPort = process.env.HTTP_PORT || 3000;
const httpsPort = process.env.HTTPS_PORT || 3443;
const sslEnabled = process.env.SSL_ENABLED === 'true';
if (sslEnabled) {
try {
const currentDir = path.dirname(fileURLToPath(import.meta.url));
const keyPath = path.join(currentDir, 'key.pem');
const certPath = path.join(currentDir, 'cert.pem');
const httpsOptions = {
key: fs.readFileSync(keyPath),
cert: fs.readFileSync(certPath),
};
https.createServer(httpsOptions, app).listen(httpsPort, '0.0.0.0', () => {
console.log(`🔒 HTTPS Server is running on https://localhost:${httpsPort}`);
});
} catch (error) {
console.error('❌ Failed to start HTTPS server:', error.message);
}
}
http.createServer(app).listen(httpPort, '0.0.0.0', () => {
console.log(`🌐 HTTP Server is running on http://localhost:${httpPort}`);
});
}
startServer();