mirror of
https://github.com/koala73/worldmonitor.git
synced 2026-04-25 17:14:57 +02:00
Reduce Vercel execution costs and Upstash Redis read counts by letting the CDN absorb more traffic. Addresses the "double dip" where bootstrap.js hit Redis for 15 keys on every 60s cache miss, and telegram-feed/geo had no s-maxage at all (every request hit Vercel). - bootstrap: s-maxage 60→600, add stale-if-error=900 - ais-snapshot: s-maxage 180→300, stale-while-revalidate 300→600 - oref-alerts: s-maxage 5→180, add stale-if-error=600 - telegram-feed: add s-maxage=600, stale-if-error=900 (had none) - geo: add s-maxage=3600, stale-if-error=3600 (had none) - gpsjam: add stale-if-error=3600 - opensky: add stale-if-error=300 - version: add stale-if-error=3600 - download: add stale-if-error=600
86 lines
3.1 KiB
JavaScript
86 lines
3.1 KiB
JavaScript
// Telegram feed proxy (web)
|
|
// Fetches Telegram Early Signals from the Railway relay (stateful MTProto lives there).
|
|
|
|
import { getCorsHeaders, isDisallowedOrigin } from './_cors.js';
|
|
|
|
export const config = { runtime: 'edge' };
|
|
|
|
async function fetchWithTimeout(url, options, timeoutMs = 25000) {
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
try {
|
|
return await fetch(url, { ...options, signal: controller.signal });
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|
|
|
|
export default async function handler(req) {
|
|
const cors = getCorsHeaders(req, 'GET, OPTIONS');
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
return new Response(null, { status: 204, headers: cors });
|
|
}
|
|
|
|
if (isDisallowedOrigin(req)) {
|
|
return new Response(JSON.stringify({ error: 'Origin not allowed' }), { status: 403, headers: cors });
|
|
}
|
|
|
|
let relay = process.env.WS_RELAY_URL;
|
|
if (!relay) {
|
|
return new Response(JSON.stringify({ error: 'WS_RELAY_URL not configured' }), {
|
|
status: 503,
|
|
headers: { 'Content-Type': 'application/json', ...cors },
|
|
});
|
|
}
|
|
|
|
// Guard: WS_RELAY_URL should be HTTP(S) for server-side fetches.
|
|
// If someone accidentally sets a ws:// or wss:// URL, normalize it.
|
|
if (relay.startsWith('wss://')) relay = relay.replace('wss://', 'https://');
|
|
if (relay.startsWith('ws://')) relay = relay.replace('ws://', 'http://');
|
|
|
|
const url = new URL(req.url);
|
|
const limit = Math.max(1, Math.min(200, parseInt(url.searchParams.get('limit') || '50', 10) || 50));
|
|
const topic = (url.searchParams.get('topic') || '').trim();
|
|
const channel = (url.searchParams.get('channel') || '').trim();
|
|
|
|
const relayUrl = new URL('/telegram/feed', relay);
|
|
relayUrl.searchParams.set('limit', String(limit));
|
|
if (topic) relayUrl.searchParams.set('topic', topic);
|
|
if (channel) relayUrl.searchParams.set('channel', channel);
|
|
|
|
const fetchHeaders = { 'Accept': 'application/json' };
|
|
const relaySecret = process.env.RELAY_SHARED_SECRET || '';
|
|
if (relaySecret) {
|
|
const relayHeader = (process.env.RELAY_AUTH_HEADER || 'x-relay-key').toLowerCase();
|
|
fetchHeaders[relayHeader] = relaySecret;
|
|
fetchHeaders.Authorization = `Bearer ${relaySecret}`;
|
|
}
|
|
|
|
try {
|
|
const res = await fetchWithTimeout(relayUrl.toString(), {
|
|
headers: fetchHeaders,
|
|
}, 25000);
|
|
|
|
const text = await res.text();
|
|
return new Response(text, {
|
|
status: res.status,
|
|
headers: {
|
|
'Content-Type': res.headers.get('content-type') || 'application/json',
|
|
// Short cache. Telegram is near-real-time.
|
|
'Cache-Control': 'public, max-age=60, s-maxage=600, stale-while-revalidate=120, stale-if-error=900',
|
|
...cors,
|
|
},
|
|
});
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : String(err);
|
|
const isAbort = err && (err.name === 'AbortError' || /aborted/i.test(msg));
|
|
return new Response(JSON.stringify({
|
|
error: isAbort ? 'Telegram relay request timed out' : 'Telegram relay fetch failed',
|
|
}), {
|
|
status: isAbort ? 504 : 502,
|
|
headers: { 'Content-Type': 'application/json', ...cors },
|
|
});
|
|
}
|
|
}
|