diff --git a/backend/moonstream/actions.py b/backend/moonstream/actions.py index 112fc36e..72e894f9 100644 --- a/backend/moonstream/actions.py +++ b/backend/moonstream/actions.py @@ -5,6 +5,8 @@ from enum import Enum import uuid import boto3 # type: ignore +from bugout.data import BugoutSearchResults +from bugout.journal import SearchOrder from moonstreamdb.models import ( EthereumAddress, EthereumLabel, @@ -20,12 +22,20 @@ from .settings import ( MOONSTREAM_APPLICATION_ID, bugout_client as bc, BUGOUT_REQUEST_TIMEOUT_SECONDS, + MOONSTREAM_ADMIN_ACCESS_TOKEN, + MOONSTREAM_DATA_JOURNAL_ID, ) logger = logging.getLogger(__name__) ETHERSCAN_SMARTCONTRACT_LABEL_NAME = "etherscan_smartcontract" +class StatusAPIException(Exception): + """ + Raised during checking Moonstream API statuses. + """ + + def get_contract_source_info( db_session: Session, contract_address: str ) -> Optional[data.EthereumSmartContractSourceInfo]: @@ -192,3 +202,29 @@ def create_onboarding_resource( timeout=BUGOUT_REQUEST_TIMEOUT_SECONDS, ) return resource + + +def check_api_status(): + crawl_types_timestamp: Dict[str, Any] = { + "ethereum_txpool": None, + "ethereum_trending": None, + } + for crawl_type in crawl_types_timestamp.keys(): + try: + search_results: BugoutSearchResults = bc.search( + token=MOONSTREAM_ADMIN_ACCESS_TOKEN, + journal_id=MOONSTREAM_DATA_JOURNAL_ID, + query=f"tag:crawl_type:{crawl_type}", + limit=1, + content=False, + timeout=10.0, + order=SearchOrder.DESCENDING, + ) + if len(search_results.results) == 1: + crawl_types_timestamp[crawl_type] = search_results.results[0].created_at + except Exception: + raise StatusAPIException( + f"Unable to get status for crawler with type: {crawl_type}" + ) + + return crawl_types_timestamp diff --git a/backend/moonstream/api.py b/backend/moonstream/api.py index cfa34320..0d8d0ed5 100644 --- a/backend/moonstream/api.py +++ b/backend/moonstream/api.py @@ -7,10 +7,11 @@ import time from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware +from . import actions from . import data +from .middleware import MoonstreamHTTPException from .routes.address_info import app as addressinfo_api from .routes.nft import app as nft_api -from .routes.status import app as status_api from .routes.subscriptions import app as subscriptions_api from .routes.streams import app as streams_api from .routes.txinfo import app as txinfo_api @@ -47,9 +48,29 @@ async def now_handler() -> data.NowResponse: return data.NowResponse(epoch_time=time.time()) +@app.get("/status", response_model=data.StatusResponse) +async def status_handler() -> data.StatusResponse: + """ + Get latest records and their creation timestamp for crawlers: + - ethereum_txpool + - ethereum_trending + """ + try: + crawl_types_timestamp = actions.check_api_status() + except actions.StatusAPIException: + raise MoonstreamHTTPException(status_code=500) + except Exception as e: + logger.error(f"Unhandled status exception, error: {e}") + raise MoonstreamHTTPException(status_code=500) + + return data.StatusResponse( + ethereum_txpool_timestamp=crawl_types_timestamp["ethereum_txpool"], + ethereum_trending_timestamp=crawl_types_timestamp["ethereum_trending"], + ) + + app.mount("/subscriptions", subscriptions_api) app.mount("/users", users_api) -app.mount("/status", status_api) app.mount("/streams", streams_api) app.mount("/txinfo", txinfo_api) app.mount("/address_info", addressinfo_api) diff --git a/backend/moonstream/routes/status.py b/backend/moonstream/routes/status.py deleted file mode 100644 index ccf41ef1..00000000 --- a/backend/moonstream/routes/status.py +++ /dev/null @@ -1,78 +0,0 @@ -import logging -from typing import Any, Dict - -from bugout.data import BugoutSearchResults -from bugout.exceptions import BugoutResponseException -from bugout.journal import SearchOrder -from fastapi import FastAPI -from fastapi.middleware.cors import CORSMiddleware - -from .. import data -from ..middleware import MoonstreamHTTPException -from ..settings import ( - bugout_client as bc, - DOCS_TARGET_PATH, - MOONSTREAM_ADMIN_ACCESS_TOKEN, - MOONSTREAM_DATA_JOURNAL_ID, - ORIGINS, -) -from ..version import MOONSTREAM_VERSION - -logger = logging.getLogger(__name__) - -tags_metadata = [ - {"name": "status", "description": "Status of Moonstream API services."} -] -app = FastAPI( - title=f"Moonstream users API.", - description="User, token and password handlers.", - version=MOONSTREAM_VERSION, - openapi_tags=tags_metadata, - openapi_url="/openapi.json", - docs_url=None, - redoc_url=f"/{DOCS_TARGET_PATH}", -) - -app.add_middleware( - CORSMiddleware, - allow_origins=ORIGINS, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - - -@app.get("/", tags=["status"], response_model=data.StatusResponse) -async def status_handler() -> data.StatusResponse: - """ - Get latest records and their creation timestamp for crawlers: - - ethereum_txpool - - ethereum_trending - """ - crawl_types_timestamp: Dict[str, Any] = { - "ethereum_txpool": None, - "ethereum_trending": None, - } - for crawl_type in crawl_types_timestamp.keys(): - try: - search_results: BugoutSearchResults = bc.search( - token=MOONSTREAM_ADMIN_ACCESS_TOKEN, - journal_id=MOONSTREAM_DATA_JOURNAL_ID, - query=f"tag:crawl_type:{crawl_type}", - limit=1, - content=False, - timeout=10.0, - order=SearchOrder.DESCENDING, - ) - if len(search_results.results) == 1: - crawl_types_timestamp[crawl_type] = search_results.results[0].created_at - except BugoutResponseException as e: - raise MoonstreamHTTPException(status_code=e.status_code, detail=e.detail) - except Exception as e: - logger.error(f"Unable to get status for crawler with type: {crawl_type}") - raise MoonstreamHTTPException(status_code=500, internal_error=e) - - return data.StatusResponse( - ethereum_txpool_timestamp=crawl_types_timestamp["ethereum_txpool"], - ethereum_trending_timestamp=crawl_types_timestamp["ethereum_trending"], - )