feat: automatically attempt reauth when timed out

sometimes MS times out our refresh request, making clients disconnect.
Implemented a retry loop, which will attempt to authenticate up to 5
times (configurable) waiting 60 seconds in between (configurable).
Only timeouts will be handled, any other exception will make it crash
immediately.
This commit is contained in:
əlemi 2022-08-25 19:42:53 +02:00
parent 1499cab317
commit b14ca9d862
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
2 changed files with 20 additions and 11 deletions

View file

@ -41,7 +41,7 @@ class AddonStorage:
cur.execute(f"INSERT INTO documents_{self.name} VALUES (?, ?)", (key, json.dumps(val, default=str),)) cur.execute(f"INSERT INTO documents_{self.name} VALUES (?, ?)", (key, json.dumps(val, default=str),))
self.db.commit() self.db.commit()
class Storage: class StorageDriver:
name : str name : str
db : sqlite3.Connection db : sqlite3.Connection

View file

@ -14,7 +14,7 @@ from aiocraft.mc.packet import Packet
from aiocraft.mc.auth import AuthInterface, AuthException, MojangAuthenticator, MicrosoftAuthenticator, OfflineAuthenticator from aiocraft.mc.auth import AuthInterface, AuthException, MojangAuthenticator, MicrosoftAuthenticator, OfflineAuthenticator
from aiocraft.mc.auth.microsoft import InvalidStateError from aiocraft.mc.auth.microsoft import InvalidStateError
from .storage import Storage, SystemState, AuthenticatorState from .storage import StorageDriver, SystemState, AuthenticatorState
from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld, GameContainer from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld, GameContainer
from .addon import Addon from .addon import Addon
from .notifier import Notifier, Provider from .notifier import Notifier, Provider
@ -37,7 +37,7 @@ class Treepuncher(
GameWorld GameWorld
): ):
name: str name: str
storage: Storage storage: StorageDriver
notifier: Notifier notifier: Notifier
scheduler: AsyncIOScheduler scheduler: AsyncIOScheduler
@ -99,7 +99,7 @@ class Treepuncher(
resolve_srv=opt('resolve_srv', default=True, t=bool), resolve_srv=opt('resolve_srv', default=True, t=bool),
) )
self.storage = Storage(opt('session_file') or f"data/{name}.session") # TODO wrap with pathlib self.storage = StorageDriver(opt('session_file') or f"data/{name}.session") # TODO wrap with pathlib
self.notifier = Notifier(self) self.notifier = Notifier(self)
@ -130,13 +130,22 @@ class Treepuncher(
return self.authenticator.selectedProfile.name return self.authenticator.selectedProfile.name
async def authenticate(self): async def authenticate(self):
await super().authenticate() sleep_interval = self.cfg.getfloat("auth_retry_interval", fallback=60.0)
state = AuthenticatorState( for _ in range(self.cfg.getint("auth_retry_count", fallback=5)):
date=datetime.datetime.now(), try:
token=self.authenticator.serialize(), await super().authenticate()
legacy=isinstance(self.authenticator, MojangAuthenticator) state = AuthenticatorState(
) date=datetime.datetime.now(),
self.storage._set_auth(state) token=self.authenticator.serialize(),
legacy=isinstance(self.authenticator, MojangAuthenticator)
)
self.storage._set_auth(state)
return
except AuthException as e:
if e.data["error"] == "request timed out":
await asyncio.sleep(sleep_interval)
continue
raise e # retrying won't help anyway
async def start(self): async def start(self):
# if self.started: # TODO readd check # if self.started: # TODO readd check