use actix::{Actor, Addr}; use actix_cors::Cors; use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer, Responder}; use actix_web_actors::ws; use crate::args::Args; use crate::data::{GameRules, PlayConfiguration}; use crate::dispatcher_actor::DispatcherActor; use crate::human_player_ws::{HumanPlayerWS, StartMode}; /// The default '/' route async fn index() -> impl Responder { HttpResponse::Ok().json("Sea battle backend") } /// The default 404 route async fn not_found() -> impl Responder { HttpResponse::NotFound().json("You missed your strike lol") } /// Get bot configuration async fn game_configuration() -> impl Responder { HttpResponse::Ok().json(PlayConfiguration::default()) } /// Start bot game async fn start_bot_play( req: HttpRequest, stream: web::Payload, query: web::Query, dispatcher: web::Data>, ) -> Result { let errors = query.0.get_errors(); if !errors.is_empty() { return Ok(HttpResponse::BadRequest().json(errors)); } let player_ws = HumanPlayerWS::new( StartMode::Bot(query.0.clone()), &dispatcher, "Human".to_string(), ); let resp = ws::start(player_ws, &req, stream); log::info!("New bot play with configuration: {:?}", &query.0); resp } /// Start game by creating invite async fn start_create_invite( req: HttpRequest, stream: web::Payload, query: web::Query, // TODO : add player name to query dispatcher: web::Data>, ) -> Result { let errors = query.0.get_errors(); if !errors.is_empty() { return Ok(HttpResponse::BadRequest().json(errors)); } let player_ws = HumanPlayerWS::new( StartMode::CreateInvite(query.0.clone()), &dispatcher, "Human".to_string(), ); let resp = ws::start(player_ws, &req, stream); log::info!("New create invite play with configuration: {:?}", &query.0); resp } #[derive(serde::Serialize, serde::Deserialize)] pub struct AcceptInviteQuery { pub code: String, // TODO : add player name to query } /// Start game by creating invite async fn start_accept_invite( req: HttpRequest, stream: web::Payload, query: web::Query, dispatcher: web::Data>, ) -> Result { let player_ws = HumanPlayerWS::new( StartMode::AcceptInvite { code: query.code.clone(), }, &dispatcher, "Human".to_string(), ); let resp = ws::start(player_ws, &req, stream); log::info!("New accept invite: {:?}", &query.0.code); resp } pub async fn start_server(args: Args) -> std::io::Result<()> { let args_clone = args.clone(); let dispatcher_actor = DispatcherActor::default().start(); HttpServer::new(move || { let mut cors = Cors::default(); match args_clone.cors.as_deref() { Some("*") => cors = cors.allow_any_origin(), Some(orig) => cors = cors.allowed_origin(orig), None => {} } App::new() .app_data(web::Data::new(dispatcher_actor.clone())) .wrap(cors) .route("/config", web::get().to(game_configuration)) .route("/play/bot", web::get().to(start_bot_play)) .route("/play/create_invite", web::get().to(start_create_invite)) .route("/play/accept_invite", web::get().to(start_accept_invite)) // TODO : join random .route("/", web::get().to(index)) .route("{tail:.*}", web::get().to(not_found)) }) .bind(&args.listen_address)? .run() .await }