Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/backend api security and minor fixes #188

Merged
merged 7 commits into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CONFIG.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@

BACKEND_API_HOST = os.getenv("BACKEND_API_HOST", "127.0.0.1")
BACKEND_API_PORT = os.getenv("BACKEND_API_PORT", 8000)
BACKEND_API_USERNAME = os.getenv("BACKEND_API_USERNAME", "admin")
BACKEND_API_PASSWORD = os.getenv("BACKEND_API_PASSWORD", "admin")
13 changes: 9 additions & 4 deletions backend/services/backend_api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import requests
import streamlit as st
from hummingbot.strategy_v2.models.executors_info import ExecutorInfo
from requests.auth import HTTPBasicAuth


class BackendAPIClient:
Expand All @@ -20,10 +21,11 @@ def get_instance(cls, *args, **kwargs) -> "BackendAPIClient":
cls._shared_instance = BackendAPIClient(*args, **kwargs)
return cls._shared_instance

def __init__(self, host: str = "localhost", port: int = 8000):
def __init__(self, host: str = "localhost", port: int = 8000, username: str = "admin", password: str = "admin"):
self.host = host
self.port = port
self.base_url = f"http://{self.host}:{self.port}"
self.auth = HTTPBasicAuth(username, password)

def post(self, endpoint: str, payload: Optional[Dict] = None, params: Optional[Dict] = None):
"""
Expand All @@ -34,7 +36,7 @@ def post(self, endpoint: str, payload: Optional[Dict] = None, params: Optional[D
:return:
"""
url = f"{self.base_url}/{endpoint}"
response = requests.post(url, json=payload, params=params)
response = requests.post(url, json=payload, params=params, auth=self.auth)
return self._process_response(response)

def get(self, endpoint: str):
Expand All @@ -44,12 +46,15 @@ def get(self, endpoint: str):
:return:
"""
url = f"{self.base_url}/{endpoint}"
response = requests.get(url)
response = requests.get(url, auth=self.auth)
return self._process_response(response)

@staticmethod
def _process_response(response):
if response.status_code == 400:
if response.status_code == 401:
st.error("You are not authorized to access Backend API. Please check your credentials.")
return
elif response.status_code == 400:
st.error(response.json()["detail"])
return
return response.json()
Expand Down
7 changes: 2 additions & 5 deletions environment_conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,10 @@ dependencies:
- statsmodels
- pandas_ta==0.3.14b
- pyyaml
- jupyter
- optuna
- optuna-dashboard
- pathlib
- st-pages
- st_pages
- streamlit-elements==0.1.*
- streamlit-authenticator
- streamlit-authenticator==0.3.2
- pydantic==1.10.4
- flake8
- isort
Expand Down
62 changes: 34 additions & 28 deletions frontend/components/launch_strategy_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,41 @@ def _handle_row_selection(self, params, _):
self._controller_config_selected = [param + ".yml" for param in params]

def launch_new_bot(self):
if self._bot_name and self._image_name and len(self._controller_config_selected) > 0:
start_time_str = time.strftime("%Y.%m.%d_%H.%M")
bot_name = f"{self._bot_name}-{start_time_str}"
script_config = {
"name": bot_name,
"content": {
"markets": {},
"candles_config": [],
"controllers_config": self._controller_config_selected,
"config_update_interval": 10,
"script_file_name": "v2_with_controllers.py",
"time_to_cash_out": None,
}
if not self._bot_name:
st.warning("You need to define the bot name.")
return
if not self._image_name:
st.warning("You need to select the hummingbot image.")
return
if not self._controller_config_selected or len(self._controller_config_selected) == 0:
st.warning("You need to select the controllers configs. Please select at least one controller "
"config by clicking on the checkbox.")
return
start_time_str = time.strftime("%Y.%m.%d_%H.%M")
bot_name = f"{self._bot_name}-{start_time_str}"
script_config = {
"name": bot_name,
"content": {
"markets": {},
"candles_config": [],
"controllers_config": self._controller_config_selected,
"config_update_interval": 10,
"script_file_name": "v2_with_controllers.py",
"time_to_cash_out": None,
}

self._backend_api_client.add_script_config(script_config)
deploy_config = {
"instance_name": bot_name,
"script": "v2_with_controllers.py",
"script_config": bot_name + ".yml",
"image": self._image_name,
"credentials_profile": self._credentials,
}
self._backend_api_client.create_hummingbot_instance(deploy_config)
with st.spinner('Starting Bot... This process may take a few seconds'):
time.sleep(3)
else:
st.warning("You need to define the bot name and select the controllers configs "
"that you want to deploy.")
}

self._backend_api_client.add_script_config(script_config)
deploy_config = {
"instance_name": bot_name,
"script": "v2_with_controllers.py",
"script_config": bot_name + ".yml",
"image": self._image_name,
"credentials_profile": self._credentials,
}
self._backend_api_client.create_hummingbot_instance(deploy_config)
with st.spinner('Starting Bot... This process may take a few seconds'):
time.sleep(3)

def delete_selected_configs(self):
if self._controller_config_selected:
Expand Down
5 changes: 2 additions & 3 deletions frontend/pages/config/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import pandas as pd
import streamlit as st

from backend.services.backend_api_client import BackendAPIClient
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from frontend.st_utils import get_backend_api_client


def get_max_records(days_to_download: int, interval: str) -> int:
Expand All @@ -16,7 +15,7 @@ def get_max_records(days_to_download: int, interval: str) -> int:

@st.cache_data
def get_candles(connector_name="binance", trading_pair="BTC-USDT", interval="1m", days=7):
backend_client = BackendAPIClient(BACKEND_API_HOST, BACKEND_API_PORT)
backend_client = get_backend_api_client()
end_time = datetime.datetime.now() - datetime.timedelta(minutes=15)
start_time = end_time - datetime.timedelta(days=days)

Expand Down
19 changes: 0 additions & 19 deletions frontend/pages/orchestration/launch_bot_v2_st/README.md

This file was deleted.

Empty file.
8 changes: 0 additions & 8 deletions frontend/pages/orchestration/launch_bot_v2_st/app.py

This file was deleted.

21 changes: 8 additions & 13 deletions frontend/st_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,16 @@ def style_metric_cards(

def get_backend_api_client():
from backend.services.backend_api_client import BackendAPIClient
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
is_docker_running = False
from CONFIG import BACKEND_API_HOST, BACKEND_API_PASSWORD, BACKEND_API_PORT, BACKEND_API_USERNAME
try:
backend_api_client = BackendAPIClient.get_instance(host=BACKEND_API_HOST, port=BACKEND_API_PORT)
is_docker_running = backend_api_client.is_docker_running()
except Exception as e:
st.error(
f"There was an error trying to connect to the Backend API. Please make sure the Backend API is running.\n\n"
f"Error: \n\n{str(e)}")
backend_api_client = BackendAPIClient.get_instance(host=BACKEND_API_HOST, port=BACKEND_API_PORT,
username=BACKEND_API_USERNAME, password=BACKEND_API_PASSWORD)
if not backend_api_client.is_docker_running():
st.error("Docker is not running. Please make sure Docker is running.")
st.stop()
return backend_api_client
except Exception:
st.stop()
if not is_docker_running:
st.error("Docker is not running. Please make sure Docker is running.")
st.stop()
return backend_api_client


def auth_system():
Expand All @@ -102,7 +98,6 @@ def auth_system():
config['cookie']['name'],
config['cookie']['key'],
config['cookie']['expiry_days'],
config['pre-authorized']
)
show_pages(main_page() + public_pages())
st.session_state.authenticator.login()
Expand Down