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();
});