register session -> send heartbeat

This commit is contained in:
thuanle
2025-08-04 15:34:01 +07:00
parent 2d175e571f
commit 48c7c25674

View File

@@ -28,6 +28,18 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
(async () => { (async () => {
'use strict'; 'use strict';
const uuid = () => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16));
const KEYS = {
SESSION_ID: 'aRah9OhHeijee6sho3baequu9phoovah',
SESSION_TOKEN: 'ThiegiecohViuZ1Iecio7gahphiechub',
AGENT_TOKEN: 'baf-agent-token',
}
if (!sessionStorage.getItem(KEYS.SESSION_ID)) {
sessionStorage.setItem(KEYS.SESSION_ID, uuid());
}
// ====== CONFIGURATION ====== // ====== CONFIGURATION ======
const CONFIG = { const CONFIG = {
HEARTBEAT_INTERVAL: 10000, HEARTBEAT_INTERVAL: 10000,
@@ -35,10 +47,17 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
SERVERS: { SERVERS: {
local: { label: '🏠 Local', url: 'http://localhost:3000' }, local: { label: '🏠 Local', url: 'http://localhost:3000' },
prod: { label: '🌐 Prod', url: 'https://baf.thuanle.me' }, prod: { label: '🌐 Prod', url: 'https://baf.thuanle.me' },
} },
}; };
const AppSession = {
SESSION_ID: sessionStorage.getItem(KEYS.SESSION_ID),
getSessionToken: () => sessionStorage.getItem(KEYS.SESSION_TOKEN),
setSessionToken: token => sessionStorage.setItem(KEYS.SESSION_TOKEN, token),
}
// ====== APP ENUMS ====== // ====== APP ENUMS ======
const AppEnums = { const AppEnums = {
BOT_STATUS: { BOT_STATUS: {
@@ -57,6 +76,7 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
this.data = { this.data = {
// Server configuration - Thông tin server hiện tại // Server configuration - Thông tin server hiện tại
server_last_seen: null, // Thời gian cuối cùng ping server thành công server_last_seen: null, // Thời gian cuối cùng ping server thành công
server_latency: null, // Thời gian ping server (ms)
// Page state - Trạng thái trang hiện tại // Page state - Trạng thái trang hiện tại
current_page: null, // Trang hiện tại (detected từ URL) current_page: null, // Trang hiện tại (detected từ URL)
@@ -95,8 +115,6 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
TL.log('APP-STATE', 'AppState initialized'); TL.log('APP-STATE', 'AppState initialized');
} }
/** /**
* Lấy copy của data hiện tại * Lấy copy của data hiện tại
* @returns {Object} Copy của state data * @returns {Object} Copy của state data
@@ -108,6 +126,8 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
// ====== GETTER METHODS ====== // ====== GETTER METHODS ======
getServer() { return CONFIG.SERVERS[AppSettings.getServerType()]; } getServer() { return CONFIG.SERVERS[AppSettings.getServerType()]; }
getServerLastSeen() { return this.data.server_last_seen; } getServerLastSeen() { return this.data.server_last_seen; }
getServerLatency() { return this.data.server_latency; }
/** /**
* Kiểm tra xem server có kết nối không * Kiểm tra xem server có kết nối không
* @returns {boolean} true nếu server kết nối trong 1 phút, false nếu không * @returns {boolean} true nếu server kết nối trong 1 phút, false nếu không
@@ -193,7 +213,7 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
* Lưu trữ cài đặt người dùng trong GM storage (vĩnh viễn) * Lưu trữ cài đặt người dùng trong GM storage (vĩnh viễn)
*/ */
const AppSettings = { const AppSettings = {
key_token: 'baf-agent-token', key_agent_token: 'baf-agent-token',
key_server_type: 'baf-server-type', key_server_type: 'baf-server-type',
key_bot_status: 'baf-bot-status', key_bot_status: 'baf-bot-status',
key_popup_position: 'baf-popup-position', key_popup_position: 'baf-popup-position',
@@ -201,9 +221,8 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
key_debug: 'baf-debug', key_debug: 'baf-debug',
key_safety_guard: 'baf-safety-guard', key_safety_guard: 'baf-safety-guard',
// Token management getAgentToken: () => GM_getValue(AppSettings.key_agent_token, ''),
getToken: () => GM_getValue(AppSettings.key_token, ''), setAgentToken: token => GM_setValue(AppSettings.key_agent_token, String(token || '').trim().replace(/^Bearer\s+/i, '')),
setToken: token => GM_setValue(AppSettings.key_token, String(token || '').trim().replace(/^Bearer\s+/i, '')),
// Server configuration // Server configuration
getServerType: () => GM_getValue(AppSettings.key_server_type, 'prod'), getServerType: () => GM_getValue(AppSettings.key_server_type, 'prod'),
@@ -351,15 +370,14 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
// ====== BAF API MODULE ====== // ====== BAF API MODULE ======
const BAF = { const BAF = {
getHost: () => AppState.getServer()?.url, _getHost: () => AppState.getServer()?.url,
request: async (method, path, { params, body, headers } = {}) => { _request: async (method, path, { params, body, headers, token } = {}) => {
const base = BAF.getHost(); const base = BAF._getHost();
const url = new URL(path, base); const url = new URL(path, base);
if (params) for (const [k, v] of Object.entries(params)) url.searchParams.append(k, v); if (params) for (const [k, v] of Object.entries(params)) url.searchParams.append(k, v);
const h = new Headers(headers || {}); const h = new Headers(headers || {});
const token = await AppSettings.getToken();
if (token && !h.has('Authorization')) h.set('Authorization', `Bearer ${token}`); if (token && !h.has('Authorization')) h.set('Authorization', `Bearer ${token}`);
const init = { method, headers: h }; const init = { method, headers: h };
@@ -372,15 +390,20 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
return TL.net.gmRequest(url.toString(), init); return TL.net.gmRequest(url.toString(), init);
}, },
get: (path, params, init = {}) => BAF.request('GET', path, { params, headers: init.headers }), _agentGet: (path, params, init = {}) => BAF._request('GET', path, { params, headers: init.headers, token: AppSettings.getAgentToken() }),
post: (path, body, init = {}) => BAF.request('POST', path, { body, headers: init.headers }), _agentPost: (path, body, init = {}) => BAF._request('POST', path, { body, headers: init.headers, token: AppSettings.getAgentToken() }),
ping: (status) => BAF.post('/agent/ping', status), _sessionGet: (path, params, init = {}) => BAF._request('GET', path, { params, headers: init.headers, token: AppSession.getSessionToken() }),
_sessionPost: (path, body, init = {}) => BAF._request('POST', path, { body, headers: init.headers, token: AppSession.getSessionToken() }),
register: (data) => BAF._agentPost('/agent/register', data),
ping: (data) => BAF._sessionPost('/session/ping', data),
getTask: (data) => BAF._sessionPost('/session/task', data),
}; };
// ====== BINANCE MODULE ====== // ====== BINANCE MODULE ======
// Binance Pages constants // Binance Pages constants
const BINANCE_PAGES = { const BINANCE_PAGES = {
LOGIN: 'login', LOGIN: 'login',
@@ -531,7 +554,7 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
} }
} }
}; };
// ====== APP UI ====== // ====== APP UI ======
const AppUi = { const AppUi = {
// ====== DASHBOARD OVERLAY ====== // ====== DASHBOARD OVERLAY ======
@@ -638,7 +661,7 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
// Get server info // Get server info
const serverLabel = AppState.getServer()?.label || 'Unknown'; const serverLabel = AppState.getServer()?.label || 'Unknown';
const serverConnected = AppState.getServerConnected() ? '🟢' : '🔴'; const serverConnected = AppState.getServerConnected() ? `🟢 (${AppState.getServerLatency()}ms)` : '🔴';
// Get page info // Get page info
const pageDisplay = AppState.getCurrentPage() || 'unknown'; const pageDisplay = AppState.getCurrentPage() || 'unknown';
@@ -660,20 +683,24 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
<span id="safety-toggle-btn" style="color: ${safetyStatus.enabled ? '#28a745' : '#dc3545'}; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid ${safetyStatus.enabled ? '#28a745' : '#dc3545'}; background: ${safetyStatus.enabled ? 'rgba(40, 167, 69, 0.1)' : 'rgba(220, 53, 69, 0.1)'}; transition: all 0.2s ease;" title="Click to toggle safety status">🛟 Safety: ${safetyStatus.enabled ? '🛡️ Safe' : '🚨 Blocked'}</span> <span id="safety-toggle-btn" style="color: ${safetyStatus.enabled ? '#28a745' : '#dc3545'}; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid ${safetyStatus.enabled ? '#28a745' : '#dc3545'}; background: ${safetyStatus.enabled ? 'rgba(40, 167, 69, 0.1)' : 'rgba(220, 53, 69, 0.1)'}; transition: all 0.2s ease;" title="Click to toggle safety status">🛟 Safety: ${safetyStatus.enabled ? '🛡️ Safe' : '🚨 Blocked'}</span>
</div> </div>
<div style="margin-bottom: 4px;"> <div style="margin-bottom: 4px;">
<span id="debug-toggle-btn" style="color: ${AppSettings.getDebug() ? '#17a2b8' : '#6c757d'}; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid ${AppSettings.getDebug() ? '#17a2b8' : '#6c757d'}; background: ${AppSettings.getDebug() ? 'rgba(23, 162, 184, 0.1)' : 'rgba(108, 117, 125, 0.1)'}; transition: all 0.2s ease;" title="Click to toggle debug mode">🐛 Debug: ${AppSettings.getDebug() ? '✔️ ON' : '❌ OFF'}</span> <span style="color: #6c757d; font-size: 11px;">🆔 Tab: ${AppSession.SESSION_ID.slice(-12)}</span>
</div> </div>
<div style="margin-bottom: 4px;"> <div style="margin-bottom: 4px;">
<span id="bot-status-toggle-btn" style="color: #007bff; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid #007bff; background: rgba(0, 123, 255, 0.1); transition: all 0.2s ease;" title="Click to toggle bot status between idle and running">🤖 Bot Status: ${statusDisplay}</span> <span id="bot-status-toggle-btn" style="color: #007bff; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid #007bff; background: rgba(0, 123, 255, 0.1); transition: all 0.2s ease;" title="Click to toggle bot status between idle and running">🤖 Bot Status: ${statusDisplay}</span>
</div> </div>
<div style="margin-bottom: 4px;">
<span id="server-toggle-btn" style="color: #e83e8c; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid #e83e8c; background: rgba(232, 62, 140, 0.1); transition: all 0.2s ease;" title="Click to switch between local and prod servers">🌐 Server: ${serverLabel} ${serverConnected}</span>
</div>
<div style="margin-bottom: 4px;"> <div style="margin-bottom: 4px;">
<span style="color: #fd7e14;">👤 Login: ${loginStatus}</span> <span style="color: #fd7e14;">👤 Login: ${loginStatus}</span>
</div> </div>
<div style="margin-bottom: 4px;"> <div style="margin-bottom: 4px;">
<span style="color: #6f42c1;">Page: ${pageDisplay}</span> <span style="color: #6f42c1;">Page: ${pageDisplay}</span>
</div> </div>
<div style="margin-bottom: 4px;">
<span id="server-toggle-btn" style="color: #e83e8c; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid #e83e8c; background: rgba(232, 62, 140, 0.1); transition: all 0.2s ease;" title="Click to switch between local and prod servers">🌐 Server: ${serverLabel} ${serverConnected}</span>
</div>
<div style="margin-bottom: 4px;">
<span id="debug-toggle-btn" style="color: ${AppSettings.getDebug() ? '#17a2b8' : '#6c757d'}; cursor: pointer; padding: 2px 4px; border-radius: 3px; border: 1px solid ${AppSettings.getDebug() ? '#17a2b8' : '#6c757d'}; background: ${AppSettings.getDebug() ? 'rgba(23, 162, 184, 0.1)' : 'rgba(108, 117, 125, 0.1)'}; transition: all 0.2s ease;" title="Click to toggle debug mode">🐛 Debug: ${AppSettings.getDebug() ? '✔️ ON' : '❌ OFF'}</span>
</div>
`; `;
// Update content (excluding position button) // Update content (excluding position button)
@@ -732,9 +759,9 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
serverToggleBtn.onclick = async () => { serverToggleBtn.onclick = async () => {
const currentServerType = AppSettings.getServerType(); const currentServerType = AppSettings.getServerType();
const newServerType = currentServerType === 'local' ? 'prod' : 'local'; const newServerType = currentServerType === 'local' ? 'prod' : 'local';
// Update server type in settings // Update server type in settings
AppSettings.setServerType(newServerType); AppSettings.setServerType(newServerType);
await AppState.update({ server_last_seen: null }); await AppState.update({ server_last_seen: null });
// Update the content to reflect the change // Update the content to reflect the change
@@ -807,7 +834,7 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
await AppSettings.setToken(input); await AppSettings.setToken(input);
} }
const s = AppState.getServer(); const s = AppState.getServer();
const res = await BAF.ping(); const res = await BAF.register({ session_id: AppSession.SESSION_ID });
const resStr = const resStr =
`Server: ${s.label} (${s.url})\n` + `Server: ${s.label} (${s.url})\n` +
`Status: ${res.ok ? 'Connected ✅' : 'Failed ❌'} (${res.status})`; `Status: ${res.ok ? 'Connected ✅' : 'Failed ❌'} (${res.status})`;
@@ -843,9 +870,11 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
// Setup observers for dashboard overlay updates // Setup observers for dashboard overlay updates
AppServices.initObservers(); AppServices.initObservers();
await AppServices.registerSession();
// Setup interval services // Setup interval services
AppServices.initInterval(); AppServices.initInterval();
TL.log('APP-SERVICES', 'AppServices initialized'); TL.log('APP-SERVICES', 'AppServices initialized');
}, },
@@ -868,13 +897,15 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
// } // }
// }); // });
}, },
registerSession: async () => {
const msg = await BAF.register({ session_id: AppSession.SESSION_ID });
AppSession.setSessionToken(msg.data.token);
TL.log('APP-SERVICES', `Session token: ${AppSession.getSessionToken()}`);
},
// Setup interval services // Setup interval services
initInterval: () => { initInterval: () => {
// Setup heartbeat interval
setInterval(() => AppServices.heartbeat(), CONFIG.HEARTBEAT_INTERVAL); setInterval(() => AppServices.heartbeat(), CONFIG.HEARTBEAT_INTERVAL);
// Setup dashboard overlay update interval
setInterval(() => AppUi.dashboardOverlay.updateContent(), CONFIG.DASHBOARD_UPDATE_INTERVAL); setInterval(() => AppUi.dashboardOverlay.updateContent(), CONFIG.DASHBOARD_UPDATE_INTERVAL);
TL.debug('APP-SERVICES', 'Interval services started'); TL.debug('APP-SERVICES', 'Interval services started');
@@ -895,14 +926,18 @@ GM_log('[TL] 🏁 Welcome to Binance Alpha Farm Agent.');
current_page: AppState.getCurrentPage(), current_page: AppState.getCurrentPage(),
bot_status: AppSettings.getBotStatus(), bot_status: AppSettings.getBotStatus(),
current_task: null, // TODO: Add to AppState if needed current_task: null, // TODO: Add to AppState if needed
task_data: null, // TODO: Add to AppState if needed current_task_data: null, // TODO: Add to AppState if needed
current_step: null, // TODO: Add to AppState if needed current_step: null, // TODO: Add to AppState if needed
}; };
// TL.debug(`HEARTBEAT`, `${JSON.stringify(status, null, 2)}`); // TL.debug(`HEARTBEAT`, `${JSON.stringify(status, null, 2)}`);
const start = performance.now();
const res = await BAF.ping(status); const res = await BAF.ping(status);
const end = performance.now();
const duration = Math.round(end - start);
if (res.ok) { if (res.ok) {
AppState.update({ server_last_seen: new Date() }); AppState.update({ server_last_seen: new Date(), server_latency: duration });
} }
return status; return status;