Spaces:
Running
Running
File size: 4,101 Bytes
dcc4f27 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | 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();
});
|