Update server.js
Browse files
server.js
CHANGED
@@ -1,9 +1,14 @@
|
|
1 |
const express = require('express');
|
2 |
const path = require('path');
|
3 |
const axios = require('axios');
|
|
|
4 |
const app = express();
|
5 |
const port = process.env.PORT || 8080;
|
6 |
|
|
|
|
|
|
|
|
|
7 |
// 从环境变量获取 HuggingFace 用户名和对应的 API Token 映射
|
8 |
const userTokenMapping = {};
|
9 |
const usernames = [];
|
@@ -26,6 +31,10 @@ if (hfUserConfig) {
|
|
26 |
const ADMIN_USERNAME = process.env.USER_NAME || 'admin';
|
27 |
const ADMIN_PASSWORD = process.env.USER_PASSWORD || 'password';
|
28 |
|
|
|
|
|
|
|
|
|
29 |
// 缓存管理
|
30 |
class SpaceCache {
|
31 |
constructor() {
|
@@ -58,6 +67,65 @@ app.get('/api/config', (req, res) => {
|
|
58 |
res.json({ usernames: usernames.join(',') });
|
59 |
});
|
60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
// 获取所有 spaces 列表(包括私有)
|
62 |
app.get('/api/proxy/spaces', async (req, res) => {
|
63 |
try {
|
@@ -121,8 +189,8 @@ app.get('/api/proxy/spaces', async (req, res) => {
|
|
121 |
}
|
122 |
});
|
123 |
|
124 |
-
// 代理重启 Space
|
125 |
-
app.post('/api/proxy/restart/:repoId(*)', async (req, res) => {
|
126 |
try {
|
127 |
const { repoId } = req.params;
|
128 |
console.log(`尝试重启 Space: ${repoId}`);
|
@@ -148,8 +216,8 @@ app.post('/api/proxy/restart/:repoId(*)', async (req, res) => {
|
|
148 |
}
|
149 |
});
|
150 |
|
151 |
-
// 代理重建 Space
|
152 |
-
app.post('/api/proxy/rebuild/:repoId(*)', async (req, res) => {
|
153 |
try {
|
154 |
const { repoId } = req.params;
|
155 |
console.log(`尝试重建 Space: ${repoId}`);
|
@@ -336,6 +404,17 @@ app.get('*', (req, res) => {
|
|
336 |
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
337 |
});
|
338 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
app.listen(port, () => {
|
340 |
console.log(`Server running on port ${port}`);
|
341 |
console.log(`User configurations:`, usernames.map(user => `${user}: ${userTokenMapping[user] ? 'Token Configured' : 'No Token'}`).join(', ') || 'None');
|
|
|
1 |
const express = require('express');
|
2 |
const path = require('path');
|
3 |
const axios = require('axios');
|
4 |
+
const crypto = require('crypto');
|
5 |
const app = express();
|
6 |
const port = process.env.PORT || 8080;
|
7 |
|
8 |
+
// 启用 JSON 和 URL-encoded 请求解析
|
9 |
+
app.use(express.json());
|
10 |
+
app.use(express.urlencoded({ extended: true }));
|
11 |
+
|
12 |
// 从环境变量获取 HuggingFace 用户名和对应的 API Token 映射
|
13 |
const userTokenMapping = {};
|
14 |
const usernames = [];
|
|
|
31 |
const ADMIN_USERNAME = process.env.USER_NAME || 'admin';
|
32 |
const ADMIN_PASSWORD = process.env.USER_PASSWORD || 'password';
|
33 |
|
34 |
+
// 存储会话 token 的简单内存数据库(生产环境中应使用数据库或 Redis)
|
35 |
+
const sessions = new Map();
|
36 |
+
const SESSION_TIMEOUT = 24 * 60 * 60 * 1000; // 24小时超时
|
37 |
+
|
38 |
// 缓存管理
|
39 |
class SpaceCache {
|
40 |
constructor() {
|
|
|
67 |
res.json({ usernames: usernames.join(',') });
|
68 |
});
|
69 |
|
70 |
+
// 登录 API 接口
|
71 |
+
app.post('/api/login', (req, res) => {
|
72 |
+
const { username, password } = req.body;
|
73 |
+
if (username === ADMIN_USERNAME && password === ADMIN_PASSWORD) {
|
74 |
+
// 生成一个随机 token 作为会话标识
|
75 |
+
const token = crypto.randomBytes(16).toString('hex');
|
76 |
+
const expiresAt = Date.now() + SESSION_TIMEOUT;
|
77 |
+
sessions.set(token, { username, expiresAt });
|
78 |
+
console.log(`用户 ${username} 登录成功,生成 token: ${token.slice(0, 8)}...`);
|
79 |
+
res.json({ success: true, token });
|
80 |
+
} else {
|
81 |
+
console.log(`用户 ${username} 登录失败,凭据无效`);
|
82 |
+
res.status(401).json({ success: false, message: '用户名或密码错误' });
|
83 |
+
}
|
84 |
+
});
|
85 |
+
|
86 |
+
// 验证登录状态 API 接口
|
87 |
+
app.post('/api/verify-token', (req, res) => {
|
88 |
+
const { token } = req.body;
|
89 |
+
const session = sessions.get(token);
|
90 |
+
if (session && session.expiresAt > Date.now()) {
|
91 |
+
res.json({ success: true, message: 'Token 有效' });
|
92 |
+
} else {
|
93 |
+
if (session) {
|
94 |
+
sessions.delete(token); // 删除过期的 token
|
95 |
+
console.log(`Token ${token.slice(0, 8)}... 已过期,已删除`);
|
96 |
+
}
|
97 |
+
res.status(401).json({ success: false, message: 'Token 无效或已过期' });
|
98 |
+
}
|
99 |
+
});
|
100 |
+
|
101 |
+
// 登出 API 接口
|
102 |
+
app.post('/api/logout', (req, res) => {
|
103 |
+
const { token } = req.body;
|
104 |
+
sessions.delete(token);
|
105 |
+
console.log(`Token ${token.slice(0, 8)}... 已手动登出`);
|
106 |
+
res.json({ success: true, message: '登出成功' });
|
107 |
+
});
|
108 |
+
|
109 |
+
// 中间件:验证请求中的 token
|
110 |
+
const authenticateToken = (req, res, next) => {
|
111 |
+
const authHeader = req.headers['authorization'];
|
112 |
+
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
113 |
+
return res.status(401).json({ error: '未提供有效的认证令牌' });
|
114 |
+
}
|
115 |
+
const token = authHeader.split(' ')[1];
|
116 |
+
const session = sessions.get(token);
|
117 |
+
if (session && session.expiresAt > Date.now()) {
|
118 |
+
req.session = session;
|
119 |
+
next();
|
120 |
+
} else {
|
121 |
+
if (session) {
|
122 |
+
sessions.delete(token); // 删除过期的 token
|
123 |
+
console.log(`Token ${token.slice(0, 8)}... 已过期,拒绝访问`);
|
124 |
+
}
|
125 |
+
return res.status(401).json({ error: '认证令牌无效或已过期' });
|
126 |
+
}
|
127 |
+
};
|
128 |
+
|
129 |
// 获取所有 spaces 列表(包括私有)
|
130 |
app.get('/api/proxy/spaces', async (req, res) => {
|
131 |
try {
|
|
|
189 |
}
|
190 |
});
|
191 |
|
192 |
+
// 代理重启 Space(需要认证)
|
193 |
+
app.post('/api/proxy/restart/:repoId(*)', authenticateToken, async (req, res) => {
|
194 |
try {
|
195 |
const { repoId } = req.params;
|
196 |
console.log(`尝试重启 Space: ${repoId}`);
|
|
|
216 |
}
|
217 |
});
|
218 |
|
219 |
+
// 代理重建 Space(需要认证)
|
220 |
+
app.post('/api/proxy/rebuild/:repoId(*)', authenticateToken, async (req, res) => {
|
221 |
try {
|
222 |
const { repoId } = req.params;
|
223 |
console.log(`尝试重建 Space: ${repoId}`);
|
|
|
404 |
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
405 |
});
|
406 |
|
407 |
+
// 定期清理过期的会话
|
408 |
+
setInterval(() => {
|
409 |
+
const now = Date.now();
|
410 |
+
for (const [token, session] of sessions.entries()) {
|
411 |
+
if (session.expiresAt < now) {
|
412 |
+
sessions.delete(token);
|
413 |
+
console.log(`Token ${token.slice(0, 8)}... 已过期,自动清理`);
|
414 |
+
}
|
415 |
+
}
|
416 |
+
}, 60 * 60 * 1000); // 每小时清理一次
|
417 |
+
|
418 |
app.listen(port, () => {
|
419 |
console.log(`Server running on port ${port}`);
|
420 |
console.log(`User configurations:`, usernames.map(user => `${user}: ${userTokenMapping[user] ? 'Token Configured' : 'No Token'}`).join(', ') || 'None');
|