kopia lustrzana https://github.com/bugout-dev/moonstream
API endpoint for crawlers
rodzic
42e764d1b2
commit
11aa45690f
|
|
@ -0,0 +1,81 @@
|
||||||
|
"""
|
||||||
|
The Mooncrawl HTTP API
|
||||||
|
"""
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
from . import data
|
||||||
|
from .middleware import MoonstreamHTTPException
|
||||||
|
from .settings import DOCS_TARGET_PATH, ORIGINS
|
||||||
|
from .version import MOONCRAWL_VERSION
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
tags_metadata = [
|
||||||
|
{"name": "jobs", "description": "Trigger crawler jobs."},
|
||||||
|
{"name": "time", "description": "Server timestamp endpoints."},
|
||||||
|
]
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title=f"Mooncrawl HTTP API",
|
||||||
|
description="Mooncrawl API endpoints.",
|
||||||
|
version=MOONCRAWL_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("/ping", response_model=data.PingResponse)
|
||||||
|
async def ping_handler() -> data.PingResponse:
|
||||||
|
"""
|
||||||
|
Check server status.
|
||||||
|
"""
|
||||||
|
return data.PingResponse(status="ok")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/version", response_model=data.VersionResponse)
|
||||||
|
async def version_handler() -> data.VersionResponse:
|
||||||
|
"""
|
||||||
|
Get server version.
|
||||||
|
"""
|
||||||
|
return data.VersionResponse(version=MOONCRAWL_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/now", tags=["time"])
|
||||||
|
async def now_handler() -> data.NowResponse:
|
||||||
|
"""
|
||||||
|
Get server current time.
|
||||||
|
"""
|
||||||
|
return data.NowResponse(epoch_time=time.time())
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/jobs/stats_update", tags=["jobs"])
|
||||||
|
async def status_handler():
|
||||||
|
"""
|
||||||
|
Find latest crawlers records with creation timestamp:
|
||||||
|
- ethereum_txpool
|
||||||
|
- ethereum_trending
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Unhandled status exception, error: {e}")
|
||||||
|
raise MoonstreamHTTPException(status_code=500)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
@ -2,6 +2,8 @@ from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
class AvailableBlockchainType(Enum):
|
class AvailableBlockchainType(Enum):
|
||||||
ETHEREUM = "ethereum"
|
ETHEREUM = "ethereum"
|
||||||
|
|
@ -14,3 +16,27 @@ class DateRange:
|
||||||
end_time: datetime
|
end_time: datetime
|
||||||
include_start: bool
|
include_start: bool
|
||||||
include_end: bool
|
include_end: bool
|
||||||
|
|
||||||
|
|
||||||
|
class PingResponse(BaseModel):
|
||||||
|
"""
|
||||||
|
Schema for ping response
|
||||||
|
"""
|
||||||
|
|
||||||
|
status: str
|
||||||
|
|
||||||
|
|
||||||
|
class VersionResponse(BaseModel):
|
||||||
|
"""
|
||||||
|
Schema for responses on /version endpoint
|
||||||
|
"""
|
||||||
|
|
||||||
|
version: str
|
||||||
|
|
||||||
|
|
||||||
|
class NowResponse(BaseModel):
|
||||||
|
"""
|
||||||
|
Schema for responses on /now endpoint
|
||||||
|
"""
|
||||||
|
|
||||||
|
epoch_time: float
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import logging
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
from fastapi import HTTPException
|
||||||
|
|
||||||
|
from .reporter import reporter
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MoonstreamHTTPException(HTTPException):
|
||||||
|
"""
|
||||||
|
Extended HTTPException to handle 500 Internal server errors
|
||||||
|
and send crash reports.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
status_code: int,
|
||||||
|
detail: Any = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
internal_error: Exception = None,
|
||||||
|
):
|
||||||
|
super().__init__(status_code, detail, headers)
|
||||||
|
if internal_error is not None:
|
||||||
|
reporter.error_report(internal_error)
|
||||||
|
|
@ -6,10 +6,21 @@ from bugout.app import Bugout
|
||||||
# Bugout
|
# Bugout
|
||||||
BUGOUT_BROOD_URL = os.environ.get("BUGOUT_BROOD_URL", "https://auth.bugout.dev")
|
BUGOUT_BROOD_URL = os.environ.get("BUGOUT_BROOD_URL", "https://auth.bugout.dev")
|
||||||
BUGOUT_SPIRE_URL = os.environ.get("BUGOUT_SPIRE_URL", "https://spire.bugout.dev")
|
BUGOUT_SPIRE_URL = os.environ.get("BUGOUT_SPIRE_URL", "https://spire.bugout.dev")
|
||||||
bc = Bugout(brood_api_url=BUGOUT_BROOD_URL, spire_api_url=BUGOUT_SPIRE_URL)
|
bugout_client = Bugout(brood_api_url=BUGOUT_BROOD_URL, spire_api_url=BUGOUT_SPIRE_URL)
|
||||||
|
|
||||||
HUMBUG_REPORTER_CRAWLERS_TOKEN = os.environ.get("HUMBUG_REPORTER_CRAWLERS_TOKEN")
|
HUMBUG_REPORTER_CRAWLERS_TOKEN = os.environ.get("HUMBUG_REPORTER_CRAWLERS_TOKEN")
|
||||||
|
|
||||||
|
# Origin
|
||||||
|
RAW_ORIGINS = os.environ.get("MOONSTREAM_CORS_ALLOWED_ORIGINS")
|
||||||
|
if RAW_ORIGINS is None:
|
||||||
|
raise ValueError(
|
||||||
|
"MOONSTREAM_CORS_ALLOWED_ORIGINS environment variable must be set (comma-separated list of CORS allowed origins)"
|
||||||
|
)
|
||||||
|
ORIGINS = RAW_ORIGINS.split(",")
|
||||||
|
|
||||||
|
# OpenAPI
|
||||||
|
DOCS_TARGET_PATH = "docs"
|
||||||
|
|
||||||
# Geth connection address
|
# Geth connection address
|
||||||
MOONSTREAM_NODE_ETHEREUM_IPC_ADDR = os.environ.get(
|
MOONSTREAM_NODE_ETHEREUM_IPC_ADDR = os.environ.get(
|
||||||
"MOONSTREAM_NODE_ETHEREUM_IPC_ADDR", "127.0.0.1"
|
"MOONSTREAM_NODE_ETHEREUM_IPC_ADDR", "127.0.0.1"
|
||||||
|
|
@ -56,4 +67,15 @@ MOONSTREAM_DATA_JOURNAL_ID = os.environ.get("MOONSTREAM_DATA_JOURNAL_ID", "")
|
||||||
if MOONSTREAM_DATA_JOURNAL_ID == "":
|
if MOONSTREAM_DATA_JOURNAL_ID == "":
|
||||||
raise ValueError("MOONSTREAM_DATA_JOURNAL_ID env variable is not set")
|
raise ValueError("MOONSTREAM_DATA_JOURNAL_ID env variable is not set")
|
||||||
|
|
||||||
AWS_S3_SMARTCONTRACTS_ABI_PREFIX = os.getenv("AWS_S3_SMARTCONTRACTS_ABI_PREFIX")
|
# AWS S3 bucket for ABI smartcontract settings
|
||||||
|
AWS_S3_SMARTCONTRACTS_ABI_BUCKET = os.environ.get("AWS_S3_SMARTCONTRACTS_ABI_BUCKET")
|
||||||
|
if AWS_S3_SMARTCONTRACTS_ABI_BUCKET is None:
|
||||||
|
raise ValueError(
|
||||||
|
"AWS_S3_SMARTCONTRACTS_ABI_BUCKET environment variable must be set"
|
||||||
|
)
|
||||||
|
AWS_S3_SMARTCONTRACTS_ABI_PREFIX = os.environ.get("AWS_S3_SMARTCONTRACTS_ABI_PREFIX")
|
||||||
|
if AWS_S3_SMARTCONTRACTS_ABI_PREFIX is None:
|
||||||
|
raise ValueError(
|
||||||
|
"AWS_S3_SMARTCONTRACTS_ABI_PREFIX environment variable must be set"
|
||||||
|
)
|
||||||
|
AWS_S3_SMARTCONTRACTS_ABI_PREFIX = AWS_S3_SMARTCONTRACTS_ABI_PREFIX.rstrip("/")
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,11 @@ from sqlalchemy.orm import Query, Session
|
||||||
from ..blockchain import get_block_model, get_label_model, get_transaction_model
|
from ..blockchain import get_block_model, get_label_model, get_transaction_model
|
||||||
from ..data import AvailableBlockchainType
|
from ..data import AvailableBlockchainType
|
||||||
from ..settings import (
|
from ..settings import (
|
||||||
|
AWS_S3_SMARTCONTRACTS_ABI_BUCKET,
|
||||||
AWS_S3_SMARTCONTRACTS_ABI_PREFIX,
|
AWS_S3_SMARTCONTRACTS_ABI_PREFIX,
|
||||||
MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
MOONSTREAM_ADMIN_ACCESS_TOKEN,
|
||||||
bc,
|
|
||||||
)
|
)
|
||||||
|
from ..settings import bugout_client as bc
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
logger.setLevel(logging.INFO)
|
logger.setLevel(logging.INFO)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# Path to IPC socket to use for web3 connections
|
export BUGOUT_BROOD_URL="https://auth.bugout.dev"
|
||||||
|
export BUGOUT_SPIRE_URL="https://spire.bugout.dev"
|
||||||
export MOONSTREAM_NODE_ETHEREUM_IPC_ADDR="127.0.0.1"
|
export MOONSTREAM_NODE_ETHEREUM_IPC_ADDR="127.0.0.1"
|
||||||
export MOONSTREAM_NODE_ETHEREUM_IPC_PORT="8545"
|
export MOONSTREAM_NODE_ETHEREUM_IPC_PORT="8545"
|
||||||
export MOONSTREAM_NODE_POLYGON_IPC_ADDR="127.0.0.1"
|
export MOONSTREAM_NODE_POLYGON_IPC_ADDR="127.0.0.1"
|
||||||
|
|
@ -7,6 +8,8 @@ export MOONSTREAM_CRAWL_WORKERS=4
|
||||||
export MOONSTREAM_DB_URI="postgresql://<username>:<password>@<db_host>:<db_port>/<db_name>"
|
export MOONSTREAM_DB_URI="postgresql://<username>:<password>@<db_host>:<db_port>/<db_name>"
|
||||||
export MOONSTREAM_ETHERSCAN_TOKEN="<Token for etherscan>"
|
export MOONSTREAM_ETHERSCAN_TOKEN="<Token for etherscan>"
|
||||||
export AWS_S3_SMARTCONTRACT_BUCKET="<AWS S3 bucket for smart contracts>"
|
export AWS_S3_SMARTCONTRACT_BUCKET="<AWS S3 bucket for smart contracts>"
|
||||||
|
export AWS_S3_SMARTCONTRACTS_ABI_BUCKET="<AWS S3 bucket to store smart contracts ABI>"
|
||||||
|
export AWS_S3_SMARTCONTRACTS_ABI_PREFIX="<Previx for AWS S3 bucket (v1/v2/dev/..)>"
|
||||||
export MOONSTREAM_HUMBUG_TOKEN="<Token for crawlers store data via Humbug>"
|
export MOONSTREAM_HUMBUG_TOKEN="<Token for crawlers store data via Humbug>"
|
||||||
export COINMARKETCAP_API_KEY="<API key to parse conmarketcap>"
|
export COINMARKETCAP_API_KEY="<API key to parse conmarketcap>"
|
||||||
export HUMBUG_REPORTER_CRAWLERS_TOKEN="<Bugout Humbug token for crash reports>"
|
export HUMBUG_REPORTER_CRAWLERS_TOKEN="<Bugout Humbug token for crash reports>"
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,14 @@ setup(
|
||||||
"boto3",
|
"boto3",
|
||||||
"bugout",
|
"bugout",
|
||||||
"chardet",
|
"chardet",
|
||||||
|
"fastapi",
|
||||||
"moonstreamdb",
|
"moonstreamdb",
|
||||||
"humbug",
|
"humbug",
|
||||||
|
"pydantic",
|
||||||
"python-dateutil",
|
"python-dateutil",
|
||||||
"requests",
|
"requests",
|
||||||
"tqdm",
|
"tqdm",
|
||||||
|
"uvicorn",
|
||||||
"web3",
|
"web3",
|
||||||
],
|
],
|
||||||
extras_require={
|
extras_require={
|
||||||
|
|
|
||||||
Ładowanie…
Reference in New Issue