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
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import threading
 | 
					import threading
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,9 +9,9 @@ import yaml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pgbotlib.dbstuff
 | 
					import pgbotlib.dbstuff
 | 
				
			||||||
import pgbotlib.commands
 | 
					import pgbotlib.commands
 | 
				
			||||||
 | 
					import pgbotlib.cron
 | 
				
			||||||
import pgbotlib.misc
 | 
					import pgbotlib.misc
 | 
				
			||||||
import pgbotlib.response
 | 
					import pgbotlib.response
 | 
				
			||||||
import pgbotlib.sched
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def init(args: list) -> tuple:
 | 
					def init(args: list) -> tuple:
 | 
				
			||||||
| 
						 | 
					@ -38,12 +39,6 @@ def main():
 | 
				
			||||||
    commander = pgbotlib.commands.Commander(config, client, config['admins'],
 | 
					    commander = pgbotlib.commands.Commander(config, client, config['admins'],
 | 
				
			||||||
                                            db_conn, namegen, responder)
 | 
					                                            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())
 | 
					    @client.on(telethon.events.NewMessage())
 | 
				
			||||||
    async def handle_new_message(event):
 | 
					    async def handle_new_message(event):
 | 
				
			||||||
        if event.message.text.startswith('/'):
 | 
					        if event.message.text.startswith('/'):
 | 
				
			||||||
| 
						 | 
					@ -51,7 +46,10 @@ def main():
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            await responder.respond(event)
 | 
					            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__':
 | 
					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.db_connection = db_connection
 | 
				
			||||||
        self.client = client
 | 
					        self.client = client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __tokenize(self, message: str) -> frozenset:
 | 
					    def tokenize(self, message: str) -> frozenset:
 | 
				
			||||||
        tokens = set()
 | 
					        tokens = set()
 | 
				
			||||||
        for token, regexi in self.tokens:
 | 
					        for token, regexi in self.tokens:
 | 
				
			||||||
            for regex in regexi:
 | 
					            for regex in regexi:
 | 
				
			||||||
| 
						 | 
					@ -101,7 +101,7 @@ class Responder:
 | 
				
			||||||
        if not self.enabled:
 | 
					        if not self.enabled:
 | 
				
			||||||
            return None
 | 
					            return None
 | 
				
			||||||
        message = event.message.text.lower()
 | 
					        message = event.message.text.lower()
 | 
				
			||||||
        tokens = self.__tokenize(message)
 | 
					        tokens = self.tokenize(message)
 | 
				
			||||||
        response = self.get_response(tokens)
 | 
					        response = self.get_response(tokens)
 | 
				
			||||||
        if not response:
 | 
					        if not response:
 | 
				
			||||||
            return None
 | 
					            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
 | 
					# schedule things here, see examples
 | 
				
			||||||
- tokens: botname,praise
 | 
					- tokens: botname,praise
 | 
				
			||||||
  chat: 00000000
 | 
					  cron: 59 19 * * 1-5
 | 
				
			||||||
  days: [1, 5]
 | 
					 | 
				
			||||||
  time:
 | 
					 | 
				
			||||||
    - "19:59"
 | 
					 | 
				
			||||||
  rand: 5
 | 
					  rand: 5
 | 
				
			||||||
 | 
					  chat: 00000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- tokens: greeting
 | 
					- tokens: greeting
 | 
				
			||||||
  chat: 00000000
 | 
					  cron: 5,10 13 * * 1-3
 | 
				
			||||||
  days: [1, 2, 3]
 | 
					 | 
				
			||||||
  time:
 | 
					 | 
				
			||||||
    - "13:05"
 | 
					 | 
				
			||||||
    - "13:10"
 | 
					 | 
				
			||||||
  rand: 3
 | 
					  rand: 3
 | 
				
			||||||
 | 
					  chat: 00000000
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue