habppyar commited on
Commit
41f0983
·
verified ·
1 Parent(s): c71851f

Create server.js

Browse files
Files changed (1) hide show
  1. server.js +151 -0
server.js ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // server.js
2
+ const http = require('http');
3
+ const os = require('os');
4
+ const fs = require('fs');
5
+ const { exec } = require('child_process');
6
+ const path = require('path');
7
+
8
+ // --- Hugging Face Spaces 核心配置 ---
9
+ // 必须监听所有接口,以响应外部请求
10
+ const HOST = '0.0.0.0';
11
+ // 必须使用 Hugging Face 指定的端口
12
+ const PORT = process.env.PORT || 7860;
13
+
14
+ // --- 辅助函数:获取磁盘使用情况 ---
15
+ function getDiskUsage() {
16
+ try {
17
+ const stats = fs.statfsSync('/'); // 获取根目录的磁盘信息
18
+ const total = stats.bsize * stats.blocks;
19
+ const free = stats.bsize * stats.bfree;
20
+ const used = total - free;
21
+ const usagePercent = ((used / total) * 100).toFixed(2);
22
+ return {
23
+ total: (total / (1024 ** 3)).toFixed(2), // GB
24
+ used: (used / (1024 ** 3)).toFixed(2), // GB
25
+ free: (free / (1024 ** 3)).toFixed(2), // GB
26
+ usagePercent: `${usagePercent}%`
27
+ };
28
+ } catch (error) {
29
+ return { error: '无法获取磁盘信息' };
30
+ }
31
+ }
32
+
33
+ // --- 辅助函数:获取出口公网IP(cURL方式)---
34
+ function getPublicIP() {
35
+ return new Promise(resolve => {
36
+ // Hugging Face Spaces 容器内通常可以访问外部网络
37
+ exec('curl -s --max-time 5 ifconfig.me', (err, stdout) => {
38
+ if (err) {
39
+ resolve('无法获取公网IP (可能为NAT环境)');
40
+ } else {
41
+ resolve(stdout.trim());
42
+ }
43
+ });
44
+ });
45
+ }
46
+
47
+ // --- 辅助函数:获取所有环境变量(过滤掉敏感信息)---
48
+ function getSafeEnvVars() {
49
+ const safeVars = {};
50
+ const sensitiveKeys = ['PASSWORD', 'SECRET', 'TOKEN', 'KEY'];
51
+ for (const [key, value] of Object.entries(process.env)) {
52
+ if (sensitiveKeys.some(k => key.toLowerCase().includes(k.toLowerCase()))) {
53
+ safeVars[key] = '****** (已隐藏)';
54
+ } else {
55
+ safeVars[key] = value;
56
+ }
57
+ }
58
+ return safeVars;
59
+ }
60
+
61
+ // --- 创建 HTTP 服务器 ---
62
+ const server = http.createServer(async (req, res) => {
63
+ // 1. 获取动态信息
64
+ const publicIP = await getPublicIP();
65
+ const diskInfo = getDiskUsage();
66
+
67
+ // 2. 系统与硬件信息 (通过 os 模块)
68
+ const cpuInfo = os.cpus()[0];
69
+ const totalMem = (os.totalmem() / (1024 ** 3)).toFixed(2); // GB
70
+ const freeMem = (os.freemem() / (1024 ** 3)).toFixed(2); // GB
71
+ const usedMem = (totalMem - freeMem).toFixed(2); // GB
72
+ const systemUptime = Math.floor(os.uptime() / 60) + ' 分钟';
73
+
74
+ // 3. 关键环境检查
75
+ const isNodePathSet = !!process.env.NODE_PATH;
76
+ const isDataDirWritable = fs.accessSync('/data', fs.constants.W_OK) === undefined; // 检查 /data 是否可写
77
+ const isHfHomeSet = !!process.env.HF_HOME;
78
+
79
+ // 4. 构建用于展示的数据模型
80
+ const envReport = {
81
+ // ========== 1. 访问信息 ==========
82
+ access: {
83
+ spaceUrl: `https://${process.env.SPACE_ID?.replace('/', '-')}.hf.space` || '未知 (请通过公网域名访问)',
84
+ publicIP: publicIP,
85
+ internalIP: (() => {
86
+ const interfaces = os.networkInterfaces();
87
+ for (const iface of Object.values(interfaces)) {
88
+ for (const addr of iface) {
89
+ if (addr.family === 'IPv4' && !addr.internal) return addr.address;
90
+ }
91
+ }
92
+ return '127.0.0.1';
93
+ })(),
94
+ hostname: os.hostname(),
95
+ spaceId: process.env.SPACE_ID || '未知',
96
+ spaceRepoName: process.env.SPACE_REPO_NAME || '未知',
97
+ },
98
+ // ========== 2. 硬件资源 (免费层标准) ==========
99
+ hardware: {
100
+ cpuModel: cpuInfo?.model || '未知',
101
+ cpuCores: os.cpus().length,
102
+ totalRamGB: totalMem,
103
+ usedRamGB: usedMem,
104
+ freeRamGB: freeMem,
105
+ disk: diskInfo,
106
+ uptime: systemUptime,
107
+ expectedFreeTier: '2 vCPU / 16GB RAM / 50GB 临时磁盘'
108
+ },
109
+ // ========== 3. Node.js 环境 ==========
110
+ nodeEnv: {
111
+ version: process.version,
112
+ platform: process.platform,
113
+ arch: process.arch,
114
+ execPath: process.execPath,
115
+ cwd: process.cwd(),
116
+ nodePath: isNodePathSet ? process.env.NODE_PATH : '未设置'
117
+ },
118
+ // ========== 4. 容器与权限 ==========
119
+ container: {
120
+ userId: process.getuid?.(),
121
+ groupId: process.getgid?.(),
122
+ expectedUserId: '1000 (Hugging Face 默认用户ID)',
123
+ isDataDirWritable: isDataDirWritable,
124
+ hfHome: process.env.HF_HOME || '未设置 (可设置为 /data/.huggingface 加速重启)',
125
+ // 检测是否使用了 Persistent Storage
126
+ persistentStorageMounted: fs.existsSync('/data'),
127
+ },
128
+ // ========== 5. 关键环境变量 (安全过滤) ==========
129
+ envVars: getSafeEnvVars(),
130
+ // ========== 6. 部署建议 ==========
131
+ suggestions: [
132
+ '✅ 必须监听 0.0.0.0,并在 README.md 中设置 app_port: 7860',
133
+ '✅ 强烈建议为敏感信息(如 OPENCODE_PASSWORD)使用 HF Secrets,勿硬编码',
134
+ '✅ 如需数据持久化,请考虑升级 Persistent Storage 或将数据备份到 HF Dataset',
135
+ '✅ 容器默认以用户 ID 1000 运行,Dockerfile 中需创建此用户避免权限问题',
136
+ '✅ 可设置 HF_HOME=/data/.huggingface 以加速 Hugging Face 库的重复启动',
137
+ ]
138
+ };
139
+
140
+ // 5. 输出美观的 JSON 报告
141
+ res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
142
+ res.end(JSON.stringify(envReport, null, 2));
143
+ });
144
+
145
+ // 启动服务器
146
+ server.listen(PORT, HOST, () => {
147
+ console.log(`🔍 Hugging Face Spaces 环境探针已启动`);
148
+ console.log(`📡 监听地址: http://${HOST}:${PORT}`);
149
+ console.log(`🌐 公网访问: https://${process.env.SPACE_ID?.replace('/', '-') || 'your-space'}.hf.space`);
150
+ console.log(`💡 提示: 访问上述 URL 即可查看详细的环境报告 JSON`);
151
+ });