More development, improvements in neglected areas

This commit is contained in:
Frisk 2022-08-09 16:08:30 +02:00
parent 5ca43bfe26
commit ef3dddfb0c
No known key found for this signature in database
GPG key ID: 213F7C15068AF8AC
5 changed files with 48 additions and 8 deletions

View file

@ -6,6 +6,8 @@ from src.config import settings
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from functools import cache from functools import cache
from src.discussions import Discussions from src.discussions import Discussions
from statistics import Log, LogType
logger = logging.getLogger("rcgcdb.domain") logger = logging.getLogger("rcgcdb.domain")
if TYPE_CHECKING: if TYPE_CHECKING:
@ -21,7 +23,7 @@ class Domain:
self.wikis: OrderedDict[str, src.wiki.Wiki] = OrderedDict() self.wikis: OrderedDict[str, src.wiki.Wiki] = OrderedDict()
self.rate_limiter: src.wiki_ratelimiter = src.wiki_ratelimiter.RateLimiter() self.rate_limiter: src.wiki_ratelimiter = src.wiki_ratelimiter.RateLimiter()
self.irc: Optional[src.irc_feed.AioIRCCat] = None self.irc: Optional[src.irc_feed.AioIRCCat] = None
self.discussions_handler: Optional[Discussions] = None self.discussions_handler: Optional[Discussions] = Discussions(self.wikis) if name == "fandom.com" else None
def __iter__(self): def __iter__(self):
return iter(self.wikis) return iter(self.wikis)
@ -32,6 +34,14 @@ class Domain:
def __len__(self): def __len__(self):
return len(self.wikis) return len(self.wikis)
def destroy(self):
if self.irc:
self.irc.connection.disconnect("Leaving")
if self.discussions_handler:
self.discussions_handler.close()
if self.task:
self.task.cancel()
def get_wiki(self, item, default=None) -> Optional[src.wiki.Wiki]: def get_wiki(self, item, default=None) -> Optional[src.wiki.Wiki]:
return self.wikis.get(item, default) return self.wikis.get(item, default)
@ -64,9 +74,10 @@ class Domain:
if first: if first:
self.wikis.move_to_end(wiki.script_url, last=False) self.wikis.move_to_end(wiki.script_url, last=False)
async def run_wiki_scan(self, wiki: src.wiki.Wiki): async def run_wiki_scan(self, wiki: src.wiki.Wiki, reason: Optional[int] = None):
await self.rate_limiter.timeout_wait() await self.rate_limiter.timeout_wait()
await wiki.scan() await wiki.scan()
wiki.statistics.update(Log(type=LogType.SCAN_REASON, title=str(reason)))
self.wikis.move_to_end(wiki.script_url) self.wikis.move_to_end(wiki.script_url)
self.rate_limiter.timeout_add(1.0) self.rate_limiter.timeout_add(1.0)

View file

@ -50,6 +50,10 @@ class DomainManager:
new_domain = await self.new_domain(wiki_domain) new_domain = await self.new_domain(wiki_domain)
new_domain.add_wiki(wiki) new_domain.add_wiki(wiki)
def remove_domain(self, domain):
domain.destoy()
del self.domains[domain]
def remove_wiki(self, script_url: str): def remove_wiki(self, script_url: str):
wiki_domain = self.get_domain(script_url) wiki_domain = self.get_domain(script_url)
try: try:
@ -58,6 +62,8 @@ class DomainManager:
raise NoDomain raise NoDomain
else: else:
domain.remove_wiki(script_url) domain.remove_wiki(script_url)
if len(domain) == 0:
self.remove_domain(domain)
@staticmethod @staticmethod
def get_domain(url: str) -> str: def get_domain(url: str) -> str:

View file

@ -2,7 +2,9 @@ class WikiError(Exception):
pass pass
class WikiServerError(Exception): class WikiServerError(Exception):
pass def __init__(self, exception: BaseException):
self.exception = exception
class WikiNotFoundError(Exception): class WikiNotFoundError(Exception):
pass pass

View file

@ -12,6 +12,7 @@ class LogType(Enum):
HTTP_ERROR: 2 HTTP_ERROR: 2
MEDIAWIKI_ERROR: 3 MEDIAWIKI_ERROR: 3
VALUE_UPDATE: 4 VALUE_UPDATE: 4
SCAN_REASON: 5
queue_limit = settings.get("queue_limit", 30) queue_limit = settings.get("queue_limit", 30)
@ -40,10 +41,23 @@ class Statistics:
self.last_action: Optional[int] = rc_id self.last_action: Optional[int] = rc_id
self.last_checked_discussion: Optional[int] = None self.last_checked_discussion: Optional[int] = None
self.last_post: Optional[int] = discussion_id self.last_post: Optional[int] = discussion_id
self.logs: LimitedList = LimitedList() self.logs: LimitedList[Log] = LimitedList()
def update(self, *args: Log, **kwargs: dict[str, Union[float, int]]): def update(self, *args: Log, **kwargs: dict[str, Union[float, int]]):
for key, value in kwargs: for key, value in kwargs:
self.__setattr__(key, value) self.__setattr__(key, value)
for log in args: for log in args:
self.logs.append(log) self.logs.append(log)
def filter_by_time(self, time_ago: int, logs: list = None): # cannot have self.logs in here as this is evaluated once
"""Returns logs with time between time_ago seconds ago and now"""
time_limit = int(time.time()) - time_ago
return [x for x in (self.logs if logs is None else logs) if x.time > time_limit]
def filter_by_type(self, log_type: LogType, logs: list = None):
"""Returns logs with same type as in log_type"""
return [x for x in (self.logs if logs is None else logs) if x.type == log_type]
def recent_connection_errors(self) -> int:
"""Count how many connection errors there were recently (2 minutes)"""
return len(self.filter_by_type(LogType.CONNECTION_ERROR, logs=self.filter_by_time(120))) # find connection errors from 2 minutes ago

View file

@ -194,18 +194,25 @@ class Wiki:
"rclimit": amount, "rctype": "edit|new|log|categorize", "siprop": "namespaces|general"}) "rclimit": amount, "rctype": "edit|new|log|categorize", "siprop": "namespaces|general"})
try: try:
response = await self.api_request(params=params) response = await self.api_request(params=params)
except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError, asyncio.TimeoutError): except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError, asyncio.TimeoutError) as e:
logger.error("A connection error occurred while requesting {}".format(params)) logger.error("A connection error occurred while requesting {}".format(params))
raise WikiServerError raise WikiServerError(e)
return response return response
async def scan(self, amount=10): async def scan(self, amount=10):
"""Fetches recent changes of a wiki
:raises WikiServerError
"""
while True: # Trap event in case there are more changes needed to be fetched while True: # Trap event in case there are more changes needed to be fetched
try: try:
request = await self.fetch_wiki(amount=amount) request = await self.fetch_wiki(amount=amount)
self.client.last_request = request self.client.last_request = request
except WikiServerError as e: except WikiServerError as e:
self.statistics.update(Log(type=LogType.CONNECTION_ERROR, title=e.)) # We need more details in WIkiServerError exception self.statistics.update(Log(type=LogType.CONNECTION_ERROR, title=str(e.exception)))
if self.statistics.recent_connection_errors() > 1:
raise
await asyncio.sleep(2.0)
if not self.mw_messages: if not self.mw_messages:
# TODO Split into other function # TODO Split into other function
mw_messages = request.get("query", {}).get("allmessages", []) mw_messages = request.get("query", {}).get("allmessages", [])