Advertisement
LyndenSylvester

Untitled

Nov 21st, 2024
50
0
18 hours
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.33 KB | None | 0 0
  1. import asyncio
  2. from datetime import datetime, timedelta
  3. import os
  4. from ncogs.Utils import Utils as utils
  5. import yaml
  6. import threading
  7. import sqlite3
  8. from ncogs.Utils import Utils
  9. from discord import app_commands
  10. from discord.ext import commands
  11. from typing import NoReturn
  12.  
  13. class Scheduler:
  14.  
  15.     @classmethod
  16.     def classm(cls, guild_id) -> 'Scheduler':
  17.         return cls(guild_id)
  18.  
  19.     def __init__(self, guild_id: int) -> NoReturn:
  20.         self.tasks = {}
  21.         self.running = False
  22.         self.server_name = Utils.get_server_name(guild_id)
  23.         self.conn = sqlite3.connect(f'{self.server_name}/{Utils.shorten_server_name(guild_id)}.db')
  24.         self.cursor = self.conn.cursor()
  25.         self.cursor.execute("""CREATE TABLE IF NOT EXISTS tasks (name TEXT, func_name TEXT, interval INTEGER, last_run TEXT, next_run TEXT)""")
  26.         self.guild_id = guild_id
  27.         #self.schedulers = {}
  28.  
  29.     @staticmethod
  30.     def get_scheduler(guild_id):
  31.         print("Getting the Scheduler")
  32.         return Scheduler.classm(guild_id).tasks.get(guild_id)
  33.  
  34.     @staticmethod
  35.     def set_scheduler(guild_id, scheduler):
  36.         print("Setting the Scheduler")
  37.         Scheduler.classm(guild_id).tasks[guild_id] = scheduler
  38.  
  39.     @staticmethod
  40.     async def load_tasks(guild_id):
  41.         with sqlite3.connect(f"{Utils.get_server_name(guild_id)}/{Utils.shorten_server_name(guild_id)}.db") as conn:
  42.             cursor = conn.cursor()
  43.             cursor.execute("SELECT * FROM tasks")
  44.             rows = cursor.fetchall()
  45.  
  46.             if len(rows) == 0:
  47.                 print(f"No tasks found for guild_id {guild_id}")
  48.             loaded_tasks = []
  49.             for row in rows:
  50.                 name, func_name, interval, last_run, next_run = row
  51.                 task = {
  52.                     'name': name,
  53.                     'func': func_name,
  54.                     'interval': interval,
  55.                     'last_run': datetime.fromisoformat(last_run),
  56.                     'next_run': datetime.fromisoformat(next_run)
  57.                 }
  58.                 Scheduler.classm(guild_id).tasks = task
  59.                 loaded_tasks.append(task)
  60.             print("Loading Scheduler tasks")
  61.             print(f"Loaded {len(rows)} tasks")
  62.         #Scheduler.classm(guild_id).conn.close()
  63.         print(f"Loaded tasks: {loaded_tasks}")
  64.         return loaded_tasks
  65.  
  66.  
  67.     @staticmethod
  68.     async def save_task(guild_id, name, func_name, interval, last_run, next_run):
  69.         with sqlite3.connect(f"{Utils.get_server_name(guild_id)}/{Utils.shorten_server_name(guild_id)}.db") as conn:
  70.             try:
  71.                 cursor = conn.cursor()
  72.                 cursor.execute("INSERT OR IGNORE INTO tasks (name, func_name, interval, last_run, next_run) VALUES (?, ?, ?, ?, ?)",
  73.                                 (name, func_name, interval, last_run, next_run))
  74.                 conn.commit()
  75.                 print("Saving Scheduler tasks")
  76.             except sqlite3.Error as e:
  77.                 raise e
  78.  
  79.     @staticmethod
  80.     async def start(guild_id):
  81.         print("Starting Scheduler")
  82.         Scheduler.classm(guild_id).running = True
  83.         print("Checking saved tasks")
  84.         await Scheduler.classm(guild_id).check_tasks(guild_id)
  85.  
  86.     @staticmethod
  87.     async def add_task(guild_id, name, func, interval, last_run, next_run):
  88.         Scheduler.classm(guild_id).tasks[name] = {
  89.             'func': func,
  90.             'interval': interval,
  91.             'last_run': last_run,
  92.             'next_run': next_run
  93.         }
  94.         if Scheduler.classm(guild_id).running != True:
  95.             await Scheduler.classm(guild_id).start(guild_id)
  96.         print("Added tasks to Scheduler")
  97.         await Scheduler.classm(guild_id).save_task(guild_id, name, func, interval, last_run, next_run)
  98.        
  99.  
  100.     @staticmethod
  101.     async def backup_database(guild_id, backup_type):
  102.         ServerName = await asyncio.to_thread(Utils.get_server_name, Scheduler.classm(guild_id).guild_id)
  103.         BasePath = await asyncio.to_thread(Utils.server_folder, ServerName)
  104.         SourceDatabasePath = await asyncio.to_thread(Utils.primary_database_folder, BasePath, ServerName)
  105.         BackupsRoute = await asyncio.to_thread(Utils.backup_folder, BasePath, ServerName)
  106.         if backup_type == "full":
  107.             print("Running full backup")
  108.             await Utils.full_backup(SourceDatabasePath, BackupsRoute)
  109.  
  110.         elif backup_type == 'differential':
  111.             print("Running differential backup")
  112.             await Utils.differential_backup(SourceDatabasePath, BackupsRoute)
  113.  
  114.     @staticmethod
  115.     async def schedule_full_backup(guild_id, db_name):
  116.         current_time = datetime.now()
  117.         midnight = current_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
  118.         Scheduler.classm(guild_id).tasks[f"full_backup_{db_name}"] = {
  119.             'func': lambda: Scheduler.classm(guild_id).backup_database(guild_id, 'full'),
  120.             'interval': 86400,
  121.             'last_run': current_time,
  122.             'next_run': midnight
  123.         }
  124.         print("Scheduling full backup task's next run time")
  125.         await Scheduler.classm(guild_id).add_task(guild_id, f"full_backup_{db_name}", 'backup_database', 86400, current_time, midnight)
  126.  
  127.     @staticmethod
  128.     async def schedule_differential_backup(guild_id, db_name):
  129.         current_time = datetime.now()
  130.         midnight = current_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
  131.         Scheduler.classm(guild_id).tasks[f"differential_backup_{db_name}"] = {
  132.             'func': lambda: Scheduler.classm(guild_id).backup_database(guild_id, 'differential'),
  133.             'interval': 86400,
  134.             'last_run': current_time,
  135.             'next_run': midnight
  136.         }
  137.         print("Scheduling differential backup task's next run time")
  138.         await Scheduler.classm(guild_id).add_task(guild_id, f"differential_backup_{db_name}", 'backup_database', 86400, current_time, midnight)
  139.  
  140.  
  141.     @staticmethod
  142.     async def check_tasks(guild_id):
  143.         while Scheduler.classm(guild_id).running == True:
  144.             Scheduler.classm(guild_id).load_tasks(guild_id)
  145.             current_time = datetime.now()
  146.             for name, task in Scheduler.classm(guild_id).tasks.items():
  147.                 if current_time >= task['next_run']:
  148.                     if name.startswith('full_backup_'):
  149.                         await task['func']()
  150.                         task['last_run'] = current_time
  151.                         task['next_run'] = current_time + timedelta(seconds=task['interval'])
  152.                         print("Check if any full backups should be run. Run them, and save the next run time")
  153.                         await Scheduler.classm(guild_id).save_task(guild_id, name, 'backup_database', task['interval'], task['last_run'], task['next_run'])
  154.                     elif name.startswith('differential_backup_'):
  155.                         db_name = name.split('_')[2]
  156.                         full_backup_task = Scheduler.classm(guild_id).tasks.get(f"full_backup_{db_name}")
  157.                         if full_backup_task and full_backup_task['next_run'] - current_time < timedelta(hours=1):
  158.                             task['next_run'] = current_time + timedelta(hours=1)
  159.                             print("Check if any differential backups should be run. If it would conflict with a full backup, update the next run time")
  160.                             await Scheduler.classm(guild_id).save_task(guild_id, name, 'backup_database', task['interval'], task['last_run'], task['next_run'])
  161.                         else:
  162.                             await task['func']()
  163.                             task['last_run'] = current_time
  164.                             task['next_run'] = current_time + timedelta(seconds=task['interval'])
  165.                             print("The differential backup does not conflict with a full backup, and the scheduled differential backup will be run. Run them, then save the next run time")
  166.                             await Scheduler.classm(guild_id).save_task(guild_id, name, 'backup_database', task['interval'], task['last_run'], task['next_run'])
  167.             await asyncio.sleep(3600)
  168.  
  169.     @staticmethod
  170.     def stop(guild_id):
  171.         Scheduler.classm(guild_id).running = False
  172.         Scheduler.classm(guild_id).conn.close()
  173.         print("Stop the Scheduler and close the database connection")
  174.  
  175.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement