mahjong_service/http_server/
admin.rs

1#![allow(clippy::await_holding_lock)]
2use crate::auth::AuthHandler;
3use crate::game_wrapper::{CreateGameOpts, GameWrapper};
4use crate::http_server::base::{get_lock, GamesManagerData};
5pub use crate::http_server::base::{DataSocketServer, DataStorage};
6use crate::service_error::{ResponseCommon, ServiceError};
7use actix_web::{get, post, web, HttpRequest, HttpResponse};
8use mahjong_core::GameId;
9use service_contracts::{
10    AdminGetGamesResponse, AdminPostAIContinueRequest, AdminPostBreakMeldRequest,
11    AdminPostClaimTileRequest, AdminPostCreateMeldRequest, AdminPostDiscardTileRequest,
12    AdminPostSayMahjongRequest,
13};
14
15#[get("/game")]
16async fn admin_get_games(storage: DataStorage, req: HttpRequest) -> ResponseCommon {
17    AuthHandler::new(&storage, &req).verify_admin()?;
18
19    let response: AdminGetGamesResponse = storage
20        .get_player_games(&None)
21        .await
22        .map_err(|_| ServiceError::Custom("Error getting games"))?;
23
24    Ok(HttpResponse::Ok().json(response))
25}
26
27#[post("/game")]
28async fn admin_post_game(
29    storage: DataStorage,
30    srv: DataSocketServer,
31    req: HttpRequest,
32) -> ResponseCommon {
33    AuthHandler::new(&storage, &req).verify_admin()?;
34
35    let new_game_opts = CreateGameOpts::default();
36    let game_wrapper = GameWrapper::from_new_game(&storage, srv, &new_game_opts)
37        .await
38        .map_err(|_| ServiceError::Custom("Error creating game"))?;
39
40    game_wrapper.handle_admin_new_game().await
41}
42
43#[get("/game/{game_id}")]
44async fn admin_get_game_by_id(
45    storage: DataStorage,
46    manager: GamesManagerData,
47    game_id: web::Path<String>,
48    req: HttpRequest,
49) -> ResponseCommon {
50    AuthHandler::new(&storage, &req).verify_admin()?;
51
52    get_lock!(manager, game_id);
53
54    let game = storage
55        .get_game(&game_id.to_string(), true)
56        .await
57        .map_err(|_| ServiceError::Custom("Error loading game"))?;
58
59    Ok(HttpResponse::Ok().json(game))
60}
61
62#[post("/game/{game_id}/sort-hands")]
63async fn admin_post_game_sort_hands(
64    manager: GamesManagerData,
65    storage: DataStorage,
66    game_id: web::Path<String>,
67    srv: DataSocketServer,
68    req: HttpRequest,
69) -> ResponseCommon {
70    AuthHandler::new(&storage, &req).verify_admin()?;
71
72    get_lock!(manager, game_id);
73
74    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
75
76    game_wrapper.handle_sort_hands().await
77}
78
79#[post("/game/{game_id}/draw-tile")]
80async fn admin_post_game_draw_tile(
81    manager: GamesManagerData,
82    storage: DataStorage,
83    game_id: web::Path<GameId>,
84    srv: DataSocketServer,
85    req: HttpRequest,
86) -> ResponseCommon {
87    AuthHandler::new(&storage, &req).verify_admin()?;
88
89    get_lock!(manager, game_id);
90
91    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
92
93    game_wrapper.handle_admin_draw_tile().await
94}
95
96#[post("/game/{game_id}/move-player")]
97async fn admin_post_game_move_player(
98    manager: GamesManagerData,
99    storage: DataStorage,
100    game_id: web::Path<String>,
101    srv: DataSocketServer,
102    req: HttpRequest,
103) -> ResponseCommon {
104    AuthHandler::new(&storage, &req).verify_admin()?;
105
106    get_lock!(manager, game_id);
107
108    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
109
110    game_wrapper.handle_admin_move_player().await
111}
112
113#[post("/game/{game_id}/break-meld")]
114async fn admin_post_game_break_meld(
115    manager: GamesManagerData,
116    storage: DataStorage,
117    body: web::Json<AdminPostBreakMeldRequest>,
118    game_id: web::Path<String>,
119    srv: DataSocketServer,
120    req: HttpRequest,
121) -> ResponseCommon {
122    AuthHandler::new(&storage, &req).verify_admin()?;
123
124    get_lock!(manager, game_id);
125
126    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
127
128    game_wrapper.handle_admin_break_meld(&body).await
129}
130
131#[post("/game/{game_id}/create-meld")]
132async fn admin_post_game_create_meld(
133    manager: GamesManagerData,
134    storage: DataStorage,
135    body: web::Json<AdminPostCreateMeldRequest>,
136    game_id: web::Path<String>,
137    srv: DataSocketServer,
138    req: HttpRequest,
139) -> ResponseCommon {
140    AuthHandler::new(&storage, &req).verify_admin()?;
141
142    get_lock!(manager, game_id);
143
144    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
145
146    game_wrapper.handle_admin_create_meld(&body).await
147}
148
149#[post("/game/{game_id}/discard-tile")]
150async fn admin_post_game_discard_tile(
151    manager: GamesManagerData,
152    storage: DataStorage,
153    body: web::Json<AdminPostDiscardTileRequest>,
154    game_id: web::Path<String>,
155    srv: DataSocketServer,
156    req: HttpRequest,
157) -> ResponseCommon {
158    AuthHandler::new(&storage, &req).verify_admin()?;
159
160    get_lock!(manager, game_id);
161
162    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
163
164    game_wrapper.handle_discard_tile_admin(&body.tile_id).await
165}
166
167#[post("/game/{game_id}/claim-tile")]
168async fn admin_post_game_claim_tile(
169    manager: GamesManagerData,
170    storage: DataStorage,
171    body: web::Json<AdminPostClaimTileRequest>,
172    game_id: web::Path<String>,
173    srv: DataSocketServer,
174    req: HttpRequest,
175) -> ResponseCommon {
176    AuthHandler::new(&storage, &req).verify_admin()?;
177
178    get_lock!(manager, game_id);
179
180    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
181
182    game_wrapper.handle_admin_claim_tile(&body.player_id).await
183}
184
185#[post("/game/{game_id}/ai-continue")]
186async fn admin_post_game_ai_continue(
187    manager: GamesManagerData,
188    storage: DataStorage,
189    game_id: web::Path<String>,
190    body: web::Json<AdminPostAIContinueRequest>,
191    srv: DataSocketServer,
192    req: HttpRequest,
193) -> ResponseCommon {
194    AuthHandler::new(&storage, &req).verify_admin()?;
195
196    get_lock!(manager, game_id);
197
198    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
199
200    game_wrapper.handle_admin_ai_continue(&body).await
201}
202
203#[post("/game/{game_id}/say-mahjong")]
204async fn admin_post_game_say_mahjong(
205    manager: GamesManagerData,
206    storage: DataStorage,
207    body: web::Json<AdminPostSayMahjongRequest>,
208    game_id: web::Path<String>,
209    srv: DataSocketServer,
210    req: HttpRequest,
211) -> ResponseCommon {
212    AuthHandler::new(&storage, &req).verify_admin()?;
213
214    get_lock!(manager, game_id);
215
216    let mut game_wrapper = GameWrapper::from_storage(&storage, &game_id, srv, None).await?;
217
218    game_wrapper.handle_admin_say_mahjong(&body.player_id).await
219}
220
221pub fn get_admin_scope() -> actix_web::Scope {
222    web::scope("/api/v1/admin")
223        .service(admin_get_game_by_id)
224        .service(admin_get_games)
225        .service(admin_post_game)
226        .service(admin_post_game_ai_continue)
227        .service(admin_post_game_break_meld)
228        .service(admin_post_game_claim_tile)
229        .service(admin_post_game_create_meld)
230        .service(admin_post_game_discard_tile)
231        .service(admin_post_game_draw_tile)
232        .service(admin_post_game_move_player)
233        .service(admin_post_game_say_mahjong)
234        .service(admin_post_game_sort_hands)
235}