- Ortak header yapısı: logo sol, nav orta (Dashboard/Botlar/Pozisyonlar), mode+çıkış sağ — index.html, bots.html, bot.html hepsinde aynı - positions.html eklendi (yeni /positions sayfası) - runner.rs: 30s periyodik order status sorgusu — FILLED/CANCELED pozisyonları closed_positions'a taşır, open_positions'dan siler - update_bot: çalışan bot varsa durdur + yeni config ile yeniden başlat - initChart guard: çift grafik oluşmasını engeller - routes.rs: /positions route eklendi, unused import temizlendi Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
123 lines
4.1 KiB
Rust
123 lines
4.1 KiB
Rust
use axum::{
|
|
extract::State,
|
|
middleware,
|
|
response::{IntoResponse, Redirect},
|
|
routing::{get, post},
|
|
Router,
|
|
};
|
|
use axum_extra::extract::CookieJar;
|
|
|
|
use crate::api::{auth, bots, events, mode, positions};
|
|
use crate::AppState;
|
|
|
|
pub fn build(state: AppState) -> Router {
|
|
let protected_api = Router::new()
|
|
.route("/symbols", get(bots::list_symbols))
|
|
.route("/bots", get(bots::list_bots).post(bots::create_bot))
|
|
.route("/bots/:id", get(bots::get_bot).delete(bots::delete_bot).put(bots::update_bot))
|
|
.route("/bots/:id/start", post(bots::start_bot))
|
|
.route("/bots/:id/stop", post(bots::stop_bot))
|
|
.route("/bots/:id/logs", get(bots::get_bot_logs))
|
|
.route("/bots/:id/positions", get(bots::get_bot_positions))
|
|
.route("/bots/:id/positions/closed", get(bots::get_bot_closed))
|
|
.route("/bots/:id/log-stream", get(events::bot_log_sse))
|
|
.route("/positions", get(positions::open_positions))
|
|
.route("/positions/closed", get(positions::closed_positions))
|
|
.route("/mode", get(mode::get_mode).post(mode::set_mode))
|
|
.route("/events", get(events::sse_handler))
|
|
.layer(middleware::from_fn_with_state(state.clone(), auth::require_auth));
|
|
|
|
let api = Router::new()
|
|
.route("/auth/login", post(auth::login))
|
|
.route("/auth/logout", post(auth::logout))
|
|
.merge(protected_api);
|
|
|
|
Router::new()
|
|
.nest("/api", api)
|
|
.route("/", get(login_handler))
|
|
.route("/dashboard", get(dashboard_handler))
|
|
.route("/bots", get(bots_handler))
|
|
.route("/bots/:id", get(bot_detail_handler))
|
|
.route("/positions", get(positions_handler))
|
|
.with_state(state)
|
|
}
|
|
|
|
async fn login_handler(
|
|
State(state): State<AppState>,
|
|
jar: CookieJar,
|
|
) -> impl IntoResponse {
|
|
let token = jar.get("mse_session").map(|c| c.value().to_string());
|
|
let authed = match token {
|
|
Some(t) => {
|
|
let db = state.db.lock().await;
|
|
db.session_exists(&t).unwrap_or(false)
|
|
}
|
|
None => false,
|
|
};
|
|
if authed {
|
|
Redirect::to("/dashboard").into_response()
|
|
} else {
|
|
axum::response::Html(include_str!("../web/login.html")).into_response()
|
|
}
|
|
}
|
|
|
|
async fn bots_handler(
|
|
State(state): State<AppState>,
|
|
jar: CookieJar,
|
|
) -> impl IntoResponse {
|
|
let token = jar.get("mse_session").map(|c| c.value().to_string());
|
|
let authed = match token {
|
|
Some(t) => { let db = state.db.lock().await; db.session_exists(&t).unwrap_or(false) }
|
|
None => false,
|
|
};
|
|
if authed { axum::response::Html(include_str!("../web/bots.html")).into_response() }
|
|
else { Redirect::to("/").into_response() }
|
|
}
|
|
|
|
async fn positions_handler(
|
|
State(state): State<AppState>,
|
|
jar: CookieJar,
|
|
) -> impl IntoResponse {
|
|
let token = jar.get("mse_session").map(|c| c.value().to_string());
|
|
let authed = match token {
|
|
Some(t) => { let db = state.db.lock().await; db.session_exists(&t).unwrap_or(false) }
|
|
None => false,
|
|
};
|
|
if authed { axum::response::Html(include_str!("../web/positions.html")).into_response() }
|
|
else { Redirect::to("/").into_response() }
|
|
}
|
|
|
|
async fn bot_detail_handler(
|
|
State(state): State<AppState>,
|
|
jar: CookieJar,
|
|
) -> impl IntoResponse {
|
|
let token = jar.get("mse_session").map(|c| c.value().to_string());
|
|
let authed = match token {
|
|
Some(t) => { let db = state.db.lock().await; db.session_exists(&t).unwrap_or(false) }
|
|
None => false,
|
|
};
|
|
if authed {
|
|
axum::response::Html(include_str!("../web/bot.html")).into_response()
|
|
} else {
|
|
Redirect::to("/").into_response()
|
|
}
|
|
}
|
|
|
|
async fn dashboard_handler(
|
|
State(state): State<AppState>,
|
|
jar: CookieJar,
|
|
) -> impl IntoResponse {
|
|
let token = jar.get("mse_session").map(|c| c.value().to_string());
|
|
let authed = match token {
|
|
Some(t) => {
|
|
let db = state.db.lock().await;
|
|
db.session_exists(&t).unwrap_or(false)
|
|
}
|
|
None => false,
|
|
};
|
|
if authed {
|
|
axum::response::Html(include_str!("../web/index.html")).into_response()
|
|
} else {
|
|
Redirect::to("/").into_response()
|
|
}
|
|
}
|