Skip to content

Commit 3010dca

Browse files
committed
Update attempt_login to better handle errors
1 parent 047c97a commit 3010dca

1 file changed

Lines changed: 95 additions & 30 deletions

File tree

SLScheevo.py

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
import requests
1212
import platform
1313
import itertools
14-
import threading
1514
import base64
1615
import subprocess
1716
import uuid
1817
import getpass
1918
import hashlib
2019
import argparse
2120
import logging
21+
from gevent import Timeout
2222
from pathlib import Path
2323
from cryptography.fernet import Fernet
2424
from cryptography.hazmat.primitives import hashes
@@ -201,8 +201,17 @@ def handle_exception(exc_type, exc_value, exc_traceback):
201201

202202
def prompt(self, msg: str) -> str:
203203
"""Log a prompt with [→] but keep input on same line."""
204-
# Get the formatted prefix from the logger (e.g. "[→] ")
205-
prefix = ConsoleFormatter.SYMBOLS.get("INFO", "[→] ")
204+
prefix = ConsoleFormatter.SYMBOLS.get("INFO", "[->] ")
205+
206+
# Print prefix and message WITHOUT newline
207+
print(f"{prefix}{msg} ", end="", flush=True)
208+
209+
# Now take input
210+
return input()
211+
212+
def promptwarn(self, msg: str) -> str:
213+
"""Log a prompt with [→] but keep input on same line."""
214+
prefix = ConsoleFormatter.SYMBOLS.get("INFO", "[!!] ")
206215

207216
# Print prefix and message WITHOUT newline
208217
print(f"{prefix}{msg} ", end="", flush=True)
@@ -250,7 +259,7 @@ def login(self, login_input=None):
250259

251260
# Step 3: Handle login result
252261
if result != EResult.OK:
253-
self.logger.log_error(f"Steam login failed: {result.name}")
262+
self.logger.log_error(f"Steam login failed, exiting")
254263
self.client.logout()
255264
sys.exit(EXIT_LOGIN_FAILED)
256265

@@ -350,44 +359,98 @@ def get_available_accounts(self):
350359
def attempt_login(self):
351360
"""Perform the main login"""
352361
result = None
353-
prompt_for_unavailable = True
362+
prompt_disabled = False
363+
login_timeout = 2
364+
retry_count = 0
365+
max_tries = 10
354366

355-
while result in (EResult.TryAnotherCM, EResult.ServiceUnavailable, EResult.InvalidPassword, None):
367+
while True:
368+
try:
369+
if retry_count == 0:
370+
self.logger.log_info(f"Logging in...")
371+
else:
372+
self.logger.log_info(f"Login attempt {retry_count + 1}...")
373+
with Timeout(login_timeout):
374+
self.client.connect()
375+
result = self.client.login(self.username, self.env_password, self.refresh_token)
376+
except Timeout:
377+
self.logger.log_warning(f"Login timed out after {login_timeout} seconds")
378+
result = EResult.Timeout
379+
except Exception as e:
380+
self.logger.log_error(f"Login error: {e}")
381+
result = None
356382

357-
# Handle connection issues
358-
if result in (EResult.TryAnotherCM, EResult.ServiceUnavailable):
359-
if prompt_for_unavailable and result == EResult.ServiceUnavailable:
360-
if not self.handle_service_unavailable():
361-
break
362-
prompt_for_unavailable = False
363-
self.client.reconnect(maxdelay=15)
383+
if result == EResult.OK:
384+
break
364385

