GUI-STUDIO commited on
Commit
63aa82b
·
1 Parent(s): 125ba72

Refactor env var access to simplify logic

Browse files

This commit refactors how environment variables are accessed across
different runtimes (Bun, Node.js, and browser) to simplify the logic. It
also consolidates the checks for `IS_BUN || IS_NODE` where appropriate,
as the access method is the same for both.

Additionally, it removes an unnecessary environment variable
`NODE_TLS_REJECT_UNAUTHORIZED` from the `frontendV3` Vercel
configuration. A new `workers-proxy.ts` file has been added to manage
proxying for Cloudflare Workers.

Files changed (2) hide show
  1. src/index.ts +28 -1
  2. src/proxy/workers-proxy.ts +239 -0
src/index.ts CHANGED
@@ -9,11 +9,17 @@ import { FfmpegRouter } from "./sub-router/ffmpeg";
9
  import { ShowtimeRouter } from "./sub-router/showtime";
10
  import { TestRouter } from "./sub-router/test";
11
  import { NS_runtime } from "../../../../packages/lib/env.runtime";
 
 
 
 
12
 
13
  const APP_ENV = process.env.APP_ENV;
14
  const APP_ORIGIN = process.env.APP_ORIGIN;
15
  const PORT = process.env.PORT;
16
 
 
 
17
  const app = new Elysia()
18
 
