diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index 448c33c..0000000 --- a/public/favicon.ico +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/dashboard/SessionLoader.ts b/src/dashboard/SessionLoader.ts new file mode 100644 index 0000000..200c80a --- /dev/null +++ b/src/dashboard/SessionLoader.ts @@ -0,0 +1,119 @@ +import fs from 'fs' +import path from 'path' + +export interface SessionPoints { + email: string + points: number + lastUpdated: string +} + +/** + * Try to load points from session data + */ +export function loadPointsFromSessions(email: string): number | undefined { + try { + const sessionsDir = path.join(process.cwd(), 'sessions') + if (!fs.existsSync(sessionsDir)) { + return undefined + } + + // Try to find session file for this email + const emailHash = Buffer.from(email).toString('base64').replace(/[^a-zA-Z0-9]/g, '') + const possibleFiles = [ + `${email}.json`, + `${emailHash}.json`, + `session_${email}.json` + ] + + for (const filename of possibleFiles) { + const filepath = path.join(sessionsDir, filename) + if (fs.existsSync(filepath)) { + const data = JSON.parse(fs.readFileSync(filepath, 'utf-8')) + if (data.points !== undefined) { + return data.points + } + if (data.availablePoints !== undefined) { + return data.availablePoints + } + } + } + + return undefined + } catch (error) { + console.error(`[Dashboard] Error loading points for ${email}:`, error) + return undefined + } +} + +/** + * Try to load all points from sessions + */ +export function loadAllPointsFromSessions(): Map { + const pointsMap = new Map() + + try { + const sessionsDir = path.join(process.cwd(), 'sessions') + if (!fs.existsSync(sessionsDir)) { + return pointsMap + } + + const files = fs.readdirSync(sessionsDir) + + for (const filename of files) { + if (!filename.endsWith('.json')) continue + + try { + const filepath = path.join(sessionsDir, filename) + const data = JSON.parse(fs.readFileSync(filepath, 'utf-8')) + + const email = data.email || data.account?.email + const points = data.points || data.availablePoints + + if (email && points !== undefined) { + pointsMap.set(email, points) + } + } catch (error) { + // Skip invalid files + continue + } + } + } catch (error) { + console.error('[Dashboard] Error loading points from sessions:', error) + } + + return pointsMap +} + +/** + * Try to load points from job state + */ +export function loadPointsFromJobState(email: string): number | undefined { + try { + const jobStateDir = path.join(process.cwd(), 'sessions', 'job-state') + if (!fs.existsSync(jobStateDir)) { + return undefined + } + + const files = fs.readdirSync(jobStateDir) + + for (const filename of files) { + if (!filename.endsWith('.json')) continue + + try { + const filepath = path.join(jobStateDir, filename) + const data = JSON.parse(fs.readFileSync(filepath, 'utf-8')) + + if (data.email === email || data.account === email) { + return data.points || data.availablePoints + } + } catch (error) { + continue + } + } + + return undefined + } catch (error) { + console.error(`[Dashboard] Error loading job state for ${email}:`, error) + return undefined + } +} diff --git a/src/dashboard/routes.ts b/src/dashboard/routes.ts index 5e76509..4ecee5c 100644 --- a/src/dashboard/routes.ts +++ b/src/dashboard/routes.ts @@ -10,8 +10,19 @@ export const apiRouter = Router() // GET /api/status - Bot status apiRouter.get('/status', (_req: Request, res: Response) => { try { - const status = dashboardState.getStatus() - res.json(status) + const accounts = dashboardState.getAccounts() + + // If no accounts loaded yet, try to load them + if (accounts.length === 0) { + try { + const loadedAccounts = loadAccounts() + dashboardState.initializeAccounts(loadedAccounts.map(a => a.email)) + } catch (error) { + console.error('[Dashboard] Failed to load accounts for status:', error) + } + } + + res.json(dashboardState.getStatus()) } catch (error) { res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' }) } @@ -20,7 +31,19 @@ apiRouter.get('/status', (_req: Request, res: Response) => { // GET /api/accounts - List all accounts with masked emails apiRouter.get('/accounts', (_req: Request, res: Response) => { try { - const accounts = dashboardState.getAccounts() + let accounts = dashboardState.getAccounts() + + // If no accounts in state, try to load from config + if (accounts.length === 0) { + try { + const loadedAccounts = loadAccounts() + dashboardState.initializeAccounts(loadedAccounts.map(a => a.email)) + accounts = dashboardState.getAccounts() + } catch (error) { + console.error('[Dashboard] Failed to load accounts:', error) + } + } + res.json(accounts) } catch (error) { res.status(500).json({ error: error instanceof Error ? error.message : 'Unknown error' }) diff --git a/src/dashboard/state.ts b/src/dashboard/state.ts index 6d18f65..6b45b41 100644 --- a/src/dashboard/state.ts +++ b/src/dashboard/state.ts @@ -1,4 +1,5 @@ import { MicrosoftRewardsBot } from '../index' +import { loadAllPointsFromSessions, loadPointsFromJobState } from './SessionLoader' export interface DashboardStatus { running: boolean @@ -133,12 +134,23 @@ class DashboardState { // Initialize accounts from config public initializeAccounts(emails: string[]): void { + // Load points from sessions if available + const pointsMap = loadAllPointsFromSessions() + for (const email of emails) { if (!this.accounts.has(email)) { + // Try to get points from session or job state + let points = pointsMap.get(email) + if (points === undefined) { + points = loadPointsFromJobState(email) + } + this.accounts.set(email, { email, maskedEmail: this.maskEmail(email), - status: 'idle' + status: 'idle', + points: points, + lastSync: points !== undefined ? new Date().toISOString() : undefined }) } }