Krifix Posted January 3 Report Posted January 3 (edited) Hey everyone, I'm developing a discord bot announcing changes in apps (kinda like steamdb). Everything works perfectly fine for the first few hours, but then appUpdate no longer fires. I haven't seen any messages thrown by steamCommunity "sessionExpired" event, client "disconnected" and "error" events. This scenario happened every time, but yesterday after running bot for about a week, I got an app update notification which is strange for me, because it was always completely silent after a few hours. I was searching through github issues and forum as well, but found nothing. I've tried implementing reconnecting to steamcommunity, but can't go past "Must not be anonymous user to use webLogOn (check to see you passed in valid credentials to logOn)". I think that is because it's logging via refreshToken. I don't even know if appUpdate is managed by steamcommunity. steam-client.ts steamClient: SteamUser; steamCommunity: SteamCommunity; listener: SteamListener; private RECONNECT_INTERVAL = 10000; private issuedRefreshToken: string | null; private useAnonymous: boolean; private refreshToken: string | null; private accountName: string | null; private password: string | null; private machineName: string | null; private shouldReconnect = false; constructor() { this.useAnonymous = Config.default.steam.anonymous; this.refreshToken = Config.default.steam.refresh_token; this.accountName = Config.default.steam.account_name; this.password = Config.default.steam.password; this.machineName = Config.default.steam.machine_name; this.issuedRefreshToken = null; this.listener = new SteamListener(); this.steamCommunity = new SteamCommunity(); this.steamClient = new SteamUser({ "enablePicsCache": true, "autoRelogin": true, "changelistUpdateInterval": 15000, "renewRefreshTokens": true, }); this.steamClient.on("webSession", (_, cookies) => { console.log(chalk.green("Steam reconnected.")); this.steamCommunity.setCookies(cookies); this.steamCommunity.startConfirmationChecker(10000, '='); this.shouldReconnect = false; }) this.steamCommunity.on("sessionExpired", () => { console.log(chalk.red("Steam session expired.")); this.shouldReconnect = true; }); this.steamClient.on("disconnected", (eresult, msg) => { console.log(chalk.red(`Disconnected from steam: [ EResult: ${eresult} ] ${msg}`)); }); this.steamClient.on("error", (error) => { console.log(chalk.red(error)); }); } private attemptToReconnectTick() { console.log("b") if(this.shouldReconnect) { if(this.steamClient.steamID) { this.steamClient.webLogOn(); } this.steamClient.logOn(); } setTimeout(this.attemptToReconnectTick.bind(this), this.RECONNECT_INTERVAL); } async connect() : Promise<void> { console.log("[/] Connecting to Steam..."); if(this.useAnonymous) { return await this.loginAsAnonymous(); } if(this.refreshToken != null && this.refreshToken != "") { await this.loginWithRefreshToken(); // TEST - start reconnect task this.shouldReconnect = true; return this.attemptToReconnectTick(); } await this.loginWithUsernameAndPassword(); } async loginAsAnonymous() { this.steamClient.logOn({ "anonymous": true, "machineName": this.machineName ? this.machineName : undefined }); await this.waitForLogin(); this.listener.registerListeners(this); console.log(chalk.green(`Steam Client connected as anonymous.`)); } private async loginWithUsernameAndPassword() { if(this.accountName == null || this.password == null || this.accountName.includes(" ") || this.password.includes(" ") || this.accountName.replace(" ", "") == "" || this.password.replace(" ", "") == "" ) { console.log(chalk.bgRed("ERROR") + " " + chalk.red("This steam authentication method requires username and password.")) process.exit(0); } this.steamClient.logOn({ "accountName": this.accountName!, "password": this.password!, "machineName": this.machineName ? this.machineName : undefined }); await this.waitForLogin(); this.listener.registerListeners(this); console.log(chalk.green(`Steam Client connected using username/password as ${this.steamClient.accountInfo?.name}.`)); if(this.issuedRefreshToken != null && this.issuedRefreshToken != "" ) { console.log(chalk.blue("Steam uses refresh tokens when logging in.")); console.log(chalk.blue("Your refresh token is: ") + chalk.bgBlue(this.issuedRefreshToken)); console.log(chalk.blue("It's recommended to use it instead of username/password. You can change that in the config file.")); } } private async loginWithRefreshToken() { if( this.refreshToken == null || this.refreshToken == "" || this.refreshToken.includes(" ") ) { console.log(chalk.bgRed("ERROR") + " " + chalk.red("This steam authentication method requires a refresh token.")) process.exit(0); } this.steamClient.logOn({ "accountName": this.accountName!, "password": this.password!, "machineName": this.machineName ? this.machineName : undefined }); await this.waitForLogin(); this.listener.registerListeners(this); console.log(chalk.green(`Steam Client connected using refresh token as ${this.steamClient.accountInfo?.name}.`)); } // library provides any type, so we need to use it // deno-lint-ignore no-explicit-any private waitForLogin() : Promise<Record<string, any>> { return new Promise((resolve) => { this.steamClient.once("loggedOn", (loginInfo) => { resolve(loginInfo); }); this.steamClient.once("refreshToken", (token) => { this.issuedRefreshToken = token; }); this.steamClient.once("error", (error) => { throw error; }); }) } getApplicationInfo(appId: number) : Promise<AppInfo | null> { return new Promise((resolve) => { this.steamClient.getProductInfo([appId], [], false, (_err, apps) => { resolve(apps[appId]); }) }); } steam-listener.ts registerListeners(steamClient: SteamClient) { steamClient.steamClient.on("appUpdate", this.onAppUpdateReceived.bind(this)); } /** * Called when an app is updated. * @param appid The id of the app that was updated. * @param data The new app info. */ async onAppUpdateReceived(appId: number, data: AppInfo): Promise<void> { if(await UserApplicationsController.isApplicationPresentAnywhere(appId) == false && await ServerApplicationsController.isApplicationPresentAnywhere(appId) == false) { return; } const cachedApp: ICachedApplications | null = await CachedApplicationsController.getCachedApplication(appId); const newAppInfo: AppInfo | null = await SteamClientInstance.getApplicationInfo(appId); console.log(`[*] Received update for application ${appId}.`); if(cachedApp != null && cachedApp.changenumber == data.changenumber) { console.log(`[*] No changes detected.`); return; } if(cachedApp == null || newAppInfo == null) { return CachedApplicationsController.cacheApplication(newAppInfo); } // don't announce if only the changenumber changed const changes = ApplicationDataComparator.compareApplicationData(cachedApp, newAppInfo); if(!this.isChangeOnlyChangeNumber(changes)) { await AnnouncementsManager.announceApplicationChangelist(data.changenumber, appId, changes); } // finally save the new app info await CachedApplicationsController.cacheApplication(newAppInfo); } private isChangeOnlyChangeNumber(changes: ApplicationChanges): boolean { let isOnlyChangeNumber = true; keys<ApplicationChanges>(changes).forEach(key => { const change = changes[key]; // changeNumber changes every time a change is detected // so we don't need to check if changeNumber actually changed // we are skipping branches because they are handled separately if(key == "branches" || key == "changenumber") { return; } if(this.didChange(change)) { isOnlyChangeNumber = false; } }); // check for branch changes Object.keys(changes.branches).forEach(branchName => { const branchChanges = changes.branches[branchName]; keys<BranchChanges>(branchChanges).forEach(key => { const change = changes.branches[branchName][key]; if(this.didChange(change)) { isOnlyChangeNumber = false; } }); }); return isOnlyChangeNumber; } private didChange(change: ChangeFromTo): boolean { if((change.from == null || change.from == "") && (change.to != null && change.to != "")) { return true; } if((change.to == null || change.to == "") && (change.from != null && change.from != "")) { return true; } if(change.from != change.to) { return true; } return false; } private getCurrentDateAsString() : string { const options: Intl.DateTimeFormatOptions = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }; return new Date().toLocaleDateString("pl-PL", options); } Edited January 3 by Krifix Quote
Krifix Posted January 6 Author Report Posted January 6 (edited) Also I am using deno.js. Is it possible deno causes that? Edited January 6 by Krifix Quote
Dr. McKay Posted January 6 Report Posted January 6 3 minutes ago, Krifix said: Also I am using deno.js. Is it possible deno causes that? Certainly is. I can't really support your setup if you aren't using Node.js, since my modules are specifically for Node.js. Quote
Krifix Posted January 6 Author Report Posted January 6 Alright, I am gonna change it to using node.js. I'll run it for some time and see if it still happens. Quote
Krifix Posted January 9 Author Report Posted January 9 Looks like it was a deno's fault. Updating it also fixes the issue. I'm sorry I didn't think of it earlier and thanks for helping me. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.