201 lines
5.0 KiB
JavaScript
201 lines
5.0 KiB
JavaScript
const Database = require("better-sqlite3");
|
|
const path = require("path");
|
|
const fs = require("fs").promises;
|
|
const crypto = require("crypto");
|
|
|
|
const stmtCaches = new Map();
|
|
|
|
class SqliteDatabase {
|
|
db_path = null;
|
|
constructor() {
|
|
this.db = null;
|
|
}
|
|
|
|
// 获取预编译语句(带缓存)
|
|
getStmt(sql) {
|
|
let stmt = stmtCaches.get(sql);
|
|
if (!stmt) {
|
|
stmt = this.db.prepare(sql);
|
|
stmtCaches.set(sql, stmt);
|
|
}
|
|
return stmt;
|
|
}
|
|
|
|
// 初始化数据库
|
|
async init(db_name) {
|
|
try {
|
|
this.db_path = path.join(__dirname, db_name);
|
|
const fileExists = await this.checkDbFileExists();
|
|
|
|
if (!fileExists) {
|
|
console.log("数据库文件不存在,正在创建...");
|
|
this.db = new Database(this.db_path);
|
|
await this.executeDefaultScripts();
|
|
console.log("数据库初始化完成");
|
|
} else {
|
|
console.log("数据库文件已存在,正在连接...");
|
|
this.db = new Database(this.db_path);
|
|
await this.executeAlterScripts();
|
|
console.log("数据库连接成功");
|
|
}
|
|
} catch (error) {
|
|
console.error("数据库初始化失败:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 检查数据库文件是否存在
|
|
async checkDbFileExists() {
|
|
try {
|
|
await fs.access(this.db_path);
|
|
return true;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// 执行 ALTER 脚本(数据库已存在时)
|
|
async executeAlterScripts() {
|
|
for (let sql of ALTER_SCRIPTS) {
|
|
try {
|
|
await this.query(sql);
|
|
} catch (error) {
|
|
console.error(sql, "查询失败", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 执行默认建表脚本(数据库新建时)
|
|
async executeDefaultScripts() {
|
|
for (let sql of DEFAULT_TABLE_SCRIPTS) {
|
|
try {
|
|
await this.query(sql);
|
|
} catch (error) {
|
|
console.error(sql, "查询失败", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 执行 INSERT/UPDATE/DELETE 等操作
|
|
query(sql, params = []) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
const stmt = this.getStmt(sql);
|
|
const info = stmt.run(...params);
|
|
resolve({ lastID: info.lastInsertRowid, changes: info.changes });
|
|
} catch (err) {
|
|
console.error("SQL执行错误:", err);
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 查询单行数据
|
|
get(sql, params = []) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
const stmt = this.getStmt(sql);
|
|
const row = stmt.get(...params);
|
|
resolve(row);
|
|
} catch (err) {
|
|
console.error("SQL查询错误:", err);
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 查询多行数据
|
|
all(sql, params = []) {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
const stmt = this.getStmt(sql);
|
|
const rows = stmt.all(...params);
|
|
resolve(rows);
|
|
} catch (err) {
|
|
console.error("SQL查询错误:", err);
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
// 关闭数据库连接
|
|
close() {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
if (this.db) {
|
|
this.db.close();
|
|
this.db = null;
|
|
}
|
|
resolve();
|
|
} catch (err) {
|
|
console.error("关闭数据库连接失败:", err);
|
|
reject(err);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
// 导出单例
|
|
module.exports = new SqliteDatabase();
|
|
|
|
// ---------- 建表及初始脚本 ----------
|
|
const DEFAULT_TABLE_SCRIPTS = [
|
|
`CREATE TABLE IF NOT EXISTS users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name VARCHAR(60) NOT NULL,
|
|
pwd VARCHAR(60) NOT NULL,
|
|
phone VARCHAR(20),
|
|
state INTEGER DEFAULT 1,
|
|
level INTEGER DEFAULT 0,
|
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE (name)
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS servers (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name VARCHAR(60) NOT NULL,
|
|
ip VARCHAR(60) NOT NULL,
|
|
port VARCHAR(60) NOT NULL,
|
|
state INTEGER DEFAULT 1,
|
|
isdef INTEGER DEFAULT 0,
|
|
istest INTEGER DEFAULT 0,
|
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS players (
|
|
id VARCHAR(40) NOT NULL,
|
|
name VARCHAR(30) NOT NULL,
|
|
userid INTEGER NOT NULL,
|
|
sid INTEGER NOT NULL,
|
|
level INTEGER DEFAULT 0,
|
|
title VARCHAR(30) NOT NULL,
|
|
data TEXT,
|
|
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS players_bak (
|
|
id VARCHAR(40) NOT NULL,
|
|
name VARCHAR(30) NOT NULL,
|
|
userid INTEGER NOT NULL,
|
|
sid INTEGER NOT NULL,
|
|
level INTEGER DEFAULT 0,
|
|
title VARCHAR(30) NOT NULL,
|
|
data TEXT,
|
|
create_time TIMESTAMP,
|
|
update_time TIMESTAMP
|
|
)`,
|
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_users_name ON users (name)`,
|
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_players_id ON players (id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_players_userid ON players (userid)`,
|
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_players_name ON players (name)`,
|
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_players_bak_id ON players_bak (id)`,
|
|
`INSERT OR IGNORE INTO users(id,name,pwd,level) VALUES(1,'administrator','${MD5("123456")}',6)`,
|
|
];
|
|
|
|
function MD5(str) {
|
|
let md5 = crypto.createHash("md5");
|
|
let result = md5.update(str + process.env.MD5_PREFIX).digest("hex");
|
|
return result.toUpperCase();
|
|
}
|
|
|
|
const ALTER_SCRIPTS = [];
|