CryptoFox-Mukan-Edition/src/api/routes.rs
Mukan Erkin 5db9332157 feat(mse): unified header, testnet order tracking, bot restart on update
- 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>
2026-04-19 20:19:56 +03:00

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()
}
}