Initial merger with Twitch interface.

This commit is contained in:
2024-08-27 17:41:33 +10:00
parent 7e6dcb006f
commit d10fd2fc1d
28 changed files with 1309 additions and 40 deletions

32
src/meta/CrocBot.py Normal file
View File

@@ -0,0 +1,32 @@
from typing import TYPE_CHECKING
import logging
from twitchio.ext import commands
from twitchio.ext import pubsub
from data import Database
from .config import Conf
if TYPE_CHECKING:
from .LionBot import LionBot
logger = logging.getLogger(__name__)
class CrocBot(commands.Bot):
def __init__(self, *args,
config: Conf,
data: Database,
lionbot: 'LionBot', **kwargs):
super().__init__(*args, **kwargs)
self.config = config
self.data = data
self.pubsub = pubsub.PubSubPool(self)
self.lionbot = lionbot
async def event_ready(self):
logger.info(f"Logged in as {self.nick}. User id is {self.user_id}")

View File

@@ -56,7 +56,9 @@ class LionBot(Bot):
def __init__(
self, *args, appname: str, shardname: str, db: Database, config: Conf, translator: LeoBabel,
initial_extensions: List[str], web_client: ClientSession, app_ipc,
testing_guilds: List[int] = [], **kwargs
testing_guilds: List[int] = [],
system_monitor: Optional[SystemMonitor] = None,
**kwargs
):
kwargs.setdefault('tree_cls', LionTree)
super().__init__(*args, **kwargs)
@@ -71,7 +73,7 @@ class LionBot(Bot):
self.app_ipc = app_ipc
self.translator = translator
self.system_monitor = SystemMonitor()
self.system_monitor = system_monitor or SystemMonitor()
self.monitor = ComponentMonitor('LionBot', self._monitor_status)
self.system_monitor.add_component(self.monitor)

View File

@@ -3,6 +3,8 @@ from .LionCog import LionCog
from .LionContext import LionContext
from .LionTree import LionTree
from .CrocBot import CrocBot
from .logger import logging_context, log_wrap, log_action_stack, log_context, log_app
from .config import conf, configEmoji
from .args import args
@@ -10,6 +12,7 @@ from .app import appname, shard_talk, appname_from_shard, shard_from_appname
from .errors import HandledException, UserInputError, ResponseTimedOut, SafeCancellation, UserCancelled
from .context import context, ctx_bot
from . import sockets
from . import sharding
from . import logger
from . import app

68
src/meta/sockets.py Normal file
View File

@@ -0,0 +1,68 @@
from abc import ABC
from collections import defaultdict
import json
from typing import Any
import logging
import websockets
logger = logging.getLogger(__name__)
class Channel(ABC):
"""
A channel is a stateful connection handler for a group of connected websockets.
"""
name = "Root Channel"
def __init__(self, **kwargs):
self.connections = set()
@property
def empty(self):
return not self.connections
async def on_connection(self, websocket: websockets.WebSocketServerProtocol, event: dict[str, Any]):
logger.info(f"Channel '{self.name}' attached new connection {websocket=} {event=}")
self.connections.add(websocket)
async def del_connection(self, websocket: websockets.WebSocketServerProtocol):
logger.info(f"Channel '{self.name}' dropped connection {websocket=}")
self.connections.discard(websocket)
async def handle_message(self, websocket: websockets.WebSocketServerProtocol, message):
raise NotImplementedError
async def send_event(self, event, websocket=None):
message = json.dumps(event)
if not websocket:
for ws in self.connections:
await ws.send(message)
else:
await websocket.send(message)
channels = {}
def register_channel(name, channel: Channel):
channels[name] = channel
async def root_handler(websocket: websockets.WebSocketServerProtocol):
message = await websocket.recv()
event = json.loads(message)
if event.get('type', None) != 'init':
raise ValueError("Received Websocket connection with no init.")
if (channel_name := event.get('channel', None)) not in channels:
raise ValueError(f"Received Init for unhandled channel {channel_name=}")
channel = channels[channel_name]
try:
await channel.on_connection(websocket, event)
async for message in websocket:
await channel.handle_message(websocket, message)
finally:
await channel.del_connection(websocket)