Introduce webserver mode for fastapi

This commit is contained in:
Matthias 2020-12-31 20:02:27 +01:00
parent 800e314bfd
commit 02b84bd018
4 changed files with 43 additions and 10 deletions

View File

@ -1,7 +1,6 @@
import logging import logging
from typing import Any, Dict from typing import Any, Dict
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -29,9 +28,14 @@ def start_trading(args: Dict[str, Any]) -> int:
return 0 return 0
def start_webserver(args: Dict[str, Any]) -> int: def start_webserver(args: Dict[str, Any]) -> None:
""" """
Main entry point for webserver mode Main entry point for webserver mode
""" """
from freqtrade.rpc.api_server import ApiServer
from freqtrade.configuration import Configuration
from freqtrade.enums import RunMode
print(args) # Initialize configuration
config = Configuration(args, RunMode.WEBSERVER).get_config()
ApiServer(config, standalone=True)

View File

@ -14,6 +14,7 @@ class RunMode(Enum):
UTIL_EXCHANGE = "util_exchange" UTIL_EXCHANGE = "util_exchange"
UTIL_NO_EXCHANGE = "util_no_exchange" UTIL_NO_EXCHANGE = "util_no_exchange"
PLOT = "plot" PLOT = "plot"
WEBSERVER = "webserver"
OTHER = "other" OTHER = "other"

View File

@ -8,6 +8,7 @@ from fastapi import Depends, FastAPI
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from starlette.responses import JSONResponse from starlette.responses import JSONResponse
from freqtrade.exceptions import OperationalException
from freqtrade.rpc.api_server.uvicorn_threaded import UvicornServer from freqtrade.rpc.api_server.uvicorn_threaded import UvicornServer
from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler from freqtrade.rpc.rpc import RPC, RPCException, RPCHandler
@ -28,16 +29,30 @@ class FTJSONResponse(JSONResponse):
class ApiServer(RPCHandler): class ApiServer(RPCHandler):
__instance = None
__initialized = False
_rpc: RPC _rpc: RPC
_has_rpc: bool = False _has_rpc: bool = False
_config: Dict[str, Any] = {} _config: Dict[str, Any] = {}
def __init__(self, rpc: RPC, config: Dict[str, Any]) -> None: def __new__(cls, *args, **kwargs):
super().__init__(rpc, config) """
This class is a singleton.
We'll only have one instance of it around.
"""
if ApiServer.__instance is None:
ApiServer.__instance = object.__new__(cls)
ApiServer.__initialized = False
return ApiServer.__instance
def __init__(self, config: Dict[str, Any], standalone: bool = False) -> None:
if self.__initialized and (standalone or self._standalone):
return
self._standalone: bool = standalone
self._config = config
self._server = None self._server = None
ApiServer._rpc = rpc
ApiServer._has_rpc = True
ApiServer._config = config ApiServer._config = config
api_config = self._config['api_server'] api_config = self._config['api_server']
@ -50,6 +65,18 @@ class ApiServer(RPCHandler):
self.start_api() self.start_api()
def add_rpc_handler(self, rpc: RPC):
"""
Attach rpc handler
"""
if not self._rpc:
self._rpc = rpc
ApiServer._rpc = rpc
ApiServer._has_rpc = True
else:
# This should not happen assuming we didn't mess up.
raise OperationalException('RPC Handler already attached.')
def cleanup(self) -> None: def cleanup(self) -> None:
""" Cleanup pending module resources """ """ Cleanup pending module resources """
if self._server: if self._server:

View File

@ -36,15 +36,16 @@ class RPCManager:
if config.get('api_server', {}).get('enabled', False): if config.get('api_server', {}).get('enabled', False):
logger.info('Enabling rpc.api_server') logger.info('Enabling rpc.api_server')
from freqtrade.rpc.api_server import ApiServer from freqtrade.rpc.api_server import ApiServer
apiserver = ApiServer(config)
self.registered_modules.append(ApiServer(self._rpc, config)) apiserver.add_rpc_handler(self._rpc)
self.registered_modules.append(apiserver)
def cleanup(self) -> None: def cleanup(self) -> None:
""" Stops all enabled rpc modules """ """ Stops all enabled rpc modules """
logger.info('Cleaning up rpc modules ...') logger.info('Cleaning up rpc modules ...')
while self.registered_modules: while self.registered_modules:
mod = self.registered_modules.pop() mod = self.registered_modules.pop()
logger.debug('Cleaning up rpc.%s ...', mod.name) logger.info('Cleaning up rpc.%s ...', mod.name)
mod.cleanup() mod.cleanup()
del mod del mod