-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
110 lines (97 loc) · 3.79 KB
/
Copy pathserver.js
File metadata and controls
110 lines (97 loc) · 3.79 KB
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
import { createServer } from 'node:http';
import { readFileSync, readdirSync, existsSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
// Load worker module
const worker = await import('./worker.js');
const handler = worker.default;
// === Build env from config ===
// Read tokens from credentials/ directory
const credDir = resolve(__dirname, 'credentials');
let tokenLines = [];
if (existsSync(credDir)) {
for (const f of readdirSync(credDir)) {
if (!f.endsWith('.json')) continue;
try {
const raw = readFileSync(resolve(credDir, f), 'utf-8');
const obj = JSON.parse(raw);
// 单账号格式:顶层 authToken(credentials/<name>.json)
if (obj.authToken) tokenLines.push(obj.authToken.trim());
// 多账号聚合格式(freebuff_credentials.json):accounts.<key>.authToken
if (obj.accounts && typeof obj.accounts === 'object') {
for (const acct of Object.values(obj.accounts)) {
if (acct && acct.authToken) tokenLines.push(acct.authToken.trim());
}
}
} catch (err) {
console.error(`[server] skip bad credential ${f}: ${err.message}`);
}
}
}
// Also allow FREEBUFF_TOKEN env var for non-credential token sources
const envToken = process.env.FREEBUFF_TOKEN || '';
if (envToken) {
for (const tok of envToken.split(/[\n,]/)) {
const t = tok.trim();
if (t && !tokenLines.includes(t)) tokenLines.push(t);
}
}
const env = {
FREEBUFF_TOKEN: tokenLines.join(','),
FREEBUFF_API_KEY: process.env.FREEBUFF_API_KEY || 'freebuff-default-key',
FREEBUFF_DEBUG: process.env.FREEBUFF_DEBUG || 'false',
CODEBUFF_API: process.env.CODEBUFF_API || '',
RELAY_KEY: process.env.RELAY_KEY || '',
};
console.log(`[server] start: ${tokenLines.length} tokens, apiKey=${env.FREEBUFF_API_KEY.slice(0,8)}..., debug=${env.FREEBUFF_DEBUG}`);
if (env.CODEBUFF_API) console.log(`[server] CODEBUFF_API=${env.CODEBUFF_API}`);
if (env.RELAY_KEY) console.log(`[server] RELAY_KEY set`);
// === HTTP server ===
const port = parseInt(process.env.PORT || '8787', 10);
const host = process.env.HOST || '0.0.0.0';
const server = createServer(async (nodeReq, nodeRes) => {
try {
// Build array of raw bytes from Node request
const chunks = [];
for await (const chunk of nodeReq) chunks.push(chunk);
const body = Buffer.concat(chunks);
// Build a CF-compatible Request
const url = `http://${nodeReq.headers.host || 'localhost'}${nodeReq.url}`;
const request = new Request(url, {
method: nodeReq.method,
headers: new Headers(nodeReq.headers),
body: body.length > 0 ? body : null,
});
// Call the worker's fetch handler
const response = await handler.fetch(request, env);
// Write response back to Node socket
nodeRes.writeHead(response.status, Object.fromEntries(response.headers.entries()));
if (response.body) {
const reader = response.body.getReader();
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
if (value) nodeRes.write(Buffer.from(value));
}
} catch (err) {
// Stream errors are expected on client disconnect
if (!nodeRes.writableEnded) nodeRes.end();
return;
}
}
if (!nodeRes.writableEnded) nodeRes.end();
} catch (err) {
console.error('[server] request error:', err.message);
if (!nodeRes.headersSent) {
nodeRes.writeHead(502, { 'content-type': 'application/json' });
nodeRes.end(JSON.stringify({ error: { message: 'proxy error', type: 'proxy_error' } }));
} else if (!nodeRes.writableEnded) {
nodeRes.end();
}
}
});
server.listen(port, host, () => {
console.log(`[server] listening on ${host}:${port}`);
});