This commit is contained in:
dece 2023-08-24 00:27:56 +02:00
parent c6326d5ee0
commit 7c030b771d
3 changed files with 594 additions and 359 deletions

View file

@ -19,3 +19,4 @@ scaruffi = "==0.0.3"
wolframalpha = "*"
meteofrance-api = "~=1.0.2"
openai = "~=0.25.0"
apscheduler = "~=3.9.0"

917
Pipfile.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
import asyncio
import importlib
import json
import os
@ -9,13 +10,15 @@ from pathlib import Path
from typing import Any, Iterable, Optional
import irc.client
import irc.client_aio
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from irc.client import Connection, Event, NickMask
from edmond.log import Logger
from edmond.plugin import Plugin
class Bot(irc.client.SimpleIRCClient, Logger):
class Bot(irc.client_aio.AioSimpleIRCClient, Logger):
"""Main class for the IRC bot: handles connection and manages plugins."""
CHANNELS_RUNTIME_KEY = "_channels"
@ -27,7 +30,9 @@ class Bot(irc.client.SimpleIRCClient, Logger):
self.plugins: list[Plugin] = []
self.values: dict[str, Any] = {}
self.storage: dict[str, Any] = self.get_storage()
self.tasks: list[asyncio.Task] = []
self.done: bool = False
self.scheduler = AsyncIOScheduler()
@property
def nick(self) -> str:
@ -72,6 +77,11 @@ class Bot(irc.client.SimpleIRCClient, Logger):
except OSError as exc:
self.log_e(f"Could not save storage file: {exc}")
def handle_task(self, coro):
"""Schedule a task in the event loop. Keep a reference to cancel it."""
task = self.connection.reactor.loop.create_task(coro)
self.tasks.append(task)
def on_welcome(self, connection: Connection, event: Event):
"""Handle a successful connection to a server."""
self.log_i(f"Connected to server {event.source}.")
@ -84,8 +94,14 @@ class Bot(irc.client.SimpleIRCClient, Logger):
if event.source.nick == self.nick:
self.log_i(f"Joined {event.target}.")
self.channels.append(event.target)
self.scheduler.add_job(self.flubiz, 'cron', hour='1',
minute='52')
self.scheduler.start()
self.run_plugin_callbacks(event)
async def flubiz(self):
self.say('#idi0crates', "acab")
def on_part(self, connection: Connection, event: Event):
"""Handle someone, possibly the bot, leaving a channel."""
if event.source.nick == self.nick:
@ -118,11 +134,14 @@ class Bot(irc.client.SimpleIRCClient, Logger):
"""Connect the bot to server, join channels and start responding."""
self.log_i("Starting Edmond.")
self.load_plugins()
self.log_i("Connecting to server.")
self.connect(self.config["host"], self.config["port"], self.nick)
self.log_i("Connecting to server")
signal.signal(signal.SIGTERM, self.handle_sigterm)
try:
self.connect(self.config["host"], self.config["port"], self.nick)
self.start()
except irc.client.ServerConnectionError as exc:
self.log_c(f"Connection failed: {exc}")
except KeyboardInterrupt:
self.log_i("Caught keyboard interrupt.")
except Exception as exc:
@ -135,7 +154,7 @@ class Bot(irc.client.SimpleIRCClient, Logger):
def load_plugins(self):
"""Load all installed plugins."""
self.log_i("Loading plugins.")
self.log_i("Loading plugins")
plugin_files = os.listdir(Path(__file__).parent / "plugins")
plugin_names = map(
lambda f: os.path.splitext(f)[0],
@ -199,7 +218,13 @@ class Bot(irc.client.SimpleIRCClient, Logger):
if self.done:
return
self.log_i("Stopping Edmond.")
self.save_storage()
self.save_storage() # FIRST THINGS FIRST
for task in self.tasks:
if not task.cancelled():
self.log_d(f"Cancelling task {task.get_name()}")
task.cancel()
if self.connection.is_connected():
self.connection.close()
self.reactor.loop.close()
self.done = True