Source code for eveuniverse.core.evemicros
"""Wrapper to access evemicros API."""
from dataclasses import dataclass
from typing import Optional
from urllib.parse import urlencode
import requests
from django.core.cache import cache
from eveuniverse.app_settings import EVEUNIVERSE_REQUESTS_DEFAULT_TIMEOUT
_CACHE_TIMEOUT = 3_600 * 12
_BASE_URL = "https://www.kalkoken.org/apps/evemicros/eveUniverse.php"
[docs]
@dataclass
class EveItem:
"""A celestial item."""
id: int
name: str
type_id: int
distance: float
[docs]
def nearest_celestial(
solar_system_id: int, x: int, y: int, z: int, group_id: Optional[int] = None
) -> Optional[EveItem]:
"""Fetch nearest celestial to given coordinates from API. Results are cached.
Args:
solar_system_id: Eve ID of solar system
x, y, z: Start point in space to look from
group_id: Eve ID of group to filter results by
Raises:
HTTPError: If an HTTP error is encountered
Returns:
Found Eve item or None if nothing found nearby.
"""
result = _fetch_result_from_api_cached(
solar_system_id=solar_system_id, x=x, y=y, z=z
)
return _get_item_from_result(result, group_id)
def _fetch_result_from_api_cached(
solar_system_id: int, x: int, y: int, z: int
) -> Optional[dict]:
"""Fetches result from API or cache.
Returns None if data from API does not have expected structure.
"""
params = map(str, map(int, [solar_system_id, x, y, z]))
query = urlencode({"nearestCelestials": ",".join(params)})
cache_key = f"EVEUNIVERSE_NEAREST_CELESTIAL_{query}"
result = cache.get(key=cache_key)
if not result:
response = requests.get(
f"{_BASE_URL}?{query}", timeout=EVEUNIVERSE_REQUESTS_DEFAULT_TIMEOUT
)
response.raise_for_status()
data = response.json()
if "ok" not in data or not data["ok"] or "result" not in data:
return None
result = data["result"]
cache.set(key=cache_key, value=result, timeout=_CACHE_TIMEOUT)
return result
def _get_item_from_result(result, group_id) -> Optional[EveItem]:
"""Tries to find item in result. Returns None if item can not be found."""
if not result:
return None
if not group_id:
return _create_item(result[0])
for item in result:
if item["groupID"] == group_id:
return _create_item(item)
return None
def _create_item(record: dict) -> EveItem:
return EveItem(
id=int(record["itemID"]),
name=str(record["itemName"]),
type_id=int(record["typeID"]),
distance=float(record["distanceKm"]),
)