365-
# Handle authentication failures
386+
# Handle authentication failures (non-retryable)
366387
if result == EResult.InvalidPassword:
367-
self.logger.log_error("Invalid password or refresh_token.")
368-
self.logger.log_error(f"Correct the password or delete '{self.main.SAVED_LOGINS_FILE}' and try again.")
369-
self.client.logout()
388+
if self.refresh_token or self.main.SILENT_MODE:
389+
self.logger.log_error("Looks like the token wasn't accepted or the password is wrong")
390+
self.logger.log_error(f"Try deleting '{self.main.SAVED_LOGINS_FILE}' and then try again.")
391+
sys.exit(EXIT_LOGIN_FAILED)
392+
else:
393+
self.logger.log_error("Invalid password. Please try again with the correct one")
394+
self.client.logout()
395+
self.client.disconnect()
396+
continue
397+
398+
if not self.main.SILENT_MODE and not prompt_disabled:
399+
self.handle_service_unavailable()
400+
prompt_disabled = True
401+
402+
# Ask if we should continue
403+
if not self.main.INFINITE_RETRY and not self.main.SILENT_MODE and retry_count >= max_tries:
404+
self.handle_service_unavailable()
405+
max_tries += 5
406+
407+
# Handle connection issues (retryable)
408+
retry_count += 1
409+
410+
msg = f"An unrecognized error occurred when trying to login: {result}"
411+
if result == EResult.TryAnotherCM:
412+
msg = "The Steam Servers aren't letting us login (TryAnotherCM) - Try waiting a while before contacting the servers again"
413+
elif result == EResult.Timeout:
414+
msg = "The login attempt timed out (Timeout)"
415+
elif result == EResult.ServiceUnavailable:
416+
msg = "The Steam Servers aren't available right now (ServiceUnavailable)"
417+
418+
self.logger.log_error(msg)
419+
if self.main.SILENT_MODE and not self.main.INFINITE_RETRY and prompt_disabled:
370420
sys.exit(EXIT_LOGIN_FAILED)
371421

372-
# Get credentials via web auth if needed
373-
if not self.refresh_token:
374-
if not self.perform_web_authentication():
375-
self.client.logout()
376-
sys.exit(EXIT_LOGIN_FAILED)
422+
base_wait = min(5 * (2 ** (retry_count - 1)), 1)
423+
jitter = base_wait * 0.1 # Add 10% random jitter
424+
wait_time = base_wait + (time.time() % jitter)
377425

378-
result = self.client.login(self.username, self.env_password, self.refresh_token)
426+
self.logger.log_info(f"Waiting {wait_time:.1f} seconds before retry ({retry_count}/{'infinity' if self.main.INFINITE_RETRY else max_tries})")
427+
time.sleep(wait_time)
428+
self.client.disconnect()
429+
continue
430+
431+
# Get credentials via web auth if needed (only on success)
432+
if not self.refresh_token and result not in (EResult.InvalidPassword, None):
433+
if not self.perform_web_authentication():
434+
self.client.logout()
435+
sys.exit(EXIT_LOGIN_FAILED)
379436

380437
return result
381438

382439
def handle_service_unavailable(self):
383-
"""Handle Steam service unavailable scenario"""
384-
if self.main.SILENT_MODE:
385-
return False
386-
440+
"""Handle Steam service unavailable scenario with y/n/i options"""
387441
while True:
388-
answer = input("[!] Steam is down. Keep retrying? [y/n]: ").lower()
389-
if answer in 'yn':
390-
return answer == 'y'
442+
answer = self.logger.promptwarn(f"Keep retrying? (y=yes, n=no, i=infinite): ").lower()
443+
if answer == 'i':
444+
self.main.INFINITE_RETRY = True
445+
self.logger.log_info("Retrying infinitely. Press CTRL+C to cancel")
446+
return
447+
elif answer == 'y':
448+
self.main.INFINITE_RETRY = False
449+
self.logger.log_info("Retrying.")
450+
return
451+
else:
452+
self.logger.log_info("No retry selected, exiting.")
453+
sys.exit(EXIT_LOGIN_FAILED)
391454

392455
def perform_web_authentication(self):
393456
"""Perform web-based authentication when no refresh token exists"""
@@ -1193,11 +1256,13 @@ def run(self):
11931256
parser.add_argument('--appid', type=str, help='Comma-separated list of app IDs to generate schemas for')
11941257
parser.add_argument('--save-dir', type=str, help='Base directory to save data and outputs (overrides default script-based base dir)')
11951258
parser.add_argument('--max-tries', type=int, help='Maximum number of consecutive "no schema" responses before giving up')
1259+
parser.add_argument('--infinite-retry', action='store_true', help='Retry login attempts infinitely when encountering network errors')
11961260

11971261
args = parser.parse_args()
11981262

11991263
self.SILENT_MODE = args.silent
12001264
self.VERBOSE = args.verbose
1265+
self.INFINITE_RETRY = args.infinite_retry
12011266

12021267
# If user specified a save directory, update BASE_DIR and all dependent paths
12031268
if args.save_dir:

0 commit comments

Comments
 (0)