Files
proxy-scraper-checker/proxy_scraper_checker/geodb.py
T

97 lines
3.0 KiB
Python
Raw Normal View History

2024-01-21 17:45:01 +00:00
from __future__ import annotations
2024-11-04 11:00:52 +03:00
import asyncio
2024-01-21 17:45:01 +00:00
import logging
2024-02-08 09:12:13 +03:00
import stat
2024-06-03 14:08:42 +05:00
from typing import TYPE_CHECKING
2024-01-21 17:45:01 +00:00
2024-07-09 03:08:30 +03:00
from aiohttp import hdrs
2024-01-21 17:45:01 +00:00
2024-11-22 14:32:29 +03:00
from proxy_scraper_checker import fs
2025-02-17 17:33:19 +03:00
from proxy_scraper_checker.utils import is_docker
2024-01-21 17:45:01 +00:00
2024-06-03 14:08:42 +05:00
if TYPE_CHECKING:
2024-07-09 03:08:30 +03:00
from aiohttp import ClientResponse, ClientSession
2024-06-03 14:08:42 +05:00
from rich.progress import Progress, TaskID
2024-11-06 15:05:34 +03:00
_logger = logging.getLogger(__name__)
2024-01-21 17:45:01 +00:00
GEODB_URL = "https://raw.githubusercontent.com/P3TERX/GeoLite.mmdb/download/GeoLite2-City.mmdb"
2024-02-08 09:12:13 +03:00
GEODB_PATH = fs.CACHE_PATH / "geolocation_database.mmdb"
2024-01-21 17:45:01 +00:00
GEODB_ETAG_PATH = GEODB_PATH.with_suffix(".mmdb.etag")
2024-06-03 14:08:42 +05:00
async def _read_etag() -> str | None:
2024-01-21 17:45:01 +00:00
try:
2025-01-09 15:30:45 +03:00
await fs.add_permission(GEODB_ETAG_PATH, stat.S_IRUSR)
2025-02-17 17:33:19 +03:00
return await asyncio.to_thread(
GEODB_ETAG_PATH.read_text, encoding="utf-8"
)
except (FileNotFoundError, UnicodeDecodeError):
2024-01-21 17:45:01 +00:00
return None
2024-11-04 11:00:52 +03:00
async def _remove_etag() -> None:
return await asyncio.to_thread(GEODB_ETAG_PATH.unlink, missing_ok=True)
2024-01-21 17:45:01 +00:00
async def _save_etag(etag: str, /) -> None:
2025-01-09 15:30:45 +03:00
await fs.add_permission(GEODB_ETAG_PATH, stat.S_IWUSR, missing_ok=True)
await asyncio.to_thread(GEODB_ETAG_PATH.write_text, etag, encoding="utf-8")
2024-01-21 17:45:01 +00:00
async def _save_geodb(
2025-02-27 11:12:52 +03:00
*, progress: Progress, progress_task: TaskID, response: ClientResponse
2024-01-21 17:45:01 +00:00
) -> None:
2025-01-09 15:30:45 +03:00
await fs.add_permission(GEODB_PATH, stat.S_IWUSR, missing_ok=True)
2025-01-07 22:52:14 +03:00
geodb = await asyncio.to_thread(GEODB_PATH.open, "wb")
try:
2024-01-21 17:45:01 +00:00
async for chunk in response.content.iter_any():
2025-01-07 22:52:14 +03:00
await asyncio.to_thread(geodb.write, chunk)
2025-02-27 11:12:52 +03:00
progress.advance(task_id=progress_task, advance=len(chunk))
2025-01-07 22:52:14 +03:00
finally:
await asyncio.to_thread(geodb.close)
2025-02-27 11:12:52 +03:00
progress.update(task_id=progress_task, successful_count="\N{CHECK MARK}")
2024-01-21 17:45:01 +00:00
async def download_geodb(*, progress: Progress, session: ClientSession) -> None:
headers = (
{hdrs.IF_NONE_MATCH: current_etag}
2025-02-17 17:33:19 +03:00
if await asyncio.to_thread(GEODB_PATH.is_file)
2024-01-21 17:45:01 +00:00
and (current_etag := await _read_etag())
else None
)
async with session.get(GEODB_URL, headers=headers) as response:
2024-01-21 17:45:01 +00:00
if response.status == 304: # noqa: PLR2004
2024-11-06 15:05:34 +03:00
_logger.info(
2024-01-21 17:45:01 +00:00
"Latest geolocation database is already cached at %s",
GEODB_PATH,
)
return
await _save_geodb(
progress=progress,
2025-02-27 11:12:52 +03:00
progress_task=progress.add_task(
2024-01-25 11:49:22 +03:00
description="",
2024-01-21 17:45:01 +00:00
total=response.content_length,
module="Downloader",
protocol="GeoDB",
2024-11-27 12:26:57 +03:00
successful_count="\N{HORIZONTAL ELLIPSIS}",
2024-01-21 17:45:01 +00:00
),
2025-02-27 11:12:52 +03:00
response=response,
2024-01-21 17:45:01 +00:00
)
2024-02-01 07:24:26 +00:00
if await asyncio.to_thread(is_docker):
2024-11-06 15:05:34 +03:00
_logger.info(
2024-02-01 07:24:26 +00:00
"Downloaded geolocation database to proxy_scraper_checker_cache "
"Docker volume (%s in container)",
GEODB_PATH,
)
else:
2024-11-06 15:05:34 +03:00
_logger.info("Downloaded geolocation database to %s", GEODB_PATH)
2024-01-21 17:45:01 +00:00
if etag := response.headers.get(hdrs.ETAG):
await _save_etag(etag)
else:
await _remove_etag()