6ef4c40e29
Two-repo monorepo for an offline FUT backend inspired by SPT. openfut-core: game-independent REST API backend (Axum, SQLite, SQLx) - 19 API endpoints: auth, profiles, clubs, cards, packs, squads, objectives, SBCs, match rewards, NPC market, statistics - JSON-driven card/pack/objective/SBC data (fully moddable) - SQLx migrations, weighted pack generator, SBC validation engine - 5 integration tests passing openfut-bridge: FIFA 23 traffic proxy + reverse-engineering scaffold - Catch-all HTTP proxy with request capture to captures/ - Known-route mapper (FUT paths → Core API calls) - Placeholder responses for unknown endpoints - Admin endpoints: captures, unknown endpoint list - 4 unit tests passing cargo fmt ✓ cargo clippy -D warnings ✓ cargo test ✓ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
63 lines
1.8 KiB
Rust
63 lines
1.8 KiB
Rust
use axum::{
|
|
http::StatusCode,
|
|
response::{IntoResponse, Response},
|
|
Json,
|
|
};
|
|
use serde_json::json;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum AppError {
|
|
#[error("not found: {0}")]
|
|
NotFound(String),
|
|
|
|
#[error("bad request: {0}")]
|
|
BadRequest(String),
|
|
|
|
#[error("conflict: {0}")]
|
|
Conflict(String),
|
|
|
|
#[error("database error: {0}")]
|
|
Database(#[from] sqlx::Error),
|
|
|
|
#[error("internal error: {0}")]
|
|
Internal(#[from] anyhow::Error),
|
|
|
|
#[error("io error: {0}")]
|
|
Io(#[from] std::io::Error),
|
|
|
|
#[error("json error: {0}")]
|
|
Json(#[from] serde_json::Error),
|
|
}
|
|
|
|
impl IntoResponse for AppError {
|
|
fn into_response(self) -> Response {
|
|
let (status, message) = match &self {
|
|
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
|
|
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
|
|
AppError::Conflict(msg) => (StatusCode::CONFLICT, msg.clone()),
|
|
AppError::Database(e) => {
|
|
tracing::error!("Database error: {e}");
|
|
(StatusCode::INTERNAL_SERVER_ERROR, "database error".into())
|
|
}
|
|
AppError::Internal(e) => {
|
|
tracing::error!("Internal error: {e}");
|
|
(
|
|
StatusCode::INTERNAL_SERVER_ERROR,
|
|
"internal server error".into(),
|
|
)
|
|
}
|
|
AppError::Io(e) => {
|
|
tracing::error!("IO error: {e}");
|
|
(StatusCode::INTERNAL_SERVER_ERROR, "io error".into())
|
|
}
|
|
AppError::Json(e) => (StatusCode::BAD_REQUEST, format!("json parse error: {e}")),
|
|
};
|
|
|
|
let body = Json(json!({ "error": message }));
|
|
(status, body).into_response()
|
|
}
|
|
}
|
|
|
|
pub type AppResult<T> = Result<T, AppError>;
|