Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import asyncio
- from datetime import datetime, timedelta
- import os
- from ncogs.Utils import Utils as utils
- import yaml
- import threading
- import sqlite3
- from ncogs.Utils import Utils
- from discord import app_commands
- from discord.ext import commands
- from typing import NoReturn
- class Scheduler:
- @classmethod
- def classm(cls, guild_id) -> 'Scheduler':
- return cls(guild_id)
- def __init__(self, guild_id: int) -> NoReturn:
- self.tasks = {}
- self.running = False
- self.server_name = Utils.get_server_name(guild_id)
- self.conn = sqlite3.connect(f'{self.server_name}/{Utils.shorten_server_name(guild_id)}.db')
- self.cursor = self.conn.cursor()
- self.cursor.execute("""CREATE TABLE IF NOT EXISTS tasks (name TEXT, func_name TEXT, interval INTEGER, last_run TEXT, next_run TEXT)""")
- self.guild_id = guild_id
- #self.schedulers = {}
- @staticmethod
- def get_scheduler(guild_id):
- print("Getting the Scheduler")
- return Scheduler.classm(guild_id).tasks.get(guild_id)
- @staticmethod
- def set_scheduler(guild_id, scheduler):
- print("Setting the Scheduler")
- Scheduler.classm(guild_id).tasks[guild_id] = scheduler
- @staticmethod
- async def load_tasks(guild_id):
- with sqlite3.connect(f"{Utils.get_server_name(guild_id)}/{Utils.shorten_server_name(guild_id)}.db") as conn:
- cursor = conn.cursor()
- cursor.execute("SELECT * FROM tasks")
- rows = cursor.fetchall()
- if len(rows) == 0:
- print(f"No tasks found for guild_id {guild_id}")
- loaded_tasks = []
- for row in rows:
- name, func_name, interval, last_run, next_run = row
- task = {
- 'name': name,
- 'func': func_name,
- 'interval': interval,
- 'last_run': datetime.fromisoformat(last_run),
- 'next_run': datetime.fromisoformat(next_run)
- }
- Scheduler.classm(guild_id).tasks = task
- loaded_tasks.append(task)
- print("Loading Scheduler tasks")
- print(f"Loaded {len(rows)} tasks")
- #Scheduler.classm(guild_id).conn.close()
- print(f"Loaded tasks: {loaded_tasks}")
- return loaded_tasks
- @staticmethod
- async def save_task(guild_id, name, func_name, interval, last_run, next_run):
- with sqlite3.connect(f"{Utils.get_server_name(guild_id)}/{Utils.shorten_server_name(guild_id)}.db") as conn:
- try:
- cursor = conn.cursor()
- cursor.execute("INSERT OR IGNORE INTO tasks (name, func_name, interval, last_run, next_run) VALUES (?, ?, ?, ?, ?)",
- (name, func_name, interval, last_run, next_run))
- conn.commit()
- print("Saving Scheduler tasks")
- except sqlite3.Error as e:
- raise e
- @staticmethod
- async def start(guild_id):
- print("Starting Scheduler")
- Scheduler.classm(guild_id).running = True
- print("Checking saved tasks")
- await Scheduler.classm(guild_id).check_tasks(guild_id)
- @staticmethod
- async def add_task(guild_id, name, func, interval, last_run, next_run):
- Scheduler.classm(guild_id).tasks[name] = {
- 'func': func,
- 'interval': interval,
- 'last_run': last_run,
- 'next_run': next_run
- }
- if Scheduler.classm(guild_id).running != True:
- await Scheduler.classm(guild_id).start(guild_id)
- print("Added tasks to Scheduler")
- await Scheduler.classm(guild_id).save_task(guild_id, name, func, interval, last_run, next_run)
- @staticmethod
- async def backup_database(guild_id, backup_type):
- ServerName = await asyncio.to_thread(Utils.get_server_name, Scheduler.classm(guild_id).guild_id)
- BasePath = await asyncio.to_thread(Utils.server_folder, ServerName)
- SourceDatabasePath = await asyncio.to_thread(Utils.primary_database_folder, BasePath, ServerName)
- BackupsRoute = await asyncio.to_thread(Utils.backup_folder, BasePath, ServerName)
- if backup_type == "full":
- print("Running full backup")
- await Utils.full_backup(SourceDatabasePath, BackupsRoute)
- elif backup_type == 'differential':
- print("Running differential backup")
- await Utils.differential_backup(SourceDatabasePath, BackupsRoute)
- @staticmethod
- async def schedule_full_backup(guild_id, db_name):
- current_time = datetime.now()
- midnight = current_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
- Scheduler.classm(guild_id).tasks[f"full_backup_{db_name}"] = {
- 'func': lambda: Scheduler.classm(guild_id).backup_database(guild_id, 'full'),
- 'interval': 86400,
- 'last_run': current_time,
- 'next_run': midnight
- }
- print("Scheduling full backup task's next run time")
- await Scheduler.classm(guild_id).add_task(guild_id, f"full_backup_{db_name}", 'backup_database', 86400, current_time, midnight)
- @staticmethod
- async def schedule_differential_backup(guild_id, db_name):
- current_time = datetime.now()
- midnight = current_time.replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=1)
- Scheduler.classm(guild_id).tasks[f"differential_backup_{db_name}"] = {
- 'func': lambda: Scheduler.classm(guild_id).backup_database(guild_id, 'differential'),
- 'interval': 86400,
- 'last_run': current_time,
- 'next_run': midnight
- }
- print("Scheduling differential backup task's next run time")
- await Scheduler.classm(guild_id).add_task(guild_id, f"differential_backup_{db_name}", 'backup_database', 86400, current_time, midnight)
- @staticmethod
- async def check_tasks(guild_id):
- while Scheduler.classm(guild_id).running == True:
- Scheduler.classm(guild_id).load_tasks(guild_id)
- current_time = datetime.now()
- for name, task in Scheduler.classm(guild_id).tasks.items():
- if current_time >= task['next_run']:
- if name.startswith('full_backup_'):
- await task['func']()
- task['last_run'] = current_time
- task['next_run'] = current_time + timedelta(seconds=task['interval'])
- print("Check if any full backups should be run. Run them, and save the next run time")
- await Scheduler.classm(guild_id).save_task(guild_id, name, 'backup_database', task['interval'], task['last_run'], task['next_run'])
- elif name.startswith('differential_backup_'):
- db_name = name.split('_')[2]
- full_backup_task = Scheduler.classm(guild_id).tasks.get(f"full_backup_{db_name}")
- if full_backup_task and full_backup_task['next_run'] - current_time < timedelta(hours=1):
- task['next_run'] = current_time + timedelta(hours=1)
- print("Check if any differential backups should be run. If it would conflict with a full backup, update the next run time")
- await Scheduler.classm(guild_id).save_task(guild_id, name, 'backup_database', task['interval'], task['last_run'], task['next_run'])
- else:
- await task['func']()
- task['last_run'] = current_time
- task['next_run'] = current_time + timedelta(seconds=task['interval'])
- 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")
- await Scheduler.classm(guild_id).save_task(guild_id, name, 'backup_database', task['interval'], task['last_run'], task['next_run'])
- await asyncio.sleep(3600)
- @staticmethod
- def stop(guild_id):
- Scheduler.classm(guild_id).running = False
- Scheduler.classm(guild_id).conn.close()
- print("Stop the Scheduler and close the database connection")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement