somratpro commited on
Commit
f4f91b0
·
1 Parent(s): 16622a0

feat: add Telegram proxy support, improve fetch/undici header handling, and expand dispatcher patching

Browse files
Files changed (2) hide show
  1. cloudflare-proxy.js +30 -17
  2. start.sh +6 -3
cloudflare-proxy.js CHANGED
@@ -149,15 +149,15 @@ if (PROXY_URL) {
149
  const hostname = url.hostname;
150
  const shouldProxy = shouldProxyHost(hostname);
151
 
152
- let headers;
153
  if (request) {
154
- headers = new Headers(request.headers);
155
  } else {
156
- headers = new Headers(init?.headers || {});
157
  }
158
 
159
  const alreadyProxied =
160
- headers.has("x-target-host") || headers.has("X-Target-Host");
161
 
162
  if (!shouldProxy || alreadyProxied) {
163
  return originalFetch(input, init);
@@ -169,9 +169,9 @@ if (PROXY_URL) {
169
  );
170
  }
171
 
172
- headers.set("x-target-host", hostname);
173
  if (PROXY_SHARED_SECRET) {
174
- headers.set("x-proxy-key", PROXY_SHARED_SECRET);
175
  }
176
 
177
  const proxiedUrl = new URL(url.pathname + url.search, proxy);
@@ -179,18 +179,25 @@ if (PROXY_URL) {
179
  if (request) {
180
  const newInit = {
181
  method: request.method,
182
- headers,
183
  body: request.body,
184
  redirect: request.redirect,
185
  duplex: "half",
186
  };
 
 
187
  return originalFetch(new Request(proxiedUrl, newInit));
188
  }
189
 
190
- return originalFetch(proxiedUrl, {
191
  ...init,
192
- headers,
193
- });
 
 
 
 
 
194
  };
195
  }
196
 
