Added single-account execution functionality and historical data loading for charts

This commit is contained in:
2025-12-22 21:55:30 +01:00
parent 5b27d11c0d
commit 00f539ae04
4 changed files with 215 additions and 2 deletions

View File

@@ -88,7 +88,7 @@
},
// === BROWSER ===
"browser": {
"headless": true,
"headless": false,
"globalTimeout": "30s"
},
"fingerprinting": {

View File

@@ -106,6 +106,81 @@ export class BotController {
return await this.start()
}
/**
* Run a single account (for dashboard "run single" feature)
* FIXED: Actually implement single account execution
*/
public async runSingle(email: string): Promise<{ success: boolean; error?: string; pid?: number }> {
if (this.botInstance) {
return { success: false, error: 'Bot is already running. Stop it first.' }
}
if (this.isStarting) {
return { success: false, error: 'Bot is currently starting, please wait' }
}
try {
this.isStarting = true
this.log(`🚀 Starting bot for single account: ${email}`, 'log')
const { MicrosoftRewardsBot } = await import('../index')
const { loadAccounts } = await import('../util/state/Load')
// Load all accounts and filter to just this one
const allAccounts = loadAccounts()
const targetAccount = allAccounts.find(a => a.email === email)
if (!targetAccount) {
return { success: false, error: `Account ${email} not found in accounts.jsonc` }
}
this.botInstance = new MicrosoftRewardsBot(false)
this.startTime = new Date()
dashboardState.setRunning(true)
dashboardState.setBotInstance(this.botInstance)
// Update account status
dashboardState.updateAccount(email, { status: 'running', errors: [] })
// Run bot asynchronously with single account
void (async () => {
try {
this.log(`✓ Bot initialized for ${email}, starting execution...`, 'log')
await this.botInstance!.initialize()
// Override accounts to run only this one
; (this.botInstance as any).accounts = [targetAccount]
await this.botInstance!.run()
this.log(`✓ Bot completed successfully for ${email}`, 'log')
dashboardState.updateAccount(email, { status: 'completed' })
} catch (error) {
const errMsg = error instanceof Error ? error.message : String(error)
this.log(`Bot error for ${email}: ${errMsg}`, 'error')
dashboardState.updateAccount(email, {
status: 'error',
errors: [errMsg]
})
} finally {
this.cleanup()
}
})()
return { success: true, pid: process.pid }
} catch (error) {
const errorMsg = error instanceof Error ? error.message : String(error)
this.log(`Failed to start bot for ${email}: ${errorMsg}`, 'error')
dashboardState.updateAccount(email, { status: 'error', errors: [errorMsg] })
this.cleanup()
return { success: false, error: errorMsg }
} finally {
this.isStarting = false
}
}
private async wait(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}

View File

@@ -199,6 +199,34 @@ apiRouter.post('/restart', async (_req: Request, res: Response): Promise<void> =
}
})
// POST /api/run-single - Run a single account (dashboard feature)
apiRouter.post('/run-single', async (req: Request, res: Response): Promise<void> => {
try {
const { email } = req.body
if (!email) {
sendError(res, 400, 'Email is required')
return
}
const status = botController.getStatus()
if (status.running) {
sendError(res, 400, `Bot already running (PID: ${status.pid}). Stop it first.`)
return
}
const result = await botController.runSingle(email)
if (result.success) {
sendSuccess(res, { message: `Started bot for account ${email}`, pid: result.pid })
} else {
sendError(res, 500, result.error || 'Failed to start bot for account')
}
} catch (error) {
sendError(res, 500, getErr(error))
}
})
// GET /api/metrics - Basic metrics
apiRouter.get('/metrics', (_req: Request, res: Response) => {
try {