implement a functioning scheduler, get rid of threads
This commit is contained in:
		
							parent
							
								
									54be2516fe
								
							
						
					
					
						commit
						bee10a2e89
					
				
					 5 changed files with 44 additions and 89 deletions
				
			
		
							
								
								
									
										14
									
								
								pgbot
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								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__':
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								pgbotlib/cron.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								pgbotlib/cron.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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))
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue