Rough Campaign module skeleton.

This commit is contained in:
2026-07-22 18:42:08 +03:00
parent b8ffacd916
commit 67a04ef82f
10 changed files with 237 additions and 50 deletions
-15
View File
@@ -1,15 +0,0 @@
from typing import Optional
from .data import (
AwesomeData,
AwesomeTable,
)
class AwesomeRegistry:
VERSION = AwesomeData.VERSION
def __init__(self, data: AwesomeData):
self.data = data
async def init(self):
await self.data.init()
+16
View File
@@ -0,0 +1,16 @@
from typing import Optional
from .data import (
CampaignData,
Campaign,
EarnedReward,
)
class CampaignRegistry:
VERSION = CampaignData.VERSION
def __init__(self, data: CampaignData):
self.data = data
async def init(self):
await self.data.init()
+124
View File
@@ -0,0 +1,124 @@
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)
+40 -8
View File
@@ -2,16 +2,48 @@ from data import Registry, RowModel, Table
from data.columns import String, Timestamp, Integer, Bool
class AwesomeTable(RowModel):
_tablename_ = "awesome_table"
_cache_ = {}
class Campaign(RowModel):
_tablename_ = "campaigns"
# _cache_ = {}
campaign_id = Integer(primary=True)
communityid = Integer()
target_rewards = Integer()
campaign_name = String()
started_at = Timestamp()
completed_at = Timestamp()
created_at = Timestamp()
_timestamp = Timestamp()
class EarnedReward(RowModel):
_tablename_ = "campaign_rewards_earned"
# _cache_ = {}
earned_id = Integer(primary=True)
campaign_id = Integer()
profileid = Integer()
event_id = Integer()
twitch_user_id = String()
twitch_user_name = String()
fulfilled_at = Timestamp()
fulfilled_note = String()
earned_at = Timestamp()
earned_from = String()
modnote = String()
userid = String(primary=True)
_timestamp = Timestamp()
class AwesomeData(Registry):
VERSION = ("AWESOME", 1)
AwesomeTable = AwesomeTable
awesome_table = AwesomeTable.table
class CampaignData(Registry):
VERSION = ("CAMPAIGN", 1)
Campaign = Campaign
campaigns = Campaign.table
EarnedReward = EarnedReward
campaign_rewards_earned = EarnedReward.table
+2 -2
View File
@@ -2,6 +2,6 @@ from .. import logger
async def setup(bot):
from .cog import AwesomeCog
from .cog import CampaignCog
await bot.add_cog(AwesomeCog(bot))
await bot.add_cog(CampaignCog(bot))
+6 -6
View File
@@ -9,18 +9,18 @@ from meta import LionBot, LionCog, LionContext
from meta.logger import log_wrap
from utils.lib import utc_now
from ..data import AwesomeData
from ..awesome import AwesomeRegistry
from ..data import CampaignData
from ..campaigns import CampaignRegistry
class AwesomeCog(LionCog):
class CampaignCog(LionCog):
def __init__(self, bot: LionBot):
self.bot = bot
self.data = bot.db.load_registry(AwesomeData())
self.profiles = AwesomeRegistry(self.data)
self.data = bot.db.load_registry(CampaignData())
self.campaigns = CampaignRegistry(self.data)
async def cog_load(self):
await self.data.init()
await self.bot.version_check(*self.data.VERSION)
await self.profiles.init()
await self.campaigns.init()
+2 -2
View File
@@ -6,6 +6,6 @@ if TYPE_CHECKING:
async def setup(bot: "Bot"):
from .component import AwesomeComponent
from .component import CampaignComponent
await bot.add_component(AwesomeComponent(bot))
await bot.add_component(CampaignComponent(bot))
+6 -6
View File
@@ -10,22 +10,22 @@ from utils.lib import utc_now
from . import logger
from ..data import AwesomeData
from ..awesome import AwesomeRegistry
from ..data import CampaignData
from ..campaign import CampaignRegistry
class AwesomeComponent(cmds.Component):
class CampaignComponent(cmds.Component):
def __init__(self, bot: Bot):
self.bot = bot
self.data = bot.dbconn.load_registry(AwesomeData())
self.awesome = AwesomeRegistry(self.data)
self.data = bot.dbconn.load_registry(CampaignData())
self.campaigns = CampaignRegistry(self.data)
# ----- API -----
async def component_load(self):
await self.data.init()
await self.bot.version_check(*self.data.VERSION)
await self.profiles.init()
await self.campaigns.init()
async def component_teardown(self):
pass