67 lines
2.1 KiB
Python
67 lines
2.1 KiB
Python
"""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]
|