feat: implement manual per-account refresh for instant ban and cooldown updates
This commit is contained in:
@@ -188,6 +188,57 @@ const handleSwitchAccount = async (loginName: string) => {
|
||||
} catch (e) { return false; }
|
||||
};
|
||||
|
||||
// --- Scraper Helper ---
|
||||
const scrapeAccountData = async (account: Account) => {
|
||||
const now = new Date();
|
||||
try {
|
||||
// 1. Refresh Basic Profile & Bans
|
||||
const profile = await fetchProfileData(account.steamId, account.steamLoginSecure);
|
||||
const bans = await scrapeBanStatus(profile.profileUrl, account.steamLoginSecure);
|
||||
|
||||
account.personaName = profile.personaName;
|
||||
account.profileUrl = profile.profileUrl;
|
||||
account.vacBanned = bans.vacBanned;
|
||||
account.gameBans = bans.gameBans;
|
||||
account.status = (bans.vacBanned || bans.gameBans > 0) ? 'banned' : 'none';
|
||||
account.lastBanCheck = now.toISOString();
|
||||
|
||||
if (profile.avatar && (!account.localAvatar || profile.avatar !== account.avatar)) {
|
||||
account.avatar = profile.avatar;
|
||||
const localPath = await downloadAvatar(account.steamId, profile.avatar);
|
||||
if (localPath) account.localAvatar = localPath;
|
||||
}
|
||||
|
||||
// 2. Refresh Cooldowns if session is active
|
||||
if (account.steamLoginSecure) {
|
||||
try {
|
||||
const result = await scrapeCooldown(account.steamId, account.steamLoginSecure);
|
||||
account.authError = false;
|
||||
account.lastScrapeTime = now.toISOString();
|
||||
if (result.isActive) {
|
||||
account.cooldownExpiresAt = result.expiresAt ? result.expiresAt.toISOString() : new Date(Date.now() + 86400000).toISOString();
|
||||
if (backend) await backend.pushCooldown(account.steamId, account.cooldownExpiresAt);
|
||||
} else {
|
||||
account.cooldownExpiresAt = undefined;
|
||||
if (backend) await backend.pushCooldown(account.steamId, undefined);
|
||||
}
|
||||
} catch (e: any) {
|
||||
if (e.message.includes('cookie') || e.message.includes('Sign In')) account.authError = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Share updated state with backend
|
||||
if (backend && !account._id.startsWith('shared_')) {
|
||||
await backend.shareAccount(account);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error(`[Scraper] Failed to scrape ${account.personaName}:`, e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// --- Sync Worker ---
|
||||
const syncAccounts = async () => {
|
||||
initBackend();
|
||||
@@ -244,30 +295,13 @@ const syncAccounts = async () => {
|
||||
const now = new Date();
|
||||
|
||||
// OPTIMIZATION: Ensure ALL authenticated accounts are shared with the server on every sync cycle
|
||||
// this guarantees that even if a push failed previously, it will be reconciled now.
|
||||
if (backend && !account._id.startsWith('shared_')) {
|
||||
console.log(`[Sync] Reconciling account with server: ${account.personaName}`);
|
||||
await backend.shareAccount(account);
|
||||
}
|
||||
|
||||
const lastCheck = account.lastBanCheck ? new Date(account.lastBanCheck) : new Date(0);
|
||||
if ((now.getTime() - lastCheck.getTime()) / 3600000 > 6 || !account.personaName) {
|
||||
const profile = await fetchProfileData(account.steamId, account.steamLoginSecure);
|
||||
const bans = await scrapeBanStatus(profile.profileUrl, account.steamLoginSecure);
|
||||
account.personaName = profile.personaName; account.profileUrl = profile.profileUrl;
|
||||
account.vacBanned = bans.vacBanned; account.gameBans = bans.gameBans;
|
||||
account.status = (bans.vacBanned || bans.gameBans > 0) ? 'banned' : 'none';
|
||||
account.lastBanCheck = now.toISOString();
|
||||
if (profile.avatar && (!account.localAvatar || profile.avatar !== account.avatar)) {
|
||||
account.avatar = profile.avatar;
|
||||
const localPath = await downloadAvatar(account.steamId, profile.avatar);
|
||||
if (localPath) account.localAvatar = localPath;
|
||||
}
|
||||
if (account.loginName) {
|
||||
const config = steamClient.extractAccountConfig(account.loginName);
|
||||
if (config) { account.loginConfig = config; account.sessionUpdatedAt = new Date().toISOString(); }
|
||||
}
|
||||
if (backend) await backend.shareAccount(account);
|
||||
await scrapeAccountData(account);
|
||||
scrapeChanges = true;
|
||||
}
|
||||
|
||||
@@ -276,20 +310,8 @@ const syncAccounts = async () => {
|
||||
const lastScrape = account.lastScrapeTime ? new Date(account.lastScrapeTime) : new Date(0);
|
||||
if ((now.getTime() - lastScrape.getTime()) / 3600000 > 8) {
|
||||
await new Promise(r => setTimeout(r, Math.floor(Math.random() * 60000) + 5000));
|
||||
try {
|
||||
const result = await scrapeCooldown(account.steamId, account.steamLoginSecure);
|
||||
account.authError = false; account.lastScrapeTime = new Date().toISOString();
|
||||
if (result.isActive) {
|
||||
account.cooldownExpiresAt = result.expiresAt ? result.expiresAt.toISOString() : new Date(Date.now() + 86400000).toISOString();
|
||||
if (backend) await backend.pushCooldown(account.steamId, account.cooldownExpiresAt);
|
||||
} else if (account.cooldownExpiresAt) {
|
||||
account.cooldownExpiresAt = undefined;
|
||||
if (backend) await backend.pushCooldown(account.steamId, undefined);
|
||||
}
|
||||
scrapeChanges = true;
|
||||
} catch (e: any) {
|
||||
if (e.message.includes('cookie') || e.message.includes('Sign In')) { account.authError = true; scrapeChanges = true; }
|
||||
}
|
||||
await scrapeAccountData(account);
|
||||
scrapeChanges = true;
|
||||
}
|
||||
}
|
||||
} catch (error) { }
|
||||
@@ -437,6 +459,22 @@ ipcMain.handle('login-to-server', async () => {
|
||||
|
||||
ipcMain.handle('get-server-user-info', () => ({ steamId: store.get('serverConfig').serverSteamId }));
|
||||
ipcMain.handle('sync-now', async () => { await syncAccounts(); return true; });
|
||||
|
||||
ipcMain.handle('scrape-account', async (event, steamId: string) => {
|
||||
const accounts = store.get('accounts') as Account[];
|
||||
const account = accounts.find(a => a.steamId === steamId);
|
||||
if (!account) return false;
|
||||
|
||||
console.log(`[Main] Manually triggering scrape for ${account.personaName}...`);
|
||||
const success = await scrapeAccountData(account);
|
||||
if (success) {
|
||||
store.set('accounts', accounts);
|
||||
if (mainWindow) mainWindow.webContents.send('accounts-updated', accounts);
|
||||
updateTrayMenu();
|
||||
}
|
||||
return success;
|
||||
});
|
||||
|
||||
ipcMain.handle('add-account', async (event, { identifier }) => {
|
||||
try {
|
||||
initBackend();
|
||||
|
||||
@@ -19,6 +19,7 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
loginToServer: () => ipcRenderer.invoke('login-to-server'),
|
||||
getServerUserInfo: () => ipcRenderer.invoke('get-server-user-info'),
|
||||
syncNow: () => ipcRenderer.invoke('sync-now'),
|
||||
scrapeAccount: (steamId: string) => ipcRenderer.invoke('scrape-account', steamId),
|
||||
getCommunityAccounts: () => ipcRenderer.invoke('get-community-accounts'),
|
||||
getServerUsers: () => ipcRenderer.invoke('get-server-users'),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user