"""What the town keeps between commands in .state/town/ (removed with the pasture): every account it made and the session (token, local id, actor) each one signs in with, so a second command never makes or signs in anyone again.""" import json import os import threading from dialects import driver from dialects.base import Account, Session ROOT = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), ".state", "town") _lock = threading.Lock() def _path(name): os.makedirs(ROOT, exist_ok=True) return os.path.join(ROOT, name) def load(name, default): try: with open(_path(name)) as f: return json.load(f) except (FileNotFoundError, ValueError): return default def save(name, value): with _lock: tmp = _path(name) + ".tmp" with open(tmp, "w") as f: json.dump(value, f, indent=1, default=str) os.replace(tmp, _path(name)) def remember(sessions): stored = load("sessions.json", {}) for s in sessions: stored[f"{s.account.platform}/{s.account.username}"] = { "account": s.account.__dict__, "token": s.token, "local_id": s.local_id, "actor_uri": s.actor_uri} save("sessions.json", stored) def session(platform, username): stored = load("sessions.json", {}).get(f"{platform}/{username}") if stored is None: raise KeyError(f"the town has no account {username} on {platform}") return Session(Account(**stored["account"]), stored["token"], stored["local_id"], stored["actor_uri"]) def sessions(platform=None): out = [] for key, stored in load("sessions.json", {}).items(): if platform and not key.startswith(platform + "/"): continue out.append(Session(Account(**stored["account"]), stored["token"], stored["local_id"], stored["actor_uri"])) return out def provision(platform, accounts): """Sessions for `accounts`, making and signing in only those the town does not already have.""" known = {s.account.username: s for s in sessions(platform)} missing = [a for a in accounts if a.username not in known] if missing: made = driver(platform).provision(missing) remember(made) known.update({s.account.username: s for s in made}) return [known[a.username] for a in accounts]