Browse Source

first commit

Pchen. 8 months ago
commit
d34b476d25
7 changed files with 265 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 5 0
      index.js
  3. 47 0
      lib/API.js
  4. 47 0
      lib/Logger.js
  5. 91 0
      lib/Server.js
  6. 19 0
      package.json
  7. 54 0
      plugin/MySQL.js

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+node_modules/
+*.log

+ 5 - 0
index.js

@@ -0,0 +1,5 @@
+const SERVER = require('./lib/server');
+
+const server = new SERVER();
+
+server.start();

+ 47 - 0
lib/API.js

@@ -0,0 +1,47 @@
+const express = require('express');
+const Logger = require('./Logger');
+
+class API {
+    constructor() {
+        this.router = express.Router();
+        this.namespace = '';
+        this.path = '';
+        this.method = 'get';
+
+        this.logger = new Logger(path.join(__dirname, '../logs/app.log'), 'INFO');
+    }
+
+    setNamespace(namespace, filename) {
+        this.namespace = namespace;
+    }
+
+    setPath(path) {
+        this.path = path;
+    }
+
+    setMethod(method) {
+        this.method = method.toLowerCase();
+    }
+
+    getRouter() {
+        return this.router;
+    }
+
+    async onRequest(req, res) {
+        throw new Error('onRequest方法未实现');
+    }
+
+    setupRoute() {
+        this.router[this.method](this.path, async (req, res) => {
+            await this.onRequest(req, res);
+        });
+    }
+
+    setAllowCORS(res) {
+        res.setHeader('Access-Control-Allow-Origin', '*');
+        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
+        res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
+    }
+}
+
+module.exports = API;

+ 47 - 0
lib/Logger.js

@@ -0,0 +1,47 @@
+const fs = require('fs');
+const path = require('path');
+
+class Logger {
+    constructor(logFilePath = null, level = 'INFO') {
+        this.logLevels = ['INFO', 'WARN', 'ERROR'];
+        this.level = level.toUpperCase(); //不区分大小写 可以偷懒
+        this.logFilePath = logFilePath ? path.resolve(logFilePath) : null;
+
+        if (this.logFilePath) {
+            // 确保日志目录存在
+            const dir = path.dirname(this.logFilePath);
+            if (!fs.existsSync(dir)) {
+                fs.mkdirSync(dir, { recursive: true });
+            }
+        }
+    }
+
+    log(level, message) {
+        level = level.toUpperCase();
+        if (this.logLevels.indexOf(level) >= this.logLevels.indexOf(this.level)) {
+            const timestamp = new Date().toISOString();
+            const logMessage = `${timestamp} [${level}] ${message}\n`;
+
+            console.log(logMessage.trim());
+            if (this.logFilePath) {
+                fs.appendFile(this.logFilePath, logMessage, (err) => {
+                    if (err) throw err;
+                });
+            }
+        }
+    }
+
+    info(message) {
+        this.log('INFO', message);
+    }
+
+    warn(message) {
+        this.log('WARN', message);
+    }
+
+    error(message) {
+        this.log('ERROR', message);
+    }
+}
+
+module.exports = Logger;

+ 91 - 0
lib/Server.js

