File size: 5,871 Bytes
2bf7a2b
 
 
 
 
 
 
e9a82dd
2bf7a2b
 
 
 
e9a82dd
2bf7a2b
 
 
 
 
 
 
 
 
 
 
 
 
138f7fd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2bf7a2b
 
 
 
 
 
 
 
 
 
 
b2c8885
2bf7a2b
997f2d0
138f7fd
2bf7a2b
 
 
 
b2c8885
2bf7a2b
 
b2c8885
2bf7a2b
 
 
 
 
b2c8885
2bf7a2b
b2c8885
2bf7a2b
 
 
 
 
b2c8885
2bf7a2b
 
 
 
 
 
 
 
 
 
b2c8885
2bf7a2b
 
 
b2c8885
2bf7a2b
 
 
 
 
 
b2c8885
2bf7a2b
 
 
b2c8885
2bf7a2b
 
 
 
 
 
 
 
b2c8885
2bf7a2b
b2c8885
2bf7a2b
997f2d0
b2c8885
2bf7a2b
 
 
 
 
 
 
 
 
 
 
 
b2c8885
997f2d0
 
7afb7eb
 
 
997f2d0
 
 
2bf7a2b
7afb7eb
a697003
7afb7eb
 
2bf7a2b
 
 
 
 
 
 
 
 
 
 
 
 
 
17bd284
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
require('dotenv').config();
const express = require('express');
const path = require('path');
const { WebSocketServer } = require('ws');
const http = require('http');
const Database = require('./database');
const ConnectionManager = require('./websocket');
const { verifyApiKey, requireAdminKey, requireRegularOrAdminKey, requireAnyKey, requireServerKey } = require('./auth');
const createKeysRouter = require('./routes/keys');
const createEventsRouter = require('./routes/events');
const createHealthRouter = require('./routes/health');
const createServerRouter = require('./routes/server');
const createAIRouter = require('./routes/ai');

const HOST = process.env.SERVER_HOST || '0.0.0.0';
const PORT = parseInt(process.env.SERVER_PORT || '8000');

const app = express();
const server = http.createServer(app);
const wss = new WebSocketServer({ noServer: true });

const db = new Database(process.env.DATABASE_PATH || 'minecraft_ws.db');
const manager = new ConnectionManager();

app.use(express.json());

// Request Logging Middleware
app.use((req, res, next) => {
    const start = Date.now();
    const timestamp = new Date().toISOString();
    
    // Log request
    console.log(`[${timestamp}] \x1b[36m${req.method}\x1b[0m ${req.url}`);
    
    // Capture response finish
    res.on('finish', () => {
        const duration = Date.now() - start;
        const statusColor = res.statusCode >= 400 ? '\x1b[31m' : (res.statusCode >= 300 ? '\x1b[33m' : '\x1b[32m');
        console.log(`[${timestamp}] ${statusColor}${res.statusCode}\x1b[0m ${req.method} ${req.url} - ${duration}ms`);
    });
    
    next();
});

app.use('/dashboard', express.static(path.join(__dirname, '../dashboard/public')));

app.get('/', (req, res) => {
    res.json({
        message: 'Minecraft WebSocket API Server (Node.js)',
        dashboard: '/dashboard',
        websocket: 'ws://' + req.get('host') + '/ws',
        version: '1.0.0'
    });
});

app.use('/manage/keys', verifyApiKey(db), createKeysRouter(db, requireAdminKey));
app.use('/api/events', verifyApiKey(db), requireAnyKey, createEventsRouter(db, manager, requireAnyKey));
app.use('/api/server', verifyApiKey(db), createServerRouter(db, manager, requireRegularOrAdminKey));
app.use('/api/ai', verifyApiKey(db), createAIRouter(db, manager, requireAdminKey, requireAnyKey));
app.use('/health', createHealthRouter(db, manager));

server.on('upgrade', async (request, socket, head) => {
    const url = new URL(request.url, `http://${request.headers.host}`);

    if (url.pathname === '/ws') {
        const apiKey = url.searchParams.get('api_key');

        if (!apiKey) {
            socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
            socket.destroy();
            return;
        }

        const result = await db.verifyApiKey(apiKey);

        if (!result) {
            socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
            socket.destroy();
            return;
        }

        wss.handleUpgrade(request, socket, head, (ws) => {
            wss.emit('connection', ws, request, result);
        });
    } else {
        socket.destroy();
    }
});

wss.on('connection', (ws, request, apiKeyInfo) => {
    manager.connect(ws, apiKeyInfo.id);

    ws.on('message', (data) => {
        try {
            const msg = JSON.parse(data.toString());

            if (msg.type === 'ping') {
                ws.send(JSON.stringify({ type: 'pong' }));
            }
        } catch (error) {
        }
    });

    ws.on('close', () => {
        manager.disconnect(ws);
    });

    ws.on('error', () => {
        manager.disconnect(ws);
    });
});

async function startServer() {
    console.log('🚀 启动Minecraft WebSocket API服务器...');
    console.log('='.repeat(50));

    await db.init();

    const adminKeyInfo = await db.ensureInitialAdminKey();
    const recoveryTokenInfo = await db.ensureAdminRecoveryToken();

    if (adminKeyInfo) {
        console.log('='.repeat(60));
        console.log('重要: 已生成新的Admin Key!');
        console.log(`  名称: ${adminKeyInfo.name}`);
        console.log(`  密钥: ${adminKeyInfo.key}`);
        console.log('请复制并安全保存此密钥。');
        console.log('您需要使用它来管理API密钥。');
        console.log('如果丢失此密钥且没有其他Admin Key,您可能失去管理员访问权限。');
        console.log('='.repeat(60));
    } else {
        console.log('信息: 已找到现有Admin Key或Admin Key检查已执行。');
    }

    if (recoveryTokenInfo) {
        console.log('='.repeat(60));
        console.log('重要: 已生成 Admin 恢复令牌。');
        console.log(`  令牌: ${recoveryTokenInfo.token}`);
        console.log('请安全存储此令牌。它仅显示一次。');
        console.log('='.repeat(60));
    }

    server.listen(PORT, HOST, () => {
        const displayHost = HOST === '0.0.0.0' ? 'localhost' : HOST;
        console.log(`服务器地址: http://${displayHost}:${PORT}/dashboard`);
        console.log(`WebSocket端点: ws://${displayHost}:${PORT}/ws`);
        console.log(`健康检查: http://${displayHost}:${PORT}/health`);
        console.log('='.repeat(50));
        console.log();
        console.log('💡 首次使用提示:');
        console.log('1. 使用CLI工具创建API密钥:');
        console.log('   node cli/cli.js create-key "MyServer"');
        console.log();
        console.log('2. 生成Minecraft插件配置文件:');
        console.log('   node cli/cli.js generate-config');
        console.log();
        console.log('3. 将API密钥配置到Minecraft插件中');
        console.log('='.repeat(50));
    });
}

if (require.main === module) {
    startServer().catch(error => {
        console.error('❌ 启动失败:', error);
        process.exit(1);
    });
}

module.exports = { app, server, db, wss, startServer };