getzero11 commited on
Commit
67c1aad
·
verified ·
1 Parent(s): d6de4c9

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +179 -17
server.js CHANGED
@@ -4,30 +4,192 @@ import { spawn } from "child_process";
4
  const app = express();
5
  app.use(express.json());
6
 
7
- app.get("/", (_, res) => {
8
- res.json({ status: "OpenClaw Space running" });
 
 
 
 
 
 
 
 
 
 
9
  });
10
 
11
- app.post("/run", (req, res) => {
12
- const proc = spawn(
13
- "node",
14
- ["src/index.js"],
15
- {
16
- cwd: "/app/openclaw",
17
- env: process.env
18
- }
19
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
- let output = "";
 
 
22
 
23
- proc.stdout.on("data", d => output += d.toString());
24
- proc.stderr.on("data", d => output += d.toString());
25
 
26
- proc.on("close", code => {
27
- res.json({ exitCode: code, output });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  });
29
  });
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  app.listen(7860, () => {
32
- console.log("🚀 OpenClaw wrapper listening on 7860");
33
  });
 
4
  const app = express();
5
  app.use(express.json());
6
 
7
+ /* ===============================
8
+ 1. BASIC AUTH
9
+ ================================ */
10
+
11
+ const GATE_KEY = process.env.OPENCLAW_GATE_KEY;
12
+
13
+ app.use((req, res, next) => {
14
+ if (!GATE_KEY) return next();
15
+ if (req.headers["x-openclaw-key"] !== GATE_KEY) {
16
+ return res.status(401).json({ error: "Unauthorized" });
17
+ }
18
+ next();
19
  });
20
 
21
+ /* ===============================
22
+ 2. RATE LIMITING (IP-based)
23
+ ================================ */
24
+
25
+ const RATE_LIMIT = 30; // requests
26
+ const WINDOW_MS = 60_000;
27
+ const ipHits = new Map();
28
+
29
+ app.use((req, res, next) => {
30
+ const ip = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
31
+ const now = Date.now();
32
+
33
+ const record = ipHits.get(ip) || { count: 0, ts: now };
34
+ if (now - record.ts > WINDOW_MS) {
35
+ record.count = 0;
36
+ record.ts = now;
37
+ }
38
+
39
+ record.count++;
40
+ ipHits.set(ip, record);
41
+
42
+ if (record.count > RATE_LIMIT) {
43
+ return res.status(429).json({ error: "Rate limit exceeded" });
44
+ }
45
+ next();
46
+ });
47
+
48
+ /* ===============================
49
+ 3. LOAD KEY POOLS
50
+ ================================ */
51
+
52
+ function loadPool(prefix) {
53
+ return Object.keys(process.env)
54
+ .filter(k => k.startsWith(prefix))
55
+ .map(k => process.env[k])
56
+ .filter(Boolean);
57
+ }
58
+
59
+ const PROVIDERS = {
60
+ openai: loadPool("OPENAI_API_KEY_"),
61
+ deepseek: loadPool("DEEPSEEK_API_KEY_"),
62
+ gemini: loadPool("GEMINI_API_KEY_"),
63
+ openrouter: loadPool("OPENROUTER_API_KEY_"),
64
+ dashscope: loadPool("DASHSCOPE_API_KEY_")
65
+ };
66
+
67
+ function randomKey(pool) {
68
+ return pool[Math.floor(Math.random() * pool.length)];
69
+ }
70
+
71
+ /* ===============================
72
+ 4. TASK ROUTING
73
+ ================================ */
74
+
75
+ const TASKS = new Set([
76
+ "market_research",
77
+ "summarize",
78
+ "classify"
79
+ ]);
80
+
81
+ /* ===============================
82
+ 5. RUN AGENT
83
+ ================================ */
84
+ app.use((req, res, next) => {
85
+ if (req.method === "POST" && !req.is("application/json")) {
86
+ return res.status(400).json({ error: "JSON body required" });
87
+ }
88
+ next();
89
+ });
90
+
91
+ app.post("/run", async (req, res) => {
92
+ const { task, provider, model, ...payload } = req.body;
93
+
94
+ if (!TASKS.has(task)) {
95
+ return res.status(400).json({ error: "Unknown task" });
96
+ }
97
 
98
+ const providersToTry = provider
99
+ ? [provider, ...Object.keys(PROVIDERS).filter(p => p !== provider)]
100
+ : Object.keys(PROVIDERS);
101
 
102
+ let lastError;
 
103
 
104
+ for (const p of providersToTry) {
105
+ const pool = PROVIDERS[p];
106
+ if (!pool || pool.length === 0) continue;
107
+
108
+ for (let i = 0; i < pool.length; i++) {
109
+ const apiKey = randomKey(pool);
110
+
111
+ const env = {
112
+ ...process.env,
113
+ OPENCLAW_PROVIDER: p,
114
+ OPENCLAW_MODEL: model || "",
115
+ OPENCLAW_API_KEY: apiKey,
116
+ OPENCLAW_TASK: task
117
+ };
118
+
119
+ try {
120
+ const result = await runOpenClaw(env, payload);
121
+ return res.json(result);
122
+ } catch (err) {
123
+ lastError = err;
124
+ if (!isRateLimit(err)) break;
125
+ }
126
+ }
127
+ }
128
+
129
+ res.status(500).json({
130
+ error: "All providers failed",
131
+ details: lastError?.message
132
  });
133
  });
134
 
135
+ /* ===============================
136
+ 6. EXECUTION + JSON PARSE
137
+ ================================ */
138
+
139
+ function runOpenClaw(env, payload) {
140
+ return new Promise((resolve, reject) => {
141
+ const proc = spawn("node", ["src/index.js"], {
142
+ cwd: "/app/openclaw",
143
+ env
144
+ });
145
+
146
+ let out = "";
147
+ let err = "";
148
+
149
+ const timeout = setTimeout(() => {
150
+ proc.kill("SIGKILL");
151
+ reject(new Error("Agent timeout"));
152
+ }, 120000); // 2 minutes
153
+
154
+ proc.stdout.on("data", d => out += d.toString());
155
+ proc.stderr.on("data", d => err += d.toString());
156
+
157
+ proc.on("close", code => {
158
+ clearTimeout(timeout);
159
+
160
+ if (code !== 0) {
161
+ return reject(new Error(err || "Execution failed"));
162
+ }
163
+
164
+ try {
165
+ const json = JSON.parse(out);
166
+ resolve(json);
167
+ } catch {
168
+ reject(new Error("Invalid JSON output from agent"));
169
+ }
170
+ });
171
+
172
+ proc.stdin.write(JSON.stringify(payload));
173
+ proc.stdin.end();
174
+ });
175
+ }
176
+
177
+
178
+ function isRateLimit(err) {
179
+ const msg = err.message?.toLowerCase() || "";
180
+ return (
181
+ msg.includes("429") ||
182
+ msg.includes("rate") ||
183
+ msg.includes("quota") ||
184
+ msg.includes("limit")
185
+ );
186
+ }
187
+
188
+
189
+ /* ===============================
190
+ 7. START
191
+ ================================ */
192
+
193
  app.listen(7860, () => {
194
+ console.log("🚀 OpenClaw Agent Gateway running");
195
  });