Spaces:
Running
Running
| require('dotenv').config(); | |
| const express = require('express'); | |
| const axios = require('axios'); | |
| const cors = require('cors'); | |
| const { connect: connectDB } = require('./db'); | |
| const { authMiddleware } = require('./auth'); | |
| const { initTelegramBot } = require('./telegramBot'); | |
| // Connect to database to validate keys | |
| connectDB(); | |
| const app = express(); | |
| app.use(cors()); | |
| app.use(express.json()); | |
| // Configuration (Set these env variables on Render/Vercel) | |
| const PORT = process.env.PORT || 8080; | |
| const HUGGINGFACE_API_URL = process.env.HUGGINGFACE_API_URL || 'https://yogeshjio5770-goldscrape-api.hf.space'; | |
| // Use a single API_KEY for both validation and HF authorization | |
| const API_KEY = process.env.API_KEY || 'aurum_live_key_2026_xK9mP3vL7qR2'; | |
| if (!process.env.API_KEY) { | |
| process.env.API_KEY = API_KEY; | |
| } | |
| const CACHE_TTL_MS = (parseInt(process.env.PROXY_CACHE_SECONDS) || 5) * 1000; // default 5 seconds cache | |
| // Partitioned memory caches based on rate source | |
| const proxyCaches = { | |
| SLN: { data: null, timestamp: 0, promise: null }, | |
| IBJA: { data: null, timestamp: 0, promise: null }, | |
| BOTH: { data: null, timestamp: 0, promise: null } | |
| }; | |
| // Route: Get cached live rates (requires valid API key from Supabase) | |
| app.get('/api/rates', authMiddleware, async (req, res) => { | |
| const source = req.priceSource || 'SLN'; | |
| const cacheKey = (req.isMasterKey || source === 'BOTH') ? 'BOTH' : source; | |
| const cache = proxyCaches[cacheKey] || proxyCaches.SLN; | |
| const now = Date.now(); | |
| // If cache is fresh, serve it immediately | |
| if (cache.data && (now - cache.timestamp) < CACHE_TTL_MS) { | |
| return res.json({ | |
| ...cache.data, | |
| from_proxy_cache: true, | |
| proxy_cache_age_seconds: Math.round((now - cache.timestamp) / 1000) | |
| }); | |
| } | |
| // If already fetching from Hugging Face, reuse the active promise to avoid duplicate calls | |
| if (cache.promise) { | |
| try { | |
| const data = await cache.promise; | |
| return res.json({ | |
| ...data, | |
| from_proxy_cache: true, | |
| proxy_cache_age_seconds: Math.round((Date.now() - cache.timestamp) / 1000) | |
| }); | |
| } catch (err) { | |
| // Fallback below if promise fails | |
| } | |
| } | |
| // Fetch fresh data from Hugging Face Space passing original client api key | |
| const clientApiKey = req.headers['x-api-key'] || req.query.apikey || API_KEY; | |
| cache.promise = (async () => { | |
| const response = await axios.get(`${HUGGINGFACE_API_URL}/api/rates`, { | |
| headers: { | |
| 'x-api-key': clientApiKey | |
| }, | |
| timeout: 8000 | |
| }); | |
| // Update cache | |
| cache.data = response.data; | |
| cache.timestamp = Date.now(); | |
| cache.promise = null; | |
| return response.data; | |
| })(); | |
| try { | |
| const data = await cache.promise; | |
| res.json({ | |
| ...data, | |
| from_proxy_cache: false | |
| }); | |
| } catch (error) { | |
| cache.promise = null; | |
| // If Hugging Face is slow/down, serve stale cache as fallback | |
| if (cache.data) { | |
| console.warn('⚠️ Hugging Face API call failed. Serving stale proxy cache.'); | |
| return res.json({ | |
| ...cache.data, | |
| from_proxy_cache: true, | |
| proxy_stale_fallback: true | |
| }); | |
| } | |
| res.status(502).json({ | |
| success: false, | |
| error: 'Failed to fetch rates from Hugging Face Space backend', | |
| details: error.message | |
| }); | |
| } | |
| }); | |
| // Health check endpoint | |
| app.get('/health', (req, res) => { | |
| res.json({ | |
| status: 'UP', | |
| caches: { | |
| sln: proxyCaches.SLN.data ? 'ACTIVE' : 'EMPTY', | |
| ibja: proxyCaches.IBJA.data ? 'ACTIVE' : 'EMPTY', | |
| both: proxyCaches.BOTH.data ? 'ACTIVE' : 'EMPTY' | |
| } | |
| }); | |
| }); | |
| // Root endpoint for browser visits | |
| app.get('/', (req, res) => { | |
| res.send('<h1>GoldScrape API Cache Proxy</h1><p>Status: Running</p><p>Use <code>/api/rates?apikey=YOUR_KEY</code> to fetch prices.</p>'); | |
| }); | |
| app.listen(PORT, () => { | |
| console.log(`🚀 Cache Proxy Server running on port ${PORT}`); | |
| console.log(`🔗 Target Hugging Face URL: ${HUGGINGFACE_API_URL}`); | |
| console.log(`⏱️ Proxy Cache TTL: ${CACHE_TTL_MS / 1000} seconds`); | |
| // Start Telegram bot on Render proxy | |
| initTelegramBot(); | |
| }); | |