@@ -0,0 +1,91 @@
+const express = require('express');
+const path = require('path');
+const fs = require('fs');
+const config = require('../config.json');
+const Logger = require('./Logger');
+const MySQL = require('../plugin/MySQL');
+
+class SERVER {
+    constructor() {
+        this.app = express();
+        this.port = config.port || 3000; 
+        this.apiDirectory = path.join(__dirname, '../apis'); // API 文件存放目录
+
+        this.logger = new Logger(path.join(__dirname, '../logs/Server.log'), 'INFO');
+
+        // 解析 JSON 请求体
+        this.app.use(express.json());
+
+        // 初始化数据库连接
+        this.db = new MySQL(); 
+
+        // 加载 API 路由
+        this.loadAPIs(this.apiDirectory);
+    }
+
+    // 测试数据库连接
+    async initDB() {
+        try {
+            await this.db.connect();
+            this.logger.info('数据库连接成功');
+        } catch (error) {
+            this.logger.error(`数据库连接失败: ${error.message}`);
+            process.exit(1);
+        }
+    }
+
+    loadAPIs(directory) {
+        this.logger.info('==============正在加载API==============');
+
+        const items = fs.readdirSync(directory);
+
+        items.forEach(item => {
+            const itemPath = path.join(directory, item);
+            const stats = fs.statSync(itemPath);
+
+            if (stats.isDirectory()) {
+                // 如果是目录,递归调用
+                this.loadAPIs(itemPath);
+            } else if (stats.isFile() && itemPath.endsWith('.js')) {
+                // 如果是文件且是 JavaScript 文件
+                this.loadAPIFile(itemPath);
+            }
+        });
+
+        this.logger.info('==============API加载完成==============');
+    }
+
+    // 加载单个 API 文件
+    loadAPIFile(filePath) {
+        try {
+            const APIClass = require(filePath);
+
+            for (const key in APIClass) {
+                if (APIClass.hasOwnProperty(key)) {
+                    const apiInstance = new APIClass[key]();
+                    apiInstance.setupRoute();
+                    this.app.use('/', apiInstance.getRouter());
+                    this.logger.info(`已加载API文件: ${filePath}`);
+                }
+            }
+        } catch (error) {
+            this.logger.error(`加载API文件失败: ${filePath},错误: ${error.message}`);
+        }
+    }
+
+    start() {
+        this.logger.info('============正在启动服务器============');
+
+        // 初始化数据库连接
+        this.initDB().then(() => {
+            this.app.listen(this.port, () => {
+                this.logger.info(`==========服务器正在 ${this.port} 上运行==========`);
+            });
+        }).catch(err => {
+            this.logger.error(`启动服务器失败: ${err.message}`);
+            process.exit(1); // 启动失败时退出进程
+        });
+    }
+}
+
+module.exports = SERVER;

+ 19 - 0
package.json

@@ -0,0 +1,19 @@
+{
+  "name": "kq",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "thc",
+  "license": "ISC",
+  "dependencies": {
+    "axios": "^1.7.4",
+    "body-parser": "^1.20.2",
+    "cors": "^2.8.5",
+    "express": "^4.19.2",
+    "mysql": "^2.18.1",
+    "mysql2": "^3.11.0"
+  }
+}

+ 54 - 0
plugin/MySQL.js

@@ -0,0 +1,54 @@
+const mysql = require('mysql2/promise');
+const path = require('path')
+const config = require('../config.json');
+const Logger = require('../lib/Logger');
+
+class MySQL {
+    constructor() {
+        this.config = config.database;
+        this.connection = null;
+
+        this.logger = new Logger(path.join(__dirname, '../logs/MySQL.log'), 'INFO')
+    }
+
+    async connect() {
+        if (this.connection) {
+            return this.connection;
+        }
+
+        try {
+            this.logger.info('正在连接数据库')
+            this.connection = await mysql.createConnection(this.config);
+            this.logger.info('已连接到数据库')
+            return this.connection;
+        } catch (error) {
+            this.logger.error('连接数据库失败:', error.message)
+            throw error;
+        }
+    }
+
+    async query(sql, params = []) {
+        try {
+            const [rows, fields] = await this.connection.execute(sql, params);
+            return { rows, fields };
+        } catch (error) {
+            this.logger.error('执行SQL语句时出错:', error);
+            throw error;
+        }
+    }
+
+    async close() {
+        if (this.connection) {
+            try {
+                await this.connection.end();
+                this.logger.info('已关闭与数据库的连接')
+                this.connection = null;
+            } catch (error) {
+                this.logger.error('关闭与数据库的连接时出错:', error);
+                throw error;
+            }
+        }
+    }
+}
+
+module.exports = MySQL;