From bee10a2e8965774b71dd02c6db81c087dcb63812 Mon Sep 17 00:00:00 2001 From: Von Random Date: Sun, 5 Nov 2023 01:01:33 +0000 Subject: [PATCH] implement a functioning scheduler, get rid of threads --- pgbot | 14 ++++----- pgbotlib/cron.py | 32 ++++++++++++++++++++ pgbotlib/response.py | 4 +-- pgbotlib/sched.py | 70 -------------------------------------------- sched.dist.yml | 13 +++----- 5 files changed, 44 insertions(+), 89 deletions(-) create mode 100644 pgbotlib/cron.py delete mode 100644 pgbotlib/sched.py diff --git a/pgbot b/pgbot index 67cd595..7f0774c 100755 --- a/pgbot +++ b/pgbot @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import asyncio import sys import threading @@ -8,9 +9,9 @@ import yaml import pgbotlib.dbstuff import pgbotlib.commands +import pgbotlib.cron import pgbotlib.misc import pgbotlib.response -import pgbotlib.sched def init(args: list) -> tuple: @@ -38,12 +39,6 @@ def main(): commander = pgbotlib.commands.Commander(config, client, config['admins'], db_conn, namegen, responder) - sched_thread = threading.Thread( - target=pgbotlib.sched.spawn_scheduler, - args=(config, client, responder), - daemon=True) - sched_thread.start() - @client.on(telethon.events.NewMessage()) async def handle_new_message(event): if event.message.text.startswith('/'): @@ -51,7 +46,10 @@ def main(): else: await responder.respond(event) - client.run_until_disconnected() + cron = pgbotlib.cron.Cron(config, client, responder) + cron.plan() + loop = asyncio.get_event_loop() + loop.run_forever() if __name__ == '__main__': diff --git a/pgbotlib/cron.py b/pgbotlib/cron.py new file mode 100644 index 0000000..f731731 --- /dev/null +++ b/pgbotlib/cron.py @@ -0,0 +1,32 @@ +import time +import random + +import yaml +import aiocron +import telethon +import pgbotlib.response + + +class Cron: + def __init__(self, + config: dict, + client: telethon.TelegramClient, + responder: pgbotlib.response.Responder) -> None: + with open(config['schedule'], 'r', encoding='utf-8') as data: + self.sched = yaml.safe_load(data.read()) + self.responder = responder + self.client = client + + def __mkjob(self, job: dict) -> callable: + tokens = frozenset(job['tokens'].split(',')) + async def send_message() -> None: + if 'rand' in job: + time.sleep(random.randint(0, job['rand']) * 60) + message = self.responder.get_response(tokens) + message = self.responder.api_match(message, '') + await self.client.send_message(job['chat'], message) + return send_message + + def plan(self) -> None: + for job in self.sched: + aiocron.crontab(job['cron'], func=self.__mkjob(job)) diff --git a/pgbotlib/response.py b/pgbotlib/response.py index df0960b..a4914a8 100644 --- a/pgbotlib/response.py +++ b/pgbotlib/response.py @@ -35,7 +35,7 @@ class Responder: self.db_connection = db_connection self.client = client - def __tokenize(self, message: str) -> frozenset: + def tokenize(self, message: str) -> frozenset: tokens = set() for token, regexi in self.tokens: for regex in regexi: @@ -101,7 +101,7 @@ class Responder: if not self.enabled: return None message = event.message.text.lower() - tokens = self.__tokenize(message) + tokens = self.tokenize(message) response = self.get_response(tokens) if not response: return None diff --git a/pgbotlib/sched.py b/pgbotlib/sched.py deleted file mode 100644 index 9b3ada2..0000000 --- a/pgbotlib/sched.py +++ /dev/null @@ -1,70 +0,0 @@ -import asyncio -import time -import random - -import yaml -import schedule -import telethon -import pgbotlib.response - - -class Scheduler: - def __init__(self, - config: dict, - client: telethon.TelegramClient, - responder: pgbotlib.response.Responder) -> None: - self.responder = responder - self.client = client - with open(config['schedule'], 'r', encoding='utf-8') as data: - self.sched = yaml.safe_load(data.read()) - self.days = ( - schedule.every().day, - schedule.every().monday, - schedule.every().tuesday, - schedule.every().wednesday, - schedule.every().thursday, - schedule.every().friday, - schedule.every().saturday, - schedule.every().sunday - ) - - def __get_job(self, tokens: frozenset, - chat_id: int, rand: int) -> callable: - async def send_message(): - if rand: - time.sleep(random.randint(0, rand) * 60) - message = self.responder.get_response(tokens) - message = self.responder.api_match(message, '') - await self.client.send_message(chat_id, message) - - def job(): - loop = asyncio.get_event_loop() - coroutine = send_message() - loop.run_until_complete(coroutine) - return job - - def __schedule_job(self, tokens: str, chat: int, - day: int, t: str, rand: int) -> None: - job_tokens = frozenset(tokens.split(',')) - job = self.__get_job(job_tokens, chat, rand) - self.days[day].at(t).do(job) - - def build(self) -> None: - for i in self.sched: - for day in i.get('days', [0]): - for timespec in i['time']: - self.__schedule_job(i['tokens'], i['chat'], - day, timespec, i.get('rand', 0)) - - def run(self) -> None: - while True: - schedule.run_pending() - time.sleep(1) - - -def spawn_scheduler(config: dict, client: telethon.TelegramClient, - responder: pgbotlib.response.Responder) -> Scheduler: - asyncio.set_event_loop(asyncio.new_event_loop()) - scheduler = Scheduler(config, client, responder) - scheduler.build() - scheduler.run() diff --git a/sched.dist.yml b/sched.dist.yml index 997d0d5..f39ba36 100644 --- a/sched.dist.yml +++ b/sched.dist.yml @@ -1,15 +1,10 @@ # schedule things here, see examples - tokens: botname,praise - chat: 00000000 - days: [1, 5] - time: - - "19:59" + cron: 59 19 * * 1-5 rand: 5 + chat: 00000000 - tokens: greeting - chat: 00000000 - days: [1, 2, 3] - time: - - "13:05" - - "13:10" + cron: 5,10 13 * * 1-3 rand: 3 + chat: 00000000