From 77849a89e6d3dff320b1c42762d84fecc75c896c Mon Sep 17 00:00:00 2001 From: Frisk Date: Wed, 15 Jun 2022 19:32:38 +0200 Subject: [PATCH] Added #152 --- docs/API spec.md | 1 + src/api/client.py | 36 ++++++++++++++++++++++++++++++++++-- src/discussions.py | 2 +- src/rcgcdw.py | 15 +++++---------- 4 files changed, 41 insertions(+), 13 deletions(-) diff --git a/docs/API spec.md b/docs/API spec.md index 0ce6278..66958d1 100644 --- a/docs/API spec.md +++ b/docs/API spec.md @@ -104,6 +104,7 @@ Client consists of the following methods: - `make_api_request(params: Union[str, OrderedDict], *json_path: str, timeout: int = 10, allow_redirects: bool = False)` - allows to make a request to the wiki with parameters specified in params argument, json_path additionally allows to provide a list of strings that will be iterated over and json path of the result of this iteration returned. Timeout in float (seconds) can be added to limit the time for response, allow_redirects can be set to disallow or allow redirects - `get_formatters()` - returns a dictionary of all formatters in format of `{'eventtype': func}` - `get_ipmapper()` - returns ip mapper which tracks edit counts of IP editors +- `schedule(function: Callable, *args, every: float, at: str, priority=5, **kwargs)` – schedules a periodic task that executes *function*. Either every or at should be defined. *every* is float amount of seconds every which tasks should be ran, *at* should be HH:MM formatted time at which task should be ran. Function returns sched event, but only for first execution. ### Context **Path**: `src.api.context.Context` diff --git a/src/api/client.py b/src/api/client.py index caf5723..e8e18c7 100644 --- a/src/api/client.py +++ b/src/api/client.py @@ -15,8 +15,9 @@ from __future__ import annotations -import src.misc -from typing import Union +from datetime import datetime +import src.misc, sched +from typing import Union, Callable from collections import OrderedDict from typing import TYPE_CHECKING, Optional @@ -37,8 +38,39 @@ class Client: self.content_parser = src.misc.ContentParser self.tags = self.__recent_changes.tags self.LinkParser: type(src.misc.LinkParser) = src.misc.LinkParser + self.scheduler: sched.scheduler = sched.scheduler() #self.make_api_request: src.rc.wiki.__recent_changes.api_request = self.__recent_changes.api_request + def schedule(self, function: Callable, *args: list, every: Optional[float] = None, at: Optional[str] = None, + priority: int = 5, **kwargs: dict): + """Schedules a function indefinitely, does not execute function immediately + + Parameters: + + function (callable): a function to call each scheduled execution + *args: arguments provided to callable function + every (float): float of time between each execution + at (str): string of time + priority (int): priority of the task (lower - more important, RcGcDw tasks are executed at 5) + **kwargs: key-value provided to callable function + + Returns: + + sched.event + """ + def return_delay(given_time: Union[float, str]) -> float: + if isinstance(given_time, float) or isinstance(given_time, int): + return float(given_time) + now = datetime.utcnow() + then = datetime(now.year, now.month, now.day, *(map(int, given_time.split(':'))), 0, 0) + return float((then - now).seconds) + def wrap_reschedule(function, period: float, *args, **kwargs): + self.schedule(function, every=period, *args, **kwargs) + function(*args, **kwargs) + if not any([every, at]) or all([every, at]): + raise ValueError("Either every or at (and not both) has to be set for client.schedule function.") + return self.scheduler.enter(return_delay(every or at), priority, wrap_reschedule, argument=(function, every or 86400.0, *args), kwargs=kwargs) + def refresh_internal_data(self): """Refreshes internal storage data for wiki tags and MediaWiki messages.""" self.__recent_changes.init_info() diff --git a/src/discussions.py b/src/discussions.py index 7331b09..5a9bcc1 100644 --- a/src/discussions.py +++ b/src/discussions.py @@ -158,5 +158,5 @@ def safe_request(url) -> Optional[requests.Response]: return request -schedule.every(settings["fandom_discussions"]["cooldown"]).seconds.do(fetch_discussions) +client.schedule(fetch_discussions, every=settings["fandom_discussions"]["cooldown"]) diff --git a/src/rcgcdw.py b/src/rcgcdw.py index 091b484..86150ee 100644 --- a/src/rcgcdw.py +++ b/src/rcgcdw.py @@ -19,7 +19,7 @@ # WARNING! SHITTY CODE AHEAD. ENTER ONLY IF YOU ARE SURE YOU CAN TAKE IT # You have been warned -import time, logging.config, requests, datetime, math, os.path, schedule, sys, re, importlib +import time, logging.config, requests, datetime, math, os.path, sched, sys, re, importlib import src.misc import src.configloader @@ -316,21 +316,16 @@ time.sleep(3.0) # this timeout is to prevent timeouts. It seems Fandom does not if settings["rc_enabled"]: logger.info("Script started! Fetching newest changes...") wiki.fetch(amount=settings["limitrefetch"] if settings["limitrefetch"] != -1 else settings["limit"]) - schedule.every(settings["cooldown"]).seconds.do(wiki.fetch) + client.schedule(wiki.fetch, every=settings["cooldown"]) if settings["overview"]: try: overview_time = time.strptime(settings["overview_time"], '%H:%M') - schedule.every().day.at("{}:{}".format(str(overview_time.tm_hour).zfill(2), - str(overview_time.tm_min).zfill(2))).do(day_overview) + client.schedule(day_overview, at="{}:{}".format(str(overview_time.tm_hour).zfill(2), str(overview_time.tm_min).zfill(2))) del overview_time - except schedule.ScheduleValueError: - logger.error("Invalid time format! Currently: {}:{}".format( - time.strptime(settings["overview_time"], '%H:%M').tm_hour, - time.strptime(settings["overview_time"], '%H:%M').tm_min)) except ValueError: logger.error("Invalid time format! Currentely: {}. Note: It needs to be in HH:MM format.".format( settings["overview_time"])) - schedule.every().day.at("00:00").do(wiki.clear_cache) + client.schedule(wiki.clear_cache, at="00:00") else: logger.info("Script started! RC is disabled however, this means no recent changes will be sent :c") @@ -349,4 +344,4 @@ if TESTING: while 1: time.sleep(1.0) - schedule.run_pending() + client.scheduler.run()