@@ -217,24 +224,23 @@ if (PROXY_URL) {
217
  if (hostname && shouldProxyHost(hostname)) {
218
  if (DEBUG) log(`[cloudflare-proxy] Redirecting undici ${name}.dispatch: ${hostname}${options.path || ""} -> ${proxy.hostname}`);
219
 
220
- let headers = options.headers;
221
  const targetHeader = "x-target-host";
222
  const secretHeader = "x-proxy-key";
223
 
224
- if (Array.isArray(headers)) {
225
  let foundTarget = false;
226
- for (let i = 0; i < headers.length; i += 2) {
227
- if (String(headers[i]).toLowerCase() === targetHeader) {
228
  foundTarget = true;
229
  break;
230
  }
231
  }
232
  if (!foundTarget) {
233
- headers.push(targetHeader, hostname);
234
- if (PROXY_SHARED_SECRET) headers.push(secretHeader, PROXY_SHARED_SECRET);
235
  }
236
  } else {
237
- options.headers = headers || {};
238
  if (options.headers instanceof Map || (typeof options.headers.set === 'function')) {
239
  options.headers.set(targetHeader, hostname);
240
  if (PROXY_SHARED_SECRET) options.headers.set(secretHeader, PROXY_SHARED_SECRET);
@@ -266,8 +272,15 @@ if (PROXY_URL) {
266
  } catch (e) {}
267
  }
268
 
 
 
 
 
 
269
  if (exports.fetch && !exports.fetch._patched) {
 
270
  exports.fetch = async function (input, init) {
 
271
  return globalThis.fetch(input, init);
272
  };
273
  exports.fetch._patched = true;
 
149
  const hostname = url.hostname;
150
  const shouldProxy = shouldProxyHost(hostname);
151
 
152
+ let mergedHeaders;
153
  if (request) {
154
+ mergedHeaders = new Headers(request.headers);
155
  } else {
156
+ mergedHeaders = new Headers(init?.headers || {});
157
  }
158
 
159
  const alreadyProxied =
160
+ mergedHeaders.has("x-target-host") || mergedHeaders.has("X-Target-Host");
161
 
162
  if (!shouldProxy || alreadyProxied) {
163
  return originalFetch(input, init);
 
169
  );
170
  }
171
 
172
+ mergedHeaders.set("x-target-host", hostname);
173
  if (PROXY_SHARED_SECRET) {
174
+ mergedHeaders.set("x-proxy-key", PROXY_SHARED_SECRET);
175
  }
176
 
177
  const proxiedUrl = new URL(url.pathname + url.search, proxy);
 
179
  if (request) {
180
  const newInit = {
181
  method: request.method,
182
+ headers: mergedHeaders,
183
  body: request.body,
184
  redirect: request.redirect,
185
  duplex: "half",
186
  };
187
+ // If body is null/undefined, don't set duplex as some Node versions throw
188
+ if (!request.body) delete newInit.duplex;
189
  return originalFetch(new Request(proxiedUrl, newInit));
190
  }
191
 
192
+ const newInit = {
193
  ...init,
194
+ headers: mergedHeaders,
195
+ };
196
+ if (newInit.body && !newInit.duplex) {
197
+ newInit.duplex = "half";
198
+ }
199
+
200
+ return originalFetch(proxiedUrl, newInit);
201
  };
202
  }
203
 
 
224
  if (hostname && shouldProxyHost(hostname)) {
225
  if (DEBUG) log(`[cloudflare-proxy] Redirecting undici ${name}.dispatch: ${hostname}${options.path || ""} -> ${proxy.hostname}`);
226
 
 
227
  const targetHeader = "x-target-host";
228
  const secretHeader = "x-proxy-key";
229
 
230
+ if (Array.isArray(options.headers)) {
231
  let foundTarget = false;
232
+ for (let i = 0; i < options.headers.length; i += 2) {
233
+ if (String(options.headers[i]).toLowerCase() === targetHeader) {
234
  foundTarget = true;
235
  break;
236
  }
237
  }
238
  if (!foundTarget) {
239
+ options.headers.push(targetHeader, hostname);
240
+ if (PROXY_SHARED_SECRET) options.headers.push(secretHeader, PROXY_SHARED_SECRET);
241
  }
242
  } else {
243
+ options.headers = options.headers || {};
244
  if (options.headers instanceof Map || (typeof options.headers.set === 'function')) {
245
  options.headers.set(targetHeader, hostname);
246
  if (PROXY_SHARED_SECRET) options.headers.set(secretHeader, PROXY_SHARED_SECRET);
 
272
  } catch (e) {}
273
  }
274
 
275
+ // Also patch Agent and other potentially unexported classes if they have dispatch
276
+ if (exports.Agent && exports.Agent.prototype) patchDispatch(exports.Agent.prototype, "Agent");
277
+ if (exports.Pool && exports.Pool.prototype) patchDispatch(exports.Pool.prototype, "Pool");
278
+ if (exports.Client && exports.Client.prototype) patchDispatch(exports.Client.prototype, "Client");
279
+
280
  if (exports.fetch && !exports.fetch._patched) {
281
+ const origFetch = exports.fetch;
282
  exports.fetch = async function (input, init) {
283
+ // If we are calling undici.fetch, it should use our globalThis.fetch which is patched
284
  return globalThis.fetch(input, init);
285
  };
286
  exports.fetch._patched = true;
start.sh CHANGED
@@ -354,18 +354,21 @@ fi
354
  # Telegram (supports multiple user IDs, comma-separated)
355
  if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
356
  CONFIG_JSON=$(echo "$CONFIG_JSON" | jq '.plugins.entries.telegram = {"enabled": true}')
357
- export TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN//[[:space:]]/}"
 
 
 
358
  export OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1
359
  export OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first
360
  # Force ipv4 for Telegram specifically as HF IPv6 often times out
361
  export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--dns-result-order=ipv4first"
362
 
363
- CONFIG_JSON=$(echo "$CONFIG_JSON" | jq --arg token "$TELEGRAM_BOT_TOKEN" '
364
  .channels.telegram.enabled = true
365
  | .channels.telegram.botToken = $token
366
  | .channels.telegram.commands.native = false
367
  | .channels.telegram.timeoutSeconds = 60
368
- | .channels.telegram.apiRoot = "https://api.telegram.org"
369
  | .channels.telegram.retry = {
370
  "attempts": 5,
371
  "minDelayMs": 800,
 
354
  # Telegram (supports multiple user IDs, comma-separated)
355
  if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
356
  CONFIG_JSON=$(echo "$CONFIG_JSON" | jq '.plugins.entries.telegram = {"enabled": true}')
357
+ # Trim spaces and ensure it is exported for the plugin
358
+ CLEAN_TG_TOKEN=$(echo "$TELEGRAM_BOT_TOKEN" | tr -d '[:space:]')
359
+ export TELEGRAM_BOT_TOKEN="$CLEAN_TG_TOKEN"
360
+
361
  export OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1
362
  export OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first
363
  # Force ipv4 for Telegram specifically as HF IPv6 often times out
364
  export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--dns-result-order=ipv4first"
365
 
366
+ CONFIG_JSON=$(echo "$CONFIG_JSON" | jq --arg token "$CLEAN_TG_TOKEN" --arg proxy_url "${CLOUDFLARE_PROXY_URL:-}" '
367
  .channels.telegram.enabled = true
368
  | .channels.telegram.botToken = $token
369
  | .channels.telegram.commands.native = false
370
  | .channels.telegram.timeoutSeconds = 60
371
+ | (if $proxy_url != "" then .channels.telegram.apiRoot = $proxy_url else .channels.telegram.apiRoot = "https://api.telegram.org" end)
372
  | .channels.telegram.retry = {
373
  "attempts": 5,
374
  "minDelayMs": 800,