export default { async fetch(request, env, ctx) { const url = new URL(request.url); const method = request.method; const SECRET_KEY = env.SECRET_KEY; const BOT_TOKEN = env.TELEGRAM_BOT_TOKEN; // Helper: Telegram Messaging async function sendTelegram(chatId, text, replyMarkup = null) { const payload = { chat_id: chatId, text: text, parse_mode: "Markdown" }; if (replyMarkup) payload.reply_markup = replyMarkup; await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); } // Helper: Save Signal to KV & Log History async function dispatchSignal(action, symbol, volume, source = "Telegram") { // Check Kill-Switch State const isPaused = await env.SIGNAL_STORE.get("bridge_paused"); if (isPaused === "true") return { success: false, reason: "Bridge is PAUSED" }; const tradePayload = { action, symbol, volume: parseFloat(volume) || 0.01, timestamp: new Date().toISOString(), source }; // Set pending trade for MT5 await env.SIGNAL_STORE.put("pending_trade", JSON.stringify(tradePayload), { expirationTtl: 60 }); // Add to History (Keep last 10) let history = await env.SIGNAL_STORE.get("history", { type: "json" }) || []; history.unshift(tradePayload); if (history.length > 10) history.pop(); await env.SIGNAL_STORE.put("history", JSON.stringify(history)); return { success: true, payload: tradePayload }; } // ------------------------------------------------------------- // 1. WEB APP DASHBOARD (GET / or GET /dashboard) // ------------------------------------------------------------- if (method === "GET" && (url.pathname === "/" || url.pathname === "/dashboard")) { const isPaused = (await env.SIGNAL_STORE.get("bridge_paused")) === "true"; const history = (await env.SIGNAL_STORE.get("history", { type: "json" })) || []; const html = ` Goated Bridge | Command Center

⚡ Goated Bridge Control Panel

Cloudflare Execution Engine & MT5 Gateway

${isPaused ? 'BRIDGE PAUSED' : 'SYSTEM LIVE'}

Manual Signal Dispatcher

Recent Signal Logs

${history.length === 0 ? '' : ''} ${history.map(item => ` `).join('')}
Time Source Action Symbol Volume
No signals logged yet.
${new Date(item.timestamp).toLocaleTimeString()} ${item.source} ${item.action} ${item.symbol} ${item.volume}
`; return new Response(html, { headers: { "Content-Type": "text/html" } }); } // ------------------------------------------------------------- // 2. WEB APP API ENDPOINTS // ------------------------------------------------------------- if (method === "POST" && url.pathname === "/api/toggle-pause") { const current = await env.SIGNAL_STORE.get("bridge_paused"); const newState = current === "true" ? "false" : "true"; await env.SIGNAL_STORE.put("bridge_paused", newState); return new Response(JSON.stringify({ paused: newState === "true" }), { status: 200 }); } if (method === "POST" && url.pathname === "/api/manual-signal") { const { action, symbol, volume } = await request.json(); const res = await dispatchSignal(action, symbol, volume, "Web App"); return res.success ? new Response("OK", { status: 200 }) : new Response(res.reason, { status: 400 }); } // ------------------------------------------------------------- // 3. TELEGRAM WEBHOOK ENDPOINT // ------------------------------------------------------------- if (method === "POST" && url.pathname === "/telegram-webhook") { try { const update = await request.json(); if (update.message && update.message.text === "/start") { const chatId = update.message.chat.id; const keyboard = { inline_keyboard: [ [ { text: "🟢 BUY XAUUSD (0.1)", callback_data: "BUY_XAUUSD_0.1" }, { text: "🔴 SELL XAUUSD (0.1)", callback_data: "SELL_XAUUSD_0.1" } ], [ { text: "⚠️ CLOSE ALL XAUUSD", callback_data: "CLOSE_XAUUSD_ALL" } ] ] }; await sendTelegram(chatId, "⚡ **Goated Analyst Command Center**\nSelect an instant action:", keyboard); return new Response("OK", { status: 200 }); } if (update.callback_query) { const query = update.callback_query; const chatId = query.message.chat.id; const parts = query.data.split('_'); const action = parts[0]; const symbol = parts[1]; const volume = parts[2] ? (parts[2] === "ALL" ? 0.0 : parseFloat(parts[2])) : 0.0; const result = await dispatchSignal(action, symbol, volume, "Telegram"); if (result.success) { await sendTelegram(chatId, `✅ **Signal Executed via Bridge!**\nAction: ${action}\nSymbol: ${symbol}\nVolume: ${parts[2] || "ALL"}`); } else { await sendTelegram(chatId, `❌ **Execution Blocked:** ${result.reason}`); } return new Response("OK", { status: 200 }); } return new Response("OK", { status: 200 }); } catch (err) { return new Response("Error", { status: 500 }); } } // ------------------------------------------------------------- // 4. MT5 POLLING ENDPOINT // ------------------------------------------------------------- if (method === "GET" && url.pathname === "/signal") { const mt5Secret = request.headers.get("X-Bridge-Secret") || url.searchParams.get("secret"); if (mt5Secret !== SECRET_KEY) { return new Response("Unauthorized", { status: 401 }); } const pendingTrade = await env.SIGNAL_STORE.get("pending_trade"); if (pendingTrade) { await env.SIGNAL_STORE.delete("pending_trade"); return new Response(pendingTrade, { status: 200, headers: { "Content-Type": "application/json" } }); } return new Response(JSON.stringify({ action: "NONE" }), { status: 200, headers: { "Content-Type": "application/json" } }); } return new Response("Not Found", { status: 404 }); } };