Really-amin commited on
Commit
68aff21
·
verified ·
1 Parent(s): 69bc051

Upload 40 files

Browse files
Files changed (3) hide show
  1. admin.html +39 -6
  2. static/js/apiClient.js +9 -19
  3. static/js/wsClient.js +29 -30
admin.html CHANGED
@@ -9,14 +9,25 @@
9
  <link rel="stylesheet" href="static/css/dashboard.css" />
10
  <link rel="stylesheet" href="static/css/pro-dashboard.css" />
11
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js" defer></script>
 
 
 
 
 
 
 
 
 
 
 
12
  </head>
13
  <body data-theme="dark">
14
  <!-- ===== تنظیم بک‌اند (اسکریپت) ===== -->
15
  <script>
16
  // اگر بک‌اندت روی Space دیگه‌ای هست اینجا عوض کن
17
  // مثال: window.BACKEND_URL = 'https://aminmckee-crypto-intelligence.hf.space';
18
- // اگر بک‌اند و داشبورد در یک Space هستن → این خط رو حذف یا کامنت کن
19
- window.BACKEND_URL = 'https://aminmckee-crypto-intelligence.hf.space';
20
  </script>
21
 
22
  <div class="app-shell">
@@ -93,11 +104,33 @@
93
  <p class="text-muted">Live market data, AI-powered sentiment analysis, and comprehensive crypto intelligence</p>
94
  </div>
95
  <div class="status-group">
 
96
  <div class="status-pill" data-api-health data-state="warn">
97
- <span class="status-dot"></span><span>checking</span>
98
- </div>
 
 
 
 
 
 
 
 
 
99
  <div class="status-pill" data-ws-status data-state="warn">
100
- <span class="status-dot"></span><span>connecting</span>
 
 
 
 
 
 
 
 
 
 
 
 
101
  </div>
102
  </div>
103
  </header>
@@ -521,4 +554,4 @@
521
  <!-- Load App JS as ES6 Module -->
522
  <script type="module" src="static/js/app.js"></script>
523
  </body>
524
- </html>
 
9
  <link rel="stylesheet" href="static/css/dashboard.css" />
10
  <link rel="stylesheet" href="static/css/pro-dashboard.css" />
11
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js" defer></script>
12
+
13
+ <!-- SVG status icon tweaks -->
14
+ <style>
15
+ .status-pill .status-icon {
16
+ margin-inline: 0.35rem;
17
+ flex-shrink: 0;
18
+ }
19
+ .status-pill .status-label {
20
+ white-space: nowrap;
21
+ }
22
+ </style>
23
  </head>
24
  <body data-theme="dark">
25
  <!-- ===== تنظیم بک‌اند (اسکریپت) ===== -->
26
  <script>
27
  // اگر بک‌اندت روی Space دیگه‌ای هست اینجا عوض کن
28
  // مثال: window.BACKEND_URL = 'https://aminmckee-crypto-intelligence.hf.space';
29
+ // الان تنظیم شده روی Space فعلی داده‌ها:
30
+ window.BACKEND_URL = 'https://really-amin-datasourceforcryptocurrency.hf.space';
31
  </script>
32
 
33
  <div class="app-shell">
 
104
  <p class="text-muted">Live market data, AI-powered sentiment analysis, and comprehensive crypto intelligence</p>
105
  </div>
106
  <div class="status-group">
107
+ <!-- API Health with SVG icon -->
108
  <div class="status-pill" data-api-health data-state="warn">
109
+ <span class="status-dot"></span>
110
+ <svg class="status-icon" width="14" height="14" viewBox="0 0 24 24" aria-hidden="true">
111
+ <path d="M4 7h16M4 12h10M4 17h7"
112
+ stroke="currentColor"
113
+ stroke-width="2"
114
+ stroke-linecap="round"
115
+ stroke-linejoin="round" />
116
+ </svg>
117
+ <span class="status-label">checking</span>
118
+ </div>
119
+ <!-- WebSocket Status with SVG icon -->
120
  <div class="status-pill" data-ws-status data-state="warn">
121
+ <span class="status-dot"></span>
122
+ <svg class="status-icon" width="14" height="14" viewBox="0 0 24 24" aria-hidden="true">
123
+ <path d="M4 5h16v6H4z"
124
+ stroke="currentColor"
125
+ stroke-width="2"
126
+ fill="none"
127
+ stroke-linejoin="round" />
128
+ <path d="M8 15h8M10 19h4"
129
+ stroke="currentColor"
130
+ stroke-width="2"
131
+ stroke-linecap="round" />
132
+ </svg>
133
+ <span class="status-label">connecting</span>
134
  </div>
135
  </div>
136
  </header>
 
554
  <!-- Load App JS as ES6 Module -->
