testdocker / server.js
habppyar's picture
Update server.js
e094011 verified
// server.js
const http = require('http');
const os = require('os');
const fs = require('fs');
const { exec } = require('child_process');
// --- Hugging Face Spaces 核心配置 ---
const HOST = '0.0.0.0';
const PORT = process.env.PORT || 7860;
// --- 辅助函数:获取磁盘使用情况(需要处理 /data 可能不存在)---
function getDiskUsage() {
try {
// 获取当前工作目录所在的文件系统(通常是容器根目录)
const stats = fs.statfsSync('/');
const total = stats.bsize * stats.blocks;
const free = stats.bsize * stats.bfree;
const used = total - free;
const usagePercent = ((used / total) * 100).toFixed(2);
return {
total: (total / (1024 ** 3)).toFixed(2),
used: (used / (1024 ** 3)).toFixed(2),
free: (free / (1024 ** 3)).toFixed(2),
usagePercent: `${usagePercent}%`
};
} catch (error) {
return { error: '无法获取磁盘信息' };
}
}
// --- 辅助函数:获取出口公网IP---
function getPublicIP() {
return new Promise(resolve => {
exec('curl -s --max-time 5 ifconfig.me', (err, stdout) => {
if (err) resolve('无法获取公网IP (可能为NAT环境)');
else resolve(stdout.trim());
});
});
}
// --- 辅助函数:安全获取环境变量---
function getSafeEnvVars() {
const safeVars = {};
const sensitiveKeys = ['PASSWORD', 'SECRET', 'TOKEN', 'KEY'];
for (const [key, value] of Object.entries(process.env)) {
if (sensitiveKeys.some(k => key.toLowerCase().includes(k.toLowerCase()))) {
safeVars[key] = '****** (已隐藏)';
} else {
safeVars[key] = value;
}
}
return safeVars;
}
// --- 辅助函数:检查 /data 目录状态(兼容不存在的情况)---
function checkDataDir() {
try {
if (fs.existsSync('/data')) {
// 目录存在,检查是否可写
fs.accessSync('/data', fs.constants.W_OK);
return { exists: true, writable: true };
} else {
return { exists: false, writable: false, reason: '目录不存在(免费层未挂载持久存储)' };
}
} catch (err) {
return { exists: true, writable: false, reason: err.message };
}
}
// --- 创建 HTTP 服务器 ---
const server = http.createServer(async (req, res) => {
// 1. 动态信息
const publicIP = await getPublicIP();
const diskInfo = getDiskUsage();
const dataDirStatus = checkDataDir();
// 2. 系统与硬件信息
const cpuInfo = os.cpus()[0];
const totalMem = (os.totalmem() / (1024 ** 3)).toFixed(2);
const freeMem = (os.freemem() / (1024 ** 3)).toFixed(2);
const usedMem = (totalMem - freeMem).toFixed(2);
const systemUptime = Math.floor(os.uptime() / 60) + ' 分钟';
// 3. 用户ID和权限
let userId = null, groupId = null;
try {
userId = process.getuid();
groupId = process.getgid();
} catch(e) { /* Windows 可能不支持 */ }
// 4. 构建环境报告
const envReport = {
// 访问信息
access: {
spaceUrl: `https://${process.env.SPACE_ID?.replace('/', '-') || 'unknown'}.hf.space`,
publicIP: publicIP,
internalIP: (() => {
const interfaces = os.networkInterfaces();
for (const iface of Object.values(interfaces)) {
for (const addr of iface) {
if (addr.family === 'IPv4' && !addr.internal) return addr.address;
}
}
return '127.0.0.1';
})(),
hostname: os.hostname(),
spaceId: process.env.SPACE_ID || '未设置',
spaceRepoName: process.env.SPACE_REPO_NAME || '未设置',
},
// 硬件资源
hardware: {
cpuModel: cpuInfo?.model || '未知',
cpuCores: os.cpus().length,
totalRamGB: totalMem,
usedRamGB: usedMem,
freeRamGB: freeMem,
disk: diskInfo,
uptime: systemUptime,
expectedFreeTier: '2 vCPU / 16GB RAM / 50GB 临时磁盘'
},
// Node.js 环境
nodeEnv: {
version: process.version,
platform: process.platform,
arch: process.arch,
execPath: process.execPath,
cwd: process.cwd(),
},
// 容器与权限
container: {
userId: userId,
groupId: groupId,
expectedUserId: '通常为 1000 (node 用户)',
isDataDirPresent: dataDirStatus.exists,
isDataDirWritable: dataDirStatus.writable,
dataDirDetail: dataDirStatus.reason || (dataDirStatus.writable ? '可写' : '不可写'),
hfHome: process.env.HF_HOME || '未设置',
persistentStorageAvailable: dataDirStatus.exists && dataDirStatus.writable,
},
// 关键环境变量(安全过滤)
envVars: getSafeEnvVars(),
// 部署建议
suggestions: [
'✅ 必须监听 0.0.0.0,并在 README.md 中设置 app_port: 7860',
'✅ 强烈建议为敏感信息使用 HF Secrets,勿硬编码',
'✅ 免费层磁盘非持久化,重启会丢失数据',
'✅ 如需持久化,考虑升级 Persistent Storage 或将数据备份到 HF Dataset',
'✅ 容器默认用户 UID 可能为 1000,Dockerfile 中建议使用现有 node 用户',
]
};
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
res.end(JSON.stringify(envReport, null, 2));
});
// 启动服务器
server.listen(PORT, HOST, () => {
console.log(`🔍 Hugging Face Spaces 环境探针已启动`);
console.log(`📡 监听地址: http://${HOST}:${PORT}`);
console.log(`🌐 公网访问: https://${process.env.SPACE_ID?.replace('/', '-') || 'your-space'}.hf.space`);
console.log(`💡 提示: 访问上述 URL 即可查看详细的环境报告 JSON`);
});