Files
hyperfocus-plugin/hyperfocus/channel.py
2025-11-01 10:58:26 +10:00

108 lines
3.5 KiB
Python

from collections import defaultdict
from typing import Optional, TypeAlias, TypedDict
import json
from datetime import datetime, timedelta
from meta.sockets import Channel
from modules.profiles.profiles.profiles import ProfilesRegistry
from . import logger
from .data import Hyperfocuser, HyperfocusData
ISOTimestamp: TypeAlias = str
class HyperfocusedPayload(TypedDict):
userid: str
user_name: str
started_at: ISOTimestamp
ends_at: ISOTimestamp
async def prepare_hyperfocuser(profiler: ProfilesRegistry, hyperfocuser: Hyperfocuser):
profile = await profiler.get_profile(hyperfocuser.profileid)
assert profile is not None
return HyperfocusedPayload(
userid=str(hyperfocuser.profileid),
user_name=profile.nickname or "Unknown",
started_at=hyperfocuser.started_at.isoformat(),
ends_at=hyperfocuser.ends_at.isoformat(),
)
class FocusChannel(Channel):
name = "HyperFocus"
def __init__(self, profiler: ProfilesRegistry, focusdata: HyperfocusData, **kwargs):
super().__init__(**kwargs)
self.profiler = profiler
self.focusdata = focusdata
# communityid -> listening websockets
self.communities = defaultdict(set)
async def on_connection(self, websocket, event):
if not (cidstr := event.get("community")):
raise ValueError("Hyperfocus browser missing communityid")
elif not cidstr.isdigit():
raise ValueError("Community id provided is not an integer")
cid = int(cidstr)
community = await self.profiler.get_community(cid)
if community is None:
raise ValueError("Unknown community provided")
await super().on_connection(websocket, event)
self.communities[cid].add(websocket)
focus_rows = await Hyperfocuser.fetch_where(started_in=cid)
await self.send_hyperfocus_put(cid, focus_rows)
async def del_connection(self, websocket):
for wss in self.communities.values():
wss.discard(websocket)
await super().del_connection(websocket)
async def send_hyperfocus_patch(
self, communityid: int, focuser: Hyperfocuser, websocket=None
):
for ws in (websocket,) if websocket else self.communities[communityid]:
await self.send_event(
{
"type": "DO",
"method": "patchFocus",
"args": await prepare_hyperfocuser(self.profiler, focuser),
},
websocket=ws,
)
async def send_hyperfocus_del(self, profileid: int, websocket=None):
await self.send_event(
{
"type": "DO",
"method": "delFocus",
"args": {"userid": profileid},
},
websocket=websocket,
)
async def send_hyperfocus_put(
self, communityid: int, focusers: list[Hyperfocuser], websocket=None
):
payload = []
for focuser in focusers:
fpl = await prepare_hyperfocuser(self.profiler, focuser)
payload.append(fpl)
for ws in (websocket,) if websocket else self.communities[communityid]:
await self.send_event(
{"type": "DO", "method": "putFocus", "args": payload},
websocket=ws,
)
async def send_event(self, event, **kwargs):
logger.info(f"Sending websocket event: {json.dumps(event, indent=1)}")
await super().send_event(event, **kwargs)