188 lines
7.1 KiB
Rust
188 lines
7.1 KiB
Rust
use axum::{
|
|
Router,
|
|
extract::{DefaultBodyLimit, FromRef},
|
|
middleware,
|
|
routing::{get, post},
|
|
};
|
|
|
|
use crate::{
|
|
auth::{require_bearer_auth, require_runtime_principal_auth},
|
|
puzzle::{
|
|
advance_puzzle_next_level, claim_puzzle_work_point_incentive, create_puzzle_agent_session,
|
|
delete_puzzle_work, drag_puzzle_piece_or_group, execute_puzzle_agent_action,
|
|
generate_puzzle_onboarding_work, get_puzzle_agent_session, get_puzzle_gallery_detail,
|
|
get_puzzle_run, get_puzzle_work_detail, get_puzzle_works, list_puzzle_gallery,
|
|
put_puzzle_work, record_puzzle_gallery_like, remix_puzzle_gallery_work,
|
|
save_puzzle_onboarding_work, start_puzzle_run, stream_puzzle_agent_message,
|
|
submit_puzzle_agent_message, submit_puzzle_leaderboard, swap_puzzle_pieces,
|
|
update_puzzle_run_pause, use_puzzle_runtime_prop,
|
|
},
|
|
state::{AppState, PuzzleApiState},
|
|
};
|
|
|
|
const PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES: usize = 12 * 1024 * 1024;
|
|
|
|
pub fn router(state: AppState) -> Router<AppState> {
|
|
// 中文注释:拼图 handler 只接收 PuzzleApiState,鉴权层仍使用全局 AppState。
|
|
Router::new()
|
|
.route(
|
|
"/api/runtime/puzzle/agent/sessions",
|
|
post(create_puzzle_agent_session)
|
|
// 中文注释:拼图表单会携带单张参考图 Data URL,需只给该写入入口放宽 body 上限。
|
|
.layer(DefaultBodyLimit::max(
|
|
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
|
))
|
|
.route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/agent/sessions/{session_id}",
|
|
get(get_puzzle_agent_session).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/agent/sessions/{session_id}/messages",
|
|
post(submit_puzzle_agent_message).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/agent/sessions/{session_id}/messages/stream",
|
|
post(stream_puzzle_agent_message).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/agent/sessions/{session_id}/actions",
|
|
post(execute_puzzle_agent_action)
|
|
// 中文注释:生成草稿/重新出图会复用 referenceImageSrc,避免默认 2MB JSON limit 拦截。
|
|
.layer(DefaultBodyLimit::max(
|
|
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
|
))
|
|
.route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/onboarding/generate",
|
|
post(generate_puzzle_onboarding_work).layer(DefaultBodyLimit::max(
|
|
PUZZLE_REFERENCE_IMAGE_BODY_LIMIT_BYTES,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/onboarding/save",
|
|
post(save_puzzle_onboarding_work).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/works",
|
|
get(get_puzzle_works).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/works/{profile_id}",
|
|
get(get_puzzle_work_detail)
|
|
.put(put_puzzle_work)
|
|
.delete(delete_puzzle_work)
|
|
.route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/works/{profile_id}/point-incentive/claim",
|
|
post(claim_puzzle_work_point_incentive).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route("/api/runtime/puzzle/gallery", get(list_puzzle_gallery))
|
|
.route(
|
|
"/api/runtime/puzzle/gallery/{profile_id}",
|
|
get(get_puzzle_gallery_detail),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/gallery/{profile_id}/remix",
|
|
post(remix_puzzle_gallery_work).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/gallery/{profile_id}/like",
|
|
post(record_puzzle_gallery_like).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_bearer_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs",
|
|
post(start_puzzle_run).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}",
|
|
get(get_puzzle_run).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}/swap",
|
|
post(swap_puzzle_pieces).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}/drag",
|
|
post(drag_puzzle_piece_or_group).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}/next-level",
|
|
post(advance_puzzle_next_level).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}/pause",
|
|
post(update_puzzle_run_pause).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}/props",
|
|
post(use_puzzle_runtime_prop).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.route(
|
|
"/api/runtime/puzzle/runs/{run_id}/leaderboard",
|
|
post(submit_puzzle_leaderboard).route_layer(middleware::from_fn_with_state(
|
|
state.clone(),
|
|
require_runtime_principal_auth,
|
|
)),
|
|
)
|
|
.with_state(PuzzleApiState::from_ref(&state))
|
|
.with_state(state)
|
|
}
|