-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.mjs
More file actions
126 lines (108 loc) · 3.69 KB
/
Copy pathserver.mjs
File metadata and controls
126 lines (108 loc) · 3.69 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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { createServer } from "node:http";
import { readFile } from "node:fs/promises";
import { extname, join, normalize } from "node:path";
import { fileURLToPath } from "node:url";
const root = fileURLToPath(new URL(".", import.meta.url));
const publicDir = join(root, "public");
const port = Number(process.env.PORT || 5173);
const upstream = "https://api.predalpha.xyz/api/markets/rewards";
const predictApi = "https://api.predict.fun/v1";
const mime = new Map([
[".html", "text/html; charset=utf-8"],
[".css", "text/css; charset=utf-8"],
[".js", "text/javascript; charset=utf-8"],
[".mjs", "text/javascript; charset=utf-8"],
[".json", "application/json; charset=utf-8"],
[".svg", "image/svg+xml"],
]);
let cache = {
at: 0,
body: null,
};
function send(res, status, body, type = "text/plain; charset=utf-8") {
res.writeHead(status, {
"content-type": type,
"cache-control": "no-store",
});
res.end(body);
}
async function proxyRewards(res) {
const now = Date.now();
if (cache.body && now - cache.at < 15_000) {
send(res, 200, cache.body, "application/json; charset=utf-8");
return;
}
const headers = {
accept: "application/json",
"user-agent": "predict-rewards-monitor/1.0",
};
if (process.env.PREDALPHA_API_KEY) {
headers["x-api-key"] = process.env.PREDALPHA_API_KEY;
}
try {
const upstreamRes = await fetch(upstream, { headers });
const body = await upstreamRes.text();
if (!upstreamRes.ok) {
send(res, upstreamRes.status, body || `Upstream HTTP ${upstreamRes.status}`);
return;
}
cache = { at: now, body };
send(res, 200, body, "application/json; charset=utf-8");
} catch (error) {
send(res, 502, JSON.stringify({ error: error.message }), "application/json; charset=utf-8");
}
}
async function proxyOrderbook(marketId, res) {
if (!process.env.PREDICT_API_KEY) {
send(res, 500, JSON.stringify({ error: "predict_api_key_not_configured" }), "application/json; charset=utf-8");
return;
}
try {
const upstreamRes = await fetch(`${predictApi}/markets/${encodeURIComponent(marketId)}/orderbook`, {
headers: {
accept: "application/json",
"x-api-key": process.env.PREDICT_API_KEY,
},
});
const body = await upstreamRes.text();
if (!upstreamRes.ok) {
send(res, upstreamRes.status, body || `Upstream HTTP ${upstreamRes.status}`);
return;
}
const payload = JSON.parse(body);
send(res, 200, JSON.stringify({ orderbook: payload?.data || payload }), "application/json; charset=utf-8");
} catch (error) {
send(res, 502, JSON.stringify({ error: error.message }), "application/json; charset=utf-8");
}
}
async function serveStatic(req, res) {
const url = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
let pathname = decodeURIComponent(url.pathname);
if (pathname === "/") pathname = "/index.html";
const normalized = normalize(pathname).replace(/^(\.\.[/\\])+/, "");
const filePath = join(publicDir, normalized);
if (!filePath.startsWith(publicDir)) {
send(res, 403, "Forbidden");
return;
}
try {
const data = await readFile(filePath);
send(res, 200, data, mime.get(extname(filePath)) || "application/octet-stream");
} catch {
send(res, 404, "Not found");
}
}
createServer((req, res) => {
if (req.url?.startsWith("/api/markets/rewards")) {
proxyRewards(res);
return;
}
const orderbookMatch = req.url?.match(/^\/api\/markets\/([^/?]+)\/orderbook(?:[?].*)?$/);
if (orderbookMatch) {
proxyOrderbook(decodeURIComponent(orderbookMatch[1]), res);
return;
}
serveStatic(req, res);
}).listen(port, () => {
console.log(`Predict rewards monitor running at http://localhost:${port}`);
});