misc-csechet/frontools/sources.py

60 lines
1.7 KiB
Python

"""Source for remote files"""
from abc import ABC, abstractmethod
from re import Pattern
from re import compile as re_compile
from aiohttp import ClientSession
from frontools.cache import Cache
class Source(ABC):
"""Base class for sources"""
@abstractmethod
async def get_url(self, url: str) -> bytes:
"""Retrieve the given url content"""
class CachedSource(Source):
"""Source loading urls from the internet."""
def __init__(self, cache: Cache[bytes]) -> None:
self._cache = cache
async def get_url(self, url: str) -> bytes:
"""Get a page content from the local or remote cache."""
return await self._cache.get(url, self._load_url)
@staticmethod
async def _load_url(url: str) -> bytes:
async with ClientSession() as session:
async with session.get(url) as response:
return await response.content.read()
class OverrideSource(Source):
"""Source overriding paths matching patterns with local files"""
def __init__(
self,
mappings: list[tuple[str, str]],
next_source: Source,
):
self._mappings: list[tuple[Pattern[str], str]] = []
self._next_source = next_source
for pattern, replace in mappings:
self._mappings.append((re_compile(pattern), replace))
async def get_url(self, url: str) -> bytes:
"""Return local stylesheet"""
for pattern, replace in self._mappings:
if pattern.match(url):
mapped_path = pattern.sub(replace, url)
with open(mapped_path, "rb") as mapped_file:
return mapped_file.read()
return await self._next_source.get_url(url)