from typing import Optional, TypeAlias, TypedDict import json from collections import defaultdict from datetime import datetime, timedelta from dataclasses import dataclass from data.queries import JOINTYPE, ORDER from meta.sockets import Channel from utils.lib import utc_now from modules.profiles.profiles.profiles import ProfilesRegistry from . import logger from .data import ( Campaign, CampaignData, EarnedReward, ) from .campaign import CampaignRegistry # ISO formatted timestamp ISOTimestamp: TypeAlias = str async def prepare_campaign( profiler: ProfilesRegistry, campaign: Campaign ): return {} class CampaignChannel(Channel): name = "PlusCampaign" def __init__( self, profiler: ProfilesRegistry, campaigns: CampaignRegistry, **kwargs ): super().__init__(**kwargs) self.profiler: ProfilesRegistry = profiler self.campaigns: CampaignRegistry = campaigns # Map of communities to webhooks listening for this community self.communities = defaultdict( set ) # Map of communityid -> listening websockets async def on_connection(self, websocket, event): if not (cidstr := event.get("community")): logger.warning("Campaign connection missing communityid") await super().on_connection(websocket, event) await self.send_sample(websocket=websocket) return 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) # TODO: Prepare campaign for sending if campaign: payload = await prepare_campaign(self.profiler, campaign) await self.send_campaign_update(cid, payload, websocket) else: await self.send_no_campaign(cid, websocket) async def send_sample(self, websocket): import json import random with open("sample-payload.json") as f: payload = json.load(f) ending = utc_now() + timedelta(seconds=10) payload['args']['end_at'] = ending.isoformat() await self.send_event(payload, websocket=websocket) async def del_connection(self, websocket): for wss in self.communities.values(): wss.discard(websocket) await super().del_connection(websocket) async def send_campaign_update( self, communityid: int, payload, websocket=None ): for ws in (websocket,) if websocket else self.communities[communityid]: await self.send_event( { "type": "DO", "method": "setTimer", "args": payload, }, websocket=ws, ) async def send_campaign_ended( self, communityid: int, payload, websocket=None ): for ws in (websocket,) if websocket else self.communities[communityid]: await self.send_event( { "type": "DO", "method": "endTimer", "args": payload, }, websocket=ws, ) async def send_no_campaign(self, communityid: int, websocket=None): for ws in (websocket,) if websocket else self.communities[communityid]: await self.send_event( { "type": "DO", "method": "noTimer", "args": {}, }, 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)