555
  <script type="module" src="static/js/app.js"></script>
556
  </body>
557
+ </html>
static/js/apiClient.js CHANGED
@@ -2,26 +2,15 @@ const DEFAULT_TTL = 60 * 1000; // 1 minute cache
2
 
3
  class ApiClient {
4
  constructor() {
5
- // ==== اصلاح هوشمندانه آدرس بک‌اند ====
6
- // ۱. اگر دستی BACKEND_URL تعریف شده باشه (از HTML)
7
- // ۲. اگر روی HF Space هستیم و بک‌اند هم همونه → خودکار
8
- // ۳. در غیر این صورت بک‌اند معروف و همیشه زنده
9
- this.baseURL =
10
- (typeof window.BACKEND_URL === 'string' && window.BACKEND_URL.trim() !== ''
11
- ? window.BACKEND_URL.trim().replace(/\/$/, '')
12
- : null) ||
13
- (window.location.origin.includes('hf.space')
14
- ? window.location.origin.replace(/\/$/, '')
15
- : null) ||
16
- 'https://aminmckee-crypto-intelligence.hf.space';
17
-
18
- // تضمین نهایی: اگر به هر دلیلی خالی بود
19
- if (!this.baseURL || this.baseURL === 'null' || this.baseURL === '') {
20
- this.baseURL = 'https://aminmckee-crypto-intelligence.hf.space';
21
  }
22
 
23
- console.log('[ApiClient] Backend URL:', this.baseURL);
24
- // ==== پایان اصلاح ====
25
 
26
  this.cache = new Map();
27
  this.requestLogs = [];
@@ -79,7 +68,8 @@ class ApiClient {
79
  }
80
 
81
  const started = performance.now();
82
- const randomId = (window.crypto && window.crypto.randomUUID && window.crypto.randomUUID()) || `${Date.now()}-${Math.random()}`;
 
83
  const entry = {
84
  id: randomId,
85
  method,
 
2
 
3
  class ApiClient {
4
  constructor() {
5
+ // ==== آدرس صحیح بک‌اند شما (Really-amin) ====
6
+ this.baseURL = 'https://really-amin-datasourceforcryptocurrency.hf.space';
7
+
8
+ // اگر بعداً بخوای دستی عوض کنی، از HTML استفاده کن
9
+ if (typeof window.BACKEND_URL === 'string' && window.BACKEND_URL.trim()) {
10
+ this.baseURL = window.BACKEND_URL.trim().replace(/\/$/, '');
 
 
 
 
 
 
 
 
 
 
11
  }
12
 
13
+ console.log('[ApiClient] Using Backend:', this.baseURL);
 
14
 
15
  this.cache = new Map();
16
  this.requestLogs = [];
 
68
  }
69
 
70
  const started = performance.now();
71
+ const randomId = (window.crypto && window.crypto.randomUUID && window.crypto.randomUUID())
72
+ || `${Date.now()}-${Math.random()}`;
73
  const entry = {
74
  id: randomId,
75
  method,
static/js/wsClient.js CHANGED
@@ -11,11 +11,12 @@ class WSClient {
11
  this.shouldReconnect = true;
12
  }
13
 
 
14
  get url() {
15
- const { protocol, host } = window.location;
16
- const wsProtocol = protocol === 'https:' ? 'wss:' : 'ws:';
17
- return `${wsProtocol}//${host}/ws`;
18
  }
 
 
19
 
20
  logEvent(event) {
21
  const entry = { ...event, time: new Date().toISOString() };
@@ -35,21 +36,21 @@ class WSClient {
35
  }
36
 
37
  subscribe(type, callback) {
38
- if (!this.typeSubscribers.has(type)) {
39
- this.typeSubscribers.set(type, new Set());
40
- }
41
  const set = this.typeSubscribers.get(type);
42
  set.add(callback);
43
  return () => set.delete(callback);
44
  }
45
 
46
  updateStatus(newStatus) {
47
- this.status = newStatus;
48
- this.statusSubscribers.forEach((cb) => cb(newStatus));
 
 
49
  }
50
 
51
  connect() {
52
- if (this.socket && (this.status === 'connecting' || this.status === 'connected')) {
53
  return;
54
  }
55
 
@@ -57,26 +58,27 @@ class WSClient {
57
  this.socket = new WebSocket(this.url);
58
  this.logEvent({ type: 'status', status: 'connecting' });
59
 
60
- this.socket.addEventListener('open', () => {
61
  this.backoff = 1000;
62
  this.updateStatus('connected');
63
  this.logEvent({ type: 'status', status: 'connected' });
64
- });
 
65
 
66
- this.socket.addEventListener('message', (event) => {
67
  try {
68
  const data = JSON.parse(event.data);
69
  this.logEvent({ type: 'message', messageType: data.type || 'unknown' });
70
- this.globalSubscribers.forEach((cb) => cb(data));
71
  if (data.type && this.typeSubscribers.has(data.type)) {
72
- this.typeSubscribers.get(data.type).forEach((cb) => cb(data));
73
  }
74
- } catch (error) {
75
- console.error('WS message parse error', error);
76
  }
77
- });
78
 
79
- this.socket.addEventListener('close', () => {
80
  this.updateStatus('disconnected');
81
  this.logEvent({ type: 'status', status: 'disconnected' });
82
  if (this.shouldReconnect) {
@@ -84,22 +86,17 @@ class WSClient {
84
  this.backoff = Math.min(this.backoff * 2, this.maxBackoff);
85
  setTimeout(() => this.connect(), delay);
86
  }
87
- });
88
 
89
- this.socket.addEventListener('error', (error) => {
90
- console.error('WebSocket error', error);
91
- this.logEvent({ type: 'error', details: error.message || 'unknown' });
92
- if (this.socket) {
93
- this.socket.close();
94
- }
95
- });
96
  }
97
 
98
  disconnect() {
99
  this.shouldReconnect = false;
100
- if (this.socket) {
101
- this.socket.close();
102
- }
103
  }
104
 
105
  getEvents() {
@@ -108,4 +105,6 @@ class WSClient {
108
  }
109
 
110
  const wsClient = new WSClient();
111
- export default wsClient;
 
 
 
11
  this.shouldReconnect = true;
12
  }
13
 
14
+ // ==== اصلاح اصلی: همیشه به Space شما وصل بشه ====
15
  get url() {
16
+ return 'wss://really-amin-datasourceforcryptocurrency.hf.space/ws';
 
 
17
  }
18
+ // اگر بعداً بخوای از HTML کنترل کنی:
19
+ // return window.WS_URL || 'wss://really-amin-datasourceforcryptocurrency.hf.space/ws';
20
 
21
  logEvent(event) {
22
  const entry = { ...event, time: new Date().toISOString() };
 
36
  }
37
 
38
  subscribe(type, callback) {
39
+ if (!this.typeSubscribers.has(type)) this.typeSubscribers.set(type, new Set());
 
 
40
  const set = this.typeSubscribers.get(type);
41
  set.add(callback);
42
  return () => set.delete(callback);
43
  }
44
 
45
  updateStatus(newStatus) {
46
+ if (this.status !== newStatus) {
47
+ this.status = newStatus;
48
+ this.statusSubscribers.forEach(cb => cb(newStatus));
49
+ }
50
  }
51
 
52
  connect() {
53
+ if (this.socket && (this.socket.readyState === WebSocket.CONNECTING || this.socket.readyState === WebSocket.OPEN)) {
54
  return;
55
  }
56
 
 
58
  this.socket = new WebSocket(this.url);
59
  this.logEvent({ type: 'status', status: 'connecting' });
60
 
61
+ this.socket.onopen = () => {
62
  this.backoff = 1000;
63
  this.updateStatus('connected');
64
  this.logEvent({ type: 'status', status: 'connected' });
65
+ console.log('[WS] Connected to Really-amin Space');
66
+ };
67
 
68
+ this.socket.onmessage = (event) => {
69
  try {
70
  const data = JSON.parse(event.data);
71
  this.logEvent({ type: 'message', messageType: data.type || 'unknown' });
72
+ this.globalSubscribers.forEach(cb => cb(data));
73
  if (data.type && this.typeSubscribers.has(data.type)) {
74
+ this.typeSubscribers.get(data.type).forEach(cb => cb(data));
75
  }
76
+ } catch (e) {
77
+ console.error('WS parse error:', e);
78
  }
79
+ };
80
 
81
+ this.socket.onclose = () => {
82
  this.updateStatus('disconnected');
83
  this.logEvent({ type: 'status', status: 'disconnected' });
84
  if (this.shouldReconnect) {
 
86
  this.backoff = Math.min(this.backoff * 2, this.maxBackoff);
87
  setTimeout(() => this.connect(), delay);
88
  }
89
+ };
90
 
91
+ this.socket.onerror = (error) => {
92
+ console.error('WebSocket error:', error);
93
+ this.logEvent({ type: 'error', details: 'connection failed' });
94
+ };
 
 
 
95
  }
96
 
97
  disconnect() {
98
  this.shouldReconnect = false;
99
+ if (this.socket) this.socket.close();
 
 
100
  }
101
 
102
  getEvents() {
 
105
  }
106
 
107
  const wsClient = new WSClient();
108
+ wsClient.connect(); // خودکار وصل بشه
109
+
110
+ export default wsClient;