19
  .use(
@@ -64,10 +70,31 @@ const app = new Elysia()
64
  .use(FfmpegRouter)
65
  .use(TestRouter)
66
 
67
- .get("/", () => {
68
  return "🦊 Hello Rafiki 🍿";
69
  })
70
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  .listen({
72
  port: PORT || 7860,
73
  ...(NS_runtime.IS_PROD && { hostname: "0.0.0.0" }),
 
9
  import { ShowtimeRouter } from "./sub-router/showtime";
10
  import { TestRouter } from "./sub-router/test";
11
  import { NS_runtime } from "../../../../packages/lib/env.runtime";
12
+ import { NS_workers_proxy } from "../../../../packages/lib/proxy-server/workers-proxy";
13
+
14
+ const { rewriteWorkersUrl, startWorkersProxy, rewriteWorkersUrl_t2, get_dns } =
15
+ NS_workers_proxy;
16
 
17
  const APP_ENV = process.env.APP_ENV;
18
  const APP_ORIGIN = process.env.APP_ORIGIN;
19
  const PORT = process.env.PORT;
20
 
21
+ await startWorkersProxy();
22
+
23
  const app = new Elysia()
24
 
25
  .use(
 
70
  .use(FfmpegRouter)
71
  .use(TestRouter)
72
 
73
+ .get("/", async ({ request }) => {
74
  return "🦊 Hello Rafiki 🍿";
75
  })
76
 
77
+ .get("/test/p", async ({ request }) => {
78
+ const originalUrl =
79
+ "https://cool.tylerfisher55.workers.dev/afc7d47f/uz5gyMPGU9TVujalv1-l0gCq1t5YoLPmJOs0BK8vPdXqyusELznNCnUjCjs93MmANIYp__VYV9NVMM33xaH8-hxFDOQjzy6xGM8xf6yfw1YOmJhdwv2R3fFOXPVk90JFUhfo-oz1cLaYBHPnU0wPrb84UsIVRnunq3UKDSpFMLVBnEy7VJtuHl7T90GpI0EcY_xtuRtQguJ7pQqdKgGVJRP7_urSkYuXf-zAySLgY6isRw-vKYh1EnOLybifGW5Q8AT-r-BlvwNe4vDMjJ3blHFeAsSS2Z3XMfOdM0dQbJwO7o4igwfpIVILbI2YkKuRzIbaWTMXAe7f9vKUJpS5cXEG5UB3EwOm_-yobxVKvrPZqcdrG-Qteh16fTl9Ll7PiYwlA-Ebc2S0QlEWRAXsB0IZd3ixrCxSqSfHZwF6p38FGC0EeNUqW_enbS8BA_kGQhiA9q9Z4P2yxF5CN5-WBTXw6O8UMygbUNhoi-BWnk02DRu0oeyEoE2OGVrN-zRP2KNGOejNL-BbmcLd9yB0qP1Z1RF8wszuFx8x6iQUuIXCXUSGzxZAQie3dELhVWFKSj__CqTSgk8adDCyd8mYLnHzh1jFpSlDDOwF65blF6rmWcYZmgfHcSIe9mIgpkRE0zPF5J_AcvKdYSoILfKj2kzpaF_yI8DceEqCWsDojyzMQi7YO02EMx8MdmtqG9BnHtto7tEiVWZnOQJyc6BinQ.m3u8";
80
+
81
+ await get_dns({
82
+ target: originalUrl,
83
+ method: "GET",
84
+ headers: {
85
+ Referer: "https://111movies.net/"
86
+ }
87
+ });
88
+
89
+ const foo = rewriteWorkersUrl_t2(originalUrl);
90
+
91
+ const res = await fetch(foo, {
92
+ method: "GET"
93
+ });
94
+
95
+ return res;
96
+ })
97
+
98
  .listen({
99
  port: PORT || 7860,
100
  ...(NS_runtime.IS_PROD && { hostname: "0.0.0.0" }),
src/proxy/workers-proxy.ts ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as https from "node:https";
2
+ import * as http from "node:http";
3
+
4
+ export const PROXY_PORT = 18080;
5
+ let proxyServer: http.Server | null = null;
6
+
7
+ const REPO_ORIGIN = process.env.REPO_ORIGIN;
8
+
9
+ // Registry of active proxy targets — keyed by servername
10
+ const targetRegistry = new Map<
11
+ string,
12
+ {
13
+ hostname: string;
14
+ port: number;
15
+ servername: string;
16
+ headers: Record<string, string>;
17
+ path: string;
18
+ method: string;
19
+ }
20
+ >();
21
+
22
+ export function registerProxyTarget(config: {
23
+ hostname: string;
24
+ port: number;
25
+ servername: string;
26
+ headers: Record<string, string>;
27
+ path: string;
28
+ method: string;
29
+ }) {
30
+ targetRegistry.set(config.servername, config);
31
+ }
32
+
33
+ export async function get_dns(arg0: {
34
+ target: string;
35
+ method: string;
36
+ headers: Record<string, string>;
37
+ }) {
38
+ if (!REPO_ORIGIN) return;
39
+ try {
40
+ const { target, headers, method } = arg0;
41
+
42
+ const res = await fetch(`${REPO_ORIGIN}/dns/resolve`, {
43
+ method: "POST",
44
+ headers: {
45
+ "Content-Type": "application/json"
46
+ },
47
+ body: JSON.stringify({ target, method, headers })
48
+ });
49
+ const data = await res.json();
50
+
51
+ if (data && typeof data === "object" && !Array.isArray(data)) {
52
+ registerProxyTarget({
53
+ ...data
54
+ });
55
+
56
+ return data;
57
+ }
58
+ } catch {}
59
+ }
60
+
61
+ export function rewriteWorkersUrl(originalUrl: string): string {
62
+ try {
63
+ const u = new URL(originalUrl);
64
+ if (u.hostname.endsWith(".workers.dev")) {
65
+ return `http://127.0.0.1:${PROXY_PORT}/__proxy__/${u.hostname}${u.pathname}${u.search}`;
66
+ }
67
+ } catch {}
68
+ return originalUrl;
69
+ }
70
+
71
+ export function rewriteWorkersUrl_t2(originalUrl: string): string {
72
+ try {
73
+ const is_http = originalUrl.startsWith("http");
74
+
75
+ if (!is_http) return originalUrl;
76
+
77
+ const start_http = originalUrl.startsWith("https://")
78
+ ? "https://"
79
+ : "http://";
80
+ const rest = originalUrl.replace(start_http, "");
81
+
82
+ if (rest) return `http://127.0.0.1:${PROXY_PORT}/__proxy__/${rest}`;
83
+
84
+ return originalUrl;
85
+ } catch {}
86
+ return originalUrl;
87
+ }
88
+
89
+ function isM3u8(headers: http.IncomingHttpHeaders): boolean {
90
+ const ct = headers["content-type"] ?? "";
91
+ // Also check path-based detection as some servers return wrong content-type
92
+ return ct.includes("mpegurl") || ct.includes("x-mpegurl");
93
+ }
94
+
95
+ function rewriteM3u8Body(body: string): string {
96
+ console.log({ body });
97
+ return body.replace(
98
+ /https?:\/\/([a-zA-Z0-9._-]+\.workers\.dev)(:[0-9]+)?([^\s"'\n]*)/g,
99
+ (_, host, _port, rest) =>
100
+ `http://127.0.0.1:${PROXY_PORT}/__proxy__/${host}${rest}`
101
+ );
102
+ }
103
+
104
+ export async function startWorkersProxy(): Promise<void> {
105
+ if (proxyServer) return Promise.resolve(); // already running
106
+
107
+ return new Promise((resolve, reject) => {
108
+ proxyServer = http.createServer((req, res) => {
109
+ // Parse target host from /__proxy__/<host>/path or Host header
110
+ let targetHost: string;
111
+ let targetPath: string;
112
+
113
+ const proxyPrefixMatch = req.url?.match(/^\/__proxy__\/([^/]+)(\/.*)?$/);
114
+
115
+ if (proxyPrefixMatch) {
116
+ targetHost = proxyPrefixMatch[1];
117
+ targetPath = proxyPrefixMatch[2] ?? "/";
118
+ // Preserve query string
119
+ const qIndex = (req.url ?? "").indexOf(
120
+ "?",
121
+ `/__proxy__/${targetHost}`.length
122
+ );
123
+ if (qIndex !== -1) {
124
+ targetPath = proxyPrefixMatch[2]?.split("?")[0] ?? "/";
125
+ targetPath += req.url!.slice(qIndex);
126
+ }
127
+ } else {
128
+ targetHost = (req.headers["host"] ?? "").split(":")[0];
129
+ targetPath = req.url ?? "/";
130
+ }
131
+
132
+ if (!targetHost.endsWith(".workers.dev")) {
133
+ res.writeHead(400);
134
+ res.end(`[workers-proxy] unexpected host: ${targetHost}`);
135
+ return;
136
+ }
137
+
138
+ // Look up registered target or fall back to Cloudflare Anycast
139
+ const registered = (() => {
140
+ const _ = targetRegistry.get(targetHost);
141
+
142
+ return _;
143
+ })();
144
+
145
+ if (!registered) {
146
+ console.error(
147
+ `[workers-proxy] no registered target for: ${targetHost}`
148
+ );
149
+ res.writeHead(502);
150
+ res.end(`[workers-proxy] no registered target for: ${targetHost}`);
151
+ return;
152
+ }
153
+
154
+ const targetIp = registered.hostname;
155
+ const extraHeaders = registered.headers ?? {};
156
+
157
+ const options: https.RequestOptions = {
158
+ hostname: targetIp,
159
+ port: registered.port || 443,
160
+ path: registered.path || targetPath,
161
+ method: registered.method || req.method, // registered.method
162
+ servername: registered.servername || targetHost, // SNI
163
+ rejectUnauthorized: false,
164
+ headers: {
165
+ // ...req.headers,
166
+ ...extraHeaders,
167
+ Host: targetHost,
168
+ host: targetHost
169
+ }
170
+ };
171
+
172
+ console.log(
173
+ `[workers-proxy] ${req.method} ${targetHost}${targetPath} → ${targetIp}`
174
+ );
175
+
176
+ const proxyReq = https.request(options, (proxyRes) => {
177
+ const isPlaylist =
178
+ isM3u8(proxyRes.headers) ||
179
+ targetPath.includes(".m3u8") ||
180
+ targetPath.includes(".m3u");
181
+
182
+ if (isPlaylist) {
183
+ const chunks: Buffer[] = [];
184
+ proxyRes.on("data", (chunk) => chunks.push(chunk));
185
+ proxyRes.on("end", () => {
186
+ const original = Buffer.concat(chunks).toString("utf8");
187
+ const rewritten = rewriteM3u8Body(original);
188
+
189
+ console.log({ rewritten });
190
+
191
+ const responseHeaders: Record<string, any> = {
192
+ ...proxyRes.headers,
193
+ "content-length": Buffer.byteLength(rewritten).toString(),
194
+ "content-encoding": undefined // decoded already
195
+ };
196
+ // Remove undefined keys
197
+ Object.keys(responseHeaders).forEach(
198
+ (k) =>
199
+ responseHeaders[k] === undefined && delete responseHeaders[k]
200
+ );
201
+
202
+ res.writeHead(proxyRes.statusCode ?? 502, responseHeaders);
203
+ res.end(rewritten);
204
+ });
205
+ } else {
206
+ // Segments — stream straight through, no buffering
207
+ res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
208
+ proxyRes.pipe(res);
209
+ }
210
+ });
211
+
212
+ proxyReq.on("error", (err) => {
213
+ console.error(`[workers-proxy] error for ${targetHost}:`, err.message);
214
+ if (!res.headersSent) {
215
+ res.writeHead(502);
216
+ res.end("Proxy error: " + err.message);
217
+ }
218
+ });
219
+
220
+ req.pipe(proxyReq);
221
+ });
222
+
223
+ proxyServer.listen(PROXY_PORT, "127.0.0.1", () => {
224
+ console.log(
225
+ `[workers-proxy] listening on http://127.0.0.1:${PROXY_PORT}`
226
+ );
227
+ resolve();
228
+ });
229
+
230
+ proxyServer.on("error", reject);
231
+ });
232
+ }
233
+
234
+ export function stopWorkersProxy(): Promise<void> {
235
+ return new Promise((resolve) => {
236
+ if (proxyServer) proxyServer.close(() => resolve());
237
+ else resolve();
238
+ });
239
+ }