Spaces:
Sleeping
Sleeping
| <html lang="fa" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Fallback API Demo</title> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| padding: 20px; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| .card { | |
| background: white; | |
| border-radius: 15px; | |
| padding: 30px; | |
| margin-bottom: 20px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.2); | |
| } | |
| h1 { | |
| color: #667eea; | |
| margin-bottom: 10px; | |
| } | |
| .subtitle { | |
| color: #666; | |
| margin-bottom: 30px; | |
| } | |
| .button-group { | |
| display: flex; | |
| gap: 10px; | |
| flex-wrap: wrap; | |
| margin-bottom: 20px; | |
| } | |
| button { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| border: none; | |
| padding: 12px 24px; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| font-size: 14px; | |
| font-weight: bold; | |
| transition: transform 0.2s; | |
| } | |
| button:hover { | |
| transform: translateY(-2px); | |
| } | |
| button:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
| gap: 15px; | |
| margin-bottom: 20px; | |
| } | |
| .stat-box { | |
| background: #f5f5f5; | |
| padding: 15px; | |
| border-radius: 8px; | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-size: 24px; | |
| font-weight: bold; | |
| color: #667eea; | |
| margin-bottom: 5px; | |
| } | |
| .stat-label { | |
| font-size: 12px; | |
| color: #666; | |
| } | |
| .log-container { | |
| background: #1e1e1e; | |
| color: #00ff00; | |
| padding: 20px; | |
| border-radius: 8px; | |
| font-family: 'Courier New', monospace; | |
| font-size: 13px; | |
| max-height: 400px; | |
| overflow-y: auto; | |
| margin-bottom: 20px; | |
| } | |
| .log-entry { | |
| margin-bottom: 5px; | |
| padding: 5px; | |
| border-left: 3px solid transparent; | |
| } | |
| .log-success { | |
| border-left-color: #00ff00; | |
| color: #00ff00; | |
| } | |
| .log-error { | |
| border-left-color: #ff0000; | |
| color: #ff6b6b; | |
| } | |
| .log-info { | |
| border-left-color: #00bfff; | |
| color: #00bfff; | |
| } | |
| .log-warning { | |
| border-left-color: #ffa500; | |
| color: #ffa500; | |
| } | |
| .endpoints-list { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 10px; | |
| } | |
| .endpoint-item { | |
| background: #f9f9f9; | |
| padding: 15px; | |
| border-radius: 8px; | |
| border-left: 4px solid #667eea; | |
| } | |
| .endpoint-url { | |
| font-family: monospace; | |
| font-size: 12px; | |
| color: #333; | |
| margin-bottom: 10px; | |
| word-break: break-all; | |
| } | |
| .endpoint-stats { | |
| display: flex; | |
| justify-content: space-between; | |
| font-size: 11px; | |
| color: #666; | |
| } | |
| .result-box { | |
| background: #f9f9f9; | |
| padding: 20px; | |
| border-radius: 8px; | |
| margin-top: 20px; | |
| } | |
| .result-box pre { | |
| background: #1e1e1e; | |
| color: #00ff00; | |
| padding: 15px; | |
| border-radius: 5px; | |
| overflow-x: auto; | |
| font-size: 12px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="card"> | |
| <h1>🔄 Fallback API Client Demo</h1> | |
| <p class="subtitle">سیستم fallback سلسله مراتبی با 10 endpoint پشتیبان</p> | |
| <div class="button-group"> | |
| <button onclick="testHealth()">🏥 Test Health</button> | |
| <button onclick="testTopCoins()">💰 Test Top Coins</button> | |
| <button onclick="testTrending()">📈 Test Trending</button> | |
| <button onclick="testSentiment()">😊 Test Sentiment</button> | |
| <button onclick="testNews()">📰 Test News</button> | |
| <button onclick="testResources()">📦 Test Resources</button> | |
| <button onclick="clearLogs()">🗑️ Clear Logs</button> | |
| <button onclick="optimizeEndpoints()">⚡ Optimize</button> | |
| </div> | |
| <div class="stats-grid"> | |
| <div class="stat-box"> | |
| <div class="stat-value" id="totalRequests">0</div> | |
| <div class="stat-label">کل درخواستها</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value" id="successRequests">0</div> | |
| <div class="stat-label">موفق</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value" id="failedRequests">0</div> | |
| <div class="stat-label">ناموفق</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value" id="successRate">0%</div> | |
| <div class="stat-label">نرخ موفقیت</div> | |
| </div> | |
| <div class="stat-box"> | |
| <div class="stat-value" id="cacheSize">0</div> | |
| <div class="stat-label">Cache Size</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2>📊 Endpoints Status</h2> | |
| <div class="endpoints-list" id="endpointsList"></div> | |
| </div> | |
| <div class="card"> | |
| <h2>📝 Logs</h2> | |
| <div class="log-container" id="logContainer"></div> | |
| </div> | |
| <div class="card" id="resultCard" style="display: none;"> | |
| <h2>✅ Result</h2> | |
| <div class="result-box"> | |
| <pre id="resultContent"></pre> | |
| </div> | |
| </div> | |
| </div> | |
| <script src="/static/shared/js/fallback-api-client.js"></script> | |
| <script> | |
| // Initialize API | |
| const api = new CryptoAPI(); | |
| // Logging | |
| function log(message, type = 'info') { | |
| const container = document.getElementById('logContainer'); | |
| const entry = document.createElement('div'); | |
| entry.className = `log-entry log-${type}`; | |
| entry.textContent = `[${new Date().toLocaleTimeString('fa-IR')}] ${message}`; | |
| container.appendChild(entry); | |
| container.scrollTop = container.scrollHeight; | |
| } | |
| function clearLogs() { | |
| document.getElementById('logContainer').innerHTML = ''; | |
| log('Logs cleared', 'info'); | |
| } | |
| // Update stats | |
| function updateStats() { | |
| const stats = api.getStats(); | |
| document.getElementById('totalRequests').textContent = stats.totalRequests; | |
| document.getElementById('successRequests').textContent = stats.successfulRequests; | |
| document.getElementById('failedRequests').textContent = stats.failedRequests; | |
| document.getElementById('successRate').textContent = stats.successRate; | |
| document.getElementById('cacheSize').textContent = stats.cacheSize; | |
| // Update endpoints list | |
| const endpointsList = document.getElementById('endpointsList'); | |
| endpointsList.innerHTML = ''; | |
| api.client.endpoints.forEach((endpoint, index) => { | |
| const endpointStats = stats.endpointStats[endpoint]; | |
| const item = document.createElement('div'); | |
| item.className = 'endpoint-item'; | |
| const successRate = endpointStats.requests > 0 | |
| ? (endpointStats.successes / endpointStats.requests * 100).toFixed(0) | |
| : 0; | |
| item.innerHTML = ` | |
| <div class="endpoint-url">${index + 1}. ${endpoint}</div> | |
| <div class="endpoint-stats"> | |
| <span>✅ ${endpointStats.successes}</span> | |
| <span>❌ ${endpointStats.failures}</span> | |
| <span>📊 ${successRate}%</span> | |
| <span>⚡ ${endpointStats.avgResponseTime.toFixed(0)}ms</span> | |
| </div> | |
| `; | |
| endpointsList.appendChild(item); | |
| }); | |
| } | |
| // Show result | |
| function showResult(data) { | |
| const resultCard = document.getElementById('resultCard'); | |
| const resultContent = document.getElementById('resultContent'); | |
| resultContent.textContent = JSON.stringify(data, null, 2); | |
| resultCard.style.display = 'block'; | |
| } | |
| // Test functions | |
| async function testHealth() { | |
| log('Testing health endpoint...', 'info'); | |
| try { | |
| const result = await api.health(); | |
| log('✅ Health check successful', 'success'); | |
| showResult(result); | |
| } catch (error) { | |
| log(`❌ Health check failed: ${error.message}`, 'error'); | |
| } | |
| updateStats(); | |
| } | |
| async function testTopCoins() { | |
| log('Testing top coins endpoint...', 'info'); | |
| try { | |
| const result = await api.getTopCoins(10); | |
| log('✅ Top coins fetched successfully', 'success'); | |
| showResult(result); | |
| } catch (error) { | |
| log(`❌ Top coins failed: ${error.message}`, 'error'); | |
| } | |
| updateStats(); | |
| } | |
| async function testTrending() { | |
| log('Testing trending endpoint...', 'info'); | |
| try { | |
| const result = await api.getTrending(); | |
| log('✅ Trending data fetched successfully', 'success'); | |
| showResult(result); | |
| } catch (error) { | |
| log(`❌ Trending failed: ${error.message}`, 'error'); | |
| } | |
| updateStats(); | |
| } | |
| async function testSentiment() { | |
| log('Testing sentiment endpoint...', 'info'); | |
| try { | |
| const result = await api.getGlobalSentiment(); | |
| log('✅ Sentiment data fetched successfully', 'success'); | |
| showResult(result); | |
| } catch (error) { | |
| log(`❌ Sentiment failed: ${error.message}`, 'error'); | |
| } | |
| updateStats(); | |
| } | |
| async function testNews() { | |
| log('Testing news endpoint...', 'info'); | |
| try { | |
| const result = await api.getNews(10); | |
| log('✅ News fetched successfully', 'success'); | |
| showResult(result); | |
| } catch (error) { | |
| log(`❌ News failed: ${error.message}`, 'error'); | |
| } | |
| updateStats(); | |
| } | |
| async function testResources() { | |
| log('Testing resources endpoint...', 'info'); | |
| try { | |
| const result = await api.getResources(); | |
| log('✅ Resources fetched successfully', 'success'); | |
| showResult(result); | |
| } catch (error) { | |
| log(`❌ Resources failed: ${error.message}`, 'error'); | |
| } | |
| updateStats(); | |
| } | |
| function optimizeEndpoints() { | |
| log('Optimizing endpoints based on performance...', 'info'); | |
| api.optimizeEndpoints(); | |
| log('✅ Endpoints optimized', 'success'); | |
| updateStats(); | |
| } | |
| // Initial update | |
| updateStats(); | |
| log('Fallback API Client initialized with 10 endpoints', 'success'); | |
| </script> | |
| </body> | |
| </html> | |