150 lines
4.1 KiB
Rust
150 lines
4.1 KiB
Rust
use axum::{
|
|
extract::{Path, State},
|
|
http::StatusCode,
|
|
response::IntoResponse,
|
|
Json,
|
|
};
|
|
use serde::{Deserialize, Serialize};
|
|
use uuid::Uuid;
|
|
|
|
use crate::binance::client::BinanceClient;
|
|
use crate::storage::config::BotConfig;
|
|
use crate::AppState;
|
|
|
|
#[derive(Serialize)]
|
|
pub struct SymbolInfo {
|
|
pub symbol: String,
|
|
pub min_notional: f64,
|
|
}
|
|
|
|
pub async fn list_symbols(State(state): State<AppState>) -> impl IntoResponse {
|
|
let client = BinanceClient::new(state.api_key, state.api_secret, state.testnet);
|
|
match client.get_usdt_symbols_with_min().await {
|
|
Ok(mut symbols) => {
|
|
symbols.sort_by(|a, b| a.0.cmp(&b.0));
|
|
let result: Vec<SymbolInfo> = symbols
|
|
.into_iter()
|
|
.map(|(symbol, min_notional)| SymbolInfo { symbol, min_notional })
|
|
.collect();
|
|
Json(result).into_response()
|
|
}
|
|
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct CreateBotRequest {
|
|
pub name: String,
|
|
pub symbol: String,
|
|
pub timeframe: crate::binance::models::Timeframe,
|
|
pub usdt_amount: f64,
|
|
pub profit_percent: f64,
|
|
pub testnet: Option<bool>,
|
|
}
|
|
|
|
#[derive(Serialize)]
|
|
pub struct BotResponse {
|
|
#[serde(flatten)]
|
|
pub config: BotConfig,
|
|
pub running: bool,
|
|
}
|
|
|
|
pub async fn list_bots(State(state): State<AppState>) -> impl IntoResponse {
|
|
let db = state.db.lock().await;
|
|
let bots = match db.get_bots() {
|
|
Ok(b) => b,
|
|
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
|
|
};
|
|
drop(db);
|
|
|
|
let manager = state.manager.lock().await;
|
|
let response: Vec<BotResponse> = bots
|
|
.into_iter()
|
|
.map(|b| {
|
|
let running = manager.is_running(&b.id);
|
|
BotResponse { config: b, running }
|
|
})
|
|
.collect();
|
|
|
|
Json(response).into_response()
|
|
}
|
|
|
|
pub async fn create_bot(
|
|
State(state): State<AppState>,
|
|
Json(req): Json<CreateBotRequest>,
|
|
) -> impl IntoResponse {
|
|
let config = BotConfig {
|
|
id: Uuid::new_v4().to_string(),
|
|
name: req.name,
|
|
symbol: req.symbol.to_uppercase(),
|
|
timeframe: req.timeframe,
|
|
usdt_amount: req.usdt_amount,
|
|
profit_percent: req.profit_percent,
|
|
testnet: req.testnet.unwrap_or(false),
|
|
active: false,
|
|
};
|
|
|
|
let db = state.db.lock().await;
|
|
if let Err(e) = db.insert_bot(&config) {
|
|
return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response();
|
|
}
|
|
drop(db);
|
|
|
|
Json(BotResponse { config, running: false }).into_response()
|
|
}
|
|
|
|
pub async fn delete_bot(
|
|
State(state): State<AppState>,
|
|
Path(id): Path<String>,
|
|
) -> impl IntoResponse {
|
|
let mut manager = state.manager.lock().await;
|
|
manager.stop(&id).await;
|
|
drop(manager);
|
|
|
|
let db = state.db.lock().await;
|
|
if let Err(e) = db.delete_bot(&id) {
|
|
return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response();
|
|
}
|
|
|
|
StatusCode::NO_CONTENT.into_response()
|
|
}
|
|
|
|
pub async fn start_bot(
|
|
State(state): State<AppState>,
|
|
Path(id): Path<String>,
|
|
) -> impl IntoResponse {
|
|
let db = state.db.lock().await;
|
|
let bots = match db.get_bots() {
|
|
Ok(b) => b,
|
|
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
|
|
};
|
|
let config = match bots.into_iter().find(|b| b.id == id) {
|
|
Some(c) => c,
|
|
None => return StatusCode::NOT_FOUND.into_response(),
|
|
};
|
|
if let Err(e) = db.set_bot_active(&id, true) {
|
|
return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response();
|
|
}
|
|
drop(db);
|
|
|
|
let mut manager = state.manager.lock().await;
|
|
manager.start(config);
|
|
|
|
StatusCode::OK.into_response()
|
|
}
|
|
|
|
pub async fn stop_bot(
|
|
State(state): State<AppState>,
|
|
Path(id): Path<String>,
|
|
) -> impl IntoResponse {
|
|
let db = state.db.lock().await;
|
|
if let Err(e) = db.set_bot_active(&id, false) {
|
|
return (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response();
|
|
}
|
|
drop(db);
|
|
|
|
let mut manager = state.manager.lock().await;
|
|
manager.stop(&id).await;
|
|
|
|
StatusCode::OK.into_response()
|
|
}
|