const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const fs = require('fs'); const http = require('http'); const https = require('https'); const morgan = require('morgan'); const logger = require('./src/utils/logger'); require('dotenv').config(); const ormService = require('./src/services/ormService'); const mailService = require('./src/services/mailService'); const upload = require('./src/services/uploadService'); const app = express(); // 整合 Morgan 到 Winston app.use(morgan('combined', { stream: { write: message => logger.info(message.trim()) } })); // --- Middleware --- const corsOptions = { origin: [ 'https://app.gex.com.tw', // 您的正式環境前端 'http://localhost:3000' // 本地開發測試用 ], methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', allowedHeaders: ['Content-Type', 'Authorization', 'token'], // 確保 token 能被傳送 credentials: true, // 如果需要帶 Cookie optionsSuccessStatus: 200 }; app.use(cors(corsOptions)); app.use(helmet()); app.use(express.json({ limit: '100mb' })); app.use(express.urlencoded({ extended: true, limit: '100mb' })); //app.use('/static', express.static('public')); app.use(express.static(__dirname + '/public')); //Serves resources from public folder // 啟動郵件排程 mailService.initAutoMail().then(() => console.log('?? Mail Scheduler Started.')); // --- Routes (保持不變) --- // 支援 v1 (舊版) 與 v3 (新版) const ormRoutes = ['/xapi/v1/:dbname/:name/:dsNo', '/xapi/v2/:dbname/:name/:dsNo', '/xapi/v3/:dbname/:name/:dsNo']; app.post(ormRoutes, async (req, res, next) => { try { const params = ormService.prepareOrmPayload(req); // 增加一個 log 觀察是哪個路徑進來的 logger.info(`Incoming Request: ${req.url} -> SP: ${req.params.name}`); // logger.info(`Calling SP: ${req.params.name} by User: ${req.body.token || 'Guest'}`); const result = await ormService.executeSp(req.params.name, params, req.params.dsNo); res.json(result); } catch (err) { logger.error(`API Error on ${req.params.name}: ${err.message}`); next(err); } }); app.post('/upload/:dbname/:typeid', upload.single('file'), (req, res) => { if (!req.file) return res.status(400).json({ status: 400, msg: 'No file' }); //const fileUrl = `/static/upload/${req.params.dbname}/${req.params.typeid}/${req.file.filename}`; // 改為完整的 Server IP const serverRoot = 'https://api.gex.com.tw:8033/upload'; const fileUrl = `${serverRoot}/${req.params.dbname}/${req.params.typeid}/${req.file.filename}`; res.json({ status: 0, data: { value: fileUrl, url: fileUrl }, msg: 'success' }); }); // 全域錯誤處理 app.use((err, req, res, next) => { res.status(err.status || 500).json({ status: err.status || 500, msg: err.message }); }); // --- Server 啟動邏輯 --- const HTTP_PORT = process.env.PORT || 5050; // 啟動標準 HTTP http.createServer(app).listen(HTTP_PORT, () => { console.log(`?? HTTP Server running on http://localhost:${HTTP_PORT}`); }); // 根據 .env 決定是否啟動 HTTPS if (process.env.ENABLE_HTTPS === 'true') { try { const options = { key: fs.readFileSync(process.env.SSL_KEY_PATH), cert: fs.readFileSync(process.env.SSL_CRT_PATH) }; const HTTPS_PORT = process.env.HTTPS_PORT || 5443; https.createServer(options, app).listen(HTTPS_PORT, () => { console.log(`?? HTTPS Server running on https://localhost:${HTTPS_PORT}`); }); } catch (error) { console.error('? Failed to start HTTPS server (Check SSL paths):', error.message); } }