File size: 5,276 Bytes
b7c3405
018314f
 
b7c3405
018314f
 
 
 
 
 
6279ff0
 
 
 
 
6acb2cb
b7c3405
6279ff0
 
 
 
e457032
1e6a865
b7c3405
 
 
 
 
 
 
 
6279ff0
 
6acb2cb
6279ff0
6acb2cb
6279ff0
 
 
 
6acb2cb
 
6279ff0
6acb2cb
 
6279ff0
 
6acb2cb
 
 
6279ff0
6acb2cb
 
3f54b86
 
6279ff0
6acb2cb
6279ff0
 
 
 
 
 
 
6acb2cb
6279ff0
 
 
 
b7c3405
e457032
b7c3405
e457032
 
 
b7c3405
1e6a865
 
81e95f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e457032
b7c3405
6acb2cb
 
6279ff0
6acb2cb
 
6279ff0
6acb2cb
6279ff0
6acb2cb
6279ff0
 
6acb2cb
6279ff0
6acb2cb
6279ff0
 
6acb2cb
 
 
6279ff0
6acb2cb
 
1e6a865
6acb2cb
 
 
6279ff0
 
6acb2cb
6279ff0
6acb2cb
6279ff0
6acb2cb
 
 
 
 
6279ff0
 
6acb2cb
 
6279ff0
 
6acb2cb
6279ff0
 
6acb2cb
6279ff0
 
 
 
 
 
b7c3405
 
6279ff0
b7c3405
6279ff0
1e6a865
b7c3405
e457032
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
// === 全局异常处理(放在顶部) ===
process.on('uncaughtException', (err) => {
    console.error('[Fatal Error] Uncaught Exception:', err.stack || err.message || err);
    process.exit(1); // 可选择退出服务进程
});

process.on('unhandledRejection', (reason, promise) => {
    console.error('[Warning] Unhandled Rejection at:', promise, 'reason:', reason);
});

// === 引入依赖 ===
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const requestIp = require('request-ip');
const crypto = require('crypto'); // 用于生成设备指纹的哈希值
const { URL } = require('url');  // 用于验证 URL 格式

const app = express();

// === 配置常量 ===
const PORT = process.env.PORT || 7860; // 动态分配的端口
const HOST = '0.0.0.0';

// 检查 PORT 是否有效
if (!PORT) {
    console.error("[Error] PORT environment variable is undefined. This is required by Hugging Face Spaces.");
    process.exit(1); // 如果 PORT 未定义,立即退出
}

console.log(`Starting server with HOST: ${HOST}, PORT: ${PORT}`);

// === 中间件配置 ===
// CORS 配置
const corsOptions = {
    origin: '*', // 允许所有来源的请求
    methods: ['GET', 'POST', 'OPTIONS'],
    allowedHeaders: ['Content-Type'],
};
app.use(cors(corsOptions));

// 使用 Body-Parser 解析 JSON 请求体
app.use(bodyParser.json());

// 使用 request-ip 中间件获取客户端 IP
app.use(requestIp.mw());

// === 内存存储及清理 ===

// URL 存储字典(以用户唯一标识符为键)
const urlMap = new Map();

// 超时时间配置(以毫秒为单位)
const EXPIRATION_TIME = 5 * 60 * 1000; // 数据保存5分钟
const CLEANUP_INTERVAL = 5.1 * 60 * 1000; // 每 5分6 秒清理一次

// 定时清理过期数据
setInterval(() => {
    const now = Date.now();
    const expiredTime = now - EXPIRATION_TIME;

    for (const [userId, { timestamp }] of urlMap) {
        if (timestamp < expiredTime) {
            console.log(`Deleting expired data for user: ${userId}`);
            urlMap.delete(userId); // 删除过期数据
        }
    }
}, CLEANUP_INTERVAL);

// 健康检查路由
app.get('/', (req, res) => {
    res.status(200).json({
        message: "Server is running with backup port.",
        port: PORT || "undefined",
        environment: process.env,
    });
});

// === 辅助函数 ===
// 生成设备指纹
const generateDeviceFingerprint = (req) => {
    const ip = req.clientIp || '';
    const userAgent = req.headers['user-agent'] || '';
    const acceptLanguage = req.headers['accept-language'] || '';
    const connection = req.headers['connection'] || '';
    const encoding = req.headers['accept-encoding'] || '';
    const forwardedFor = req.headers['x-forwarded-for'] || '';

    // 将关键信息合并生成唯一指纹
    const rawFingerprint = `${ip}-${userAgent}-${acceptLanguage}-${connection}-${encoding}-${forwardedFor}`;

    // 使用 SHA-256 哈希算法生成指纹
    const fingerprint = crypto.createHash('sha256').update(rawFingerprint).digest('hex');
    return fingerprint;
};

// === 路由与业务逻辑 ===

// 存储 URL(POST 请求)
app.post('/storeURL', (req, res) => {
    const url = req.body.url; // 从请求体中解析 URL
    const ip = req.clientIp; // 获取客户端 IP

    // 验证 URL 是否存在并合法
    if (!url) {
        return res.status(400).json({ error: 'URL is required.' });
    }
    try {
        new URL(url); // 验证 URL 格式
    } catch (err) {
        return res.status(400).json({ error: 'Invalid URL format.' });
    }

    // 生成用户唯一标识符(包括 IP 和设备指纹)
    const deviceFingerprint = generateDeviceFingerprint(req);
    const userId = `${ip}-${deviceFingerprint}`; // 结合 IP 和设备指纹生成唯一标识符

    // 存储到字典中
    urlMap.set(userId, { url, timestamp: Date.now() });
    console.log(`Stored URL for user: ${userId}`);

    // 返回成功响应
    res.json({ message: 'URL stored successfully.', userId });
});

// 获取 URL(GET 请求)
app.get('/getURL', (req, res) => {
    const ip = req.clientIp; // 获取客户端 IP

    // 生成用户唯一标识符(包括 IP 和设备指纹)
    const deviceFingerprint = generateDeviceFingerprint(req);
    const userId = `${ip}-${deviceFingerprint}`;

    // 查询字典获取存储的 URL
    if (urlMap.has(userId)) {
        const storedData = urlMap.get(userId);
        storedData.timestamp = Date.now(); // 更新数据时间戳
        urlMap.set(userId, storedData); // 保存更新后的数据

        console.log(`Retrieved URL for user: ${userId}`);
        return res.json({ url: storedData.url });
    } else {
        console.error(`No URL found for user: ${userId}`);
        return res.status(404).json({ error: 'URL not found for this user.' });
    }
});

// === 启动服务器 ===
app.listen(PORT, HOST, (err) => {
    if (err) {
        console.error("[Error] Server failed to start:", err);
        process.exit(1); // 如果存在错误,立即退出
    }
    console.log(`Server successfully started on http://${HOST}:${PORT}`);
});

// 打印环境变量(调试使用)
console.log("Full Environment Variables:", process.env);