stable/freqtrade/rpc/api_server/webserver.py

111 lines
4.0 KiB
Python
Raw Normal View History

import logging
2020-12-27 09:56:19 +00:00
from ipaddress import IPv4Address
2020-12-27 09:59:17 +00:00
from typing import Any, Dict
2020-12-25 19:07:12 +00:00
import uvicorn
2020-12-25 14:50:19 +00:00
from fastapi import Depends, FastAPI
from fastapi.middleware.cors import CORSMiddleware
2020-12-26 19:05:27 +00:00
from starlette.responses import JSONResponse
from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler
from .uvicorn_threaded import UvicornServer
logger = logging.getLogger(__name__)
class ApiServer(RPCHandler):
2020-12-31 10:01:50 +00:00
_rpc: RPC
2020-12-25 14:50:19 +00:00
_config: Dict[str, Any] = {}
def __init__(self, rpc: RPC, config: Dict[str, Any]) -> None:
super().__init__(rpc, config)
self._server = None
ApiServer._rpc = rpc
ApiServer._config = config
api_config = self._config['api_server']
self.app = FastAPI(title="Freqtrade API",
openapi_url='openapi.json' if api_config.get(
'enable_openapi') else None,
redoc_url=None,
)
self.configure_app(self.app, self._config)
self.start_api()
def cleanup(self) -> None:
""" Cleanup pending module resources """
if self._server:
2020-12-27 09:56:19 +00:00
logger.info("Stopping API Server")
self._server.cleanup()
def send_msg(self, msg: Dict[str, str]) -> None:
pass
def handle_rpc_exception(self, request, exc):
logger.exception(f"API Error calling: {exc}")
return JSONResponse(
status_code=502,
content={'error': f"Error querying {request.url.path}: {exc.message}"}
)
def configure_app(self, app: FastAPI, config):
from .api_auth import http_basic_or_jwt_token, router_login
from .api_v1 import router as api_v1
2020-12-25 14:50:19 +00:00
from .api_v1 import router_public as api_v1_public
app.include_router(api_v1_public, prefix="/api/v1")
2020-12-25 14:50:19 +00:00
app.include_router(api_v1, prefix="/api/v1",
2020-12-26 07:48:15 +00:00
dependencies=[Depends(http_basic_or_jwt_token)],
2020-12-25 14:50:19 +00:00
)
2020-12-26 07:48:15 +00:00
app.include_router(router_login, prefix="/api/v1", tags=["auth"])
app.add_middleware(
CORSMiddleware,
allow_origins=config['api_server'].get('CORS_origins', []),
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.add_exception_handler(RPCException, self.handle_rpc_exception)
def start_api(self):
"""
Start API ... should be run in thread.
"""
2020-12-27 09:56:19 +00:00
rest_ip = self._config['api_server']['listen_ip_address']
rest_port = self._config['api_server']['listen_port']
logger.info(f'Starting HTTP Server at {rest_ip}:{rest_port}')
if not IPv4Address(rest_ip).is_loopback:
logger.warning("SECURITY WARNING - Local Rest Server listening to external connections")
logger.warning("SECURITY WARNING - This is insecure please set to your loopback,"
"e.g 127.0.0.1 in config.json")
if not self._config['api_server'].get('password'):
logger.warning("SECURITY WARNING - No password for local REST Server defined. "
"Please make sure that this is intentional!")
2020-12-27 14:24:49 +00:00
if (self._config['api_server'].get('jwt_secret_key', 'super-secret')
in ('super-secret, somethingrandom')):
logger.warning("SECURITY WARNING - `jwt_secret_key` seems to be default."
"Others may be able to log into your bot.")
2020-12-27 09:56:19 +00:00
logger.info('Starting Local Rest Server.')
verbosity = self._config['api_server'].get('verbosity', 'info')
uvconfig = uvicorn.Config(self.app,
2020-12-27 09:56:19 +00:00
port=rest_port,
host=rest_ip,
2020-12-29 16:23:28 +00:00
access_log=True if verbosity != 'error' else False,
)
2020-12-27 09:56:19 +00:00
try:
self._server = UvicornServer(uvconfig)
self._server.run_in_thread()
except Exception:
logger.exception("Api server failed to start.")