rename bot_api to client_api

This commit is contained in:
Ilion Beyst 2022-07-25 22:16:50 +02:00
parent 93c4306b10
commit 67276bd0bb
8 changed files with 93 additions and 80 deletions

View file

@ -4,6 +4,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure() tonic_build::configure()
.build_server(false) .build_server(false)
.build_client(true) .build_client(true)
.compile(&["../proto/bot_api.proto"], &["../proto"])?; .compile(&["../proto/client_api.proto"], &["../proto"])?;
Ok(()) Ok(())
} }

View file

@ -1,9 +1,12 @@
pub mod pb { pub mod pb {
tonic::include_proto!("grpc.planetwars.bot_api"); tonic::include_proto!("grpc.planetwars.client_api");
pub use player_api_client_message::ClientMessage as PlayerApiClientMessageType;
pub use player_api_server_message::ServerMessage as PlayerApiServerMessageType;
} }
use clap::Parser; use clap::Parser;
use pb::bot_api_service_client::BotApiServiceClient; use pb::client_api_service_client::ClientApiServiceClient;
use planetwars_matchrunner::bot_runner::Bot; use planetwars_matchrunner::bot_runner::Bot;
use serde::Deserialize; use serde::Deserialize;
use std::{path::PathBuf, time::Duration}; use std::{path::PathBuf, time::Duration};
@ -77,16 +80,19 @@ async fn main() {
tokio::time::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
} }
async fn create_match(channel: Channel, opponent_name: String) -> Result<pb::CreatedMatch, Status> { async fn create_match(
let mut client = BotApiServiceClient::new(channel); channel: Channel,
opponent_name: String,
) -> Result<pb::CreateMatchResponse, Status> {
let mut client = ClientApiServiceClient::new(channel);
let res = client let res = client
.create_match(Request::new(pb::MatchRequest { opponent_name })) .create_match(Request::new(pb::CreateMatchRequest { opponent_name }))
.await; .await;
res.map(|response| response.into_inner()) res.map(|response| response.into_inner())
} }
async fn run_player(bot_config: BotConfig, player_key: String, channel: Channel) { async fn run_player(bot_config: BotConfig, player_key: String, channel: Channel) {
let mut client = BotApiServiceClient::with_interceptor(channel, |mut req: Request<()>| { let mut client = ClientApiServiceClient::with_interceptor(channel, |mut req: Request<()>| {
let player_key: MetadataValue<_> = player_key.parse().unwrap(); let player_key: MetadataValue<_> = player_key.parse().unwrap();
req.metadata_mut().insert("player_key", player_key); req.metadata_mut().insert("player_key", player_key);
Ok(req) Ok(req)
@ -109,18 +115,15 @@ async fn run_player(bot_config: BotConfig, player_key: String, channel: Channel)
.unwrap() .unwrap()
.into_inner(); .into_inner();
while let Some(message) = stream.message().await.unwrap() { while let Some(message) = stream.message().await.unwrap() {
use pb::client_message::ClientMessage;
use pb::server_message::ServerMessage;
match message.server_message { match message.server_message {
Some(ServerMessage::PlayerRequest(req)) => { Some(pb::PlayerApiServerMessageType::ActionRequest(req)) => {
let moves = bot_process.communicate(&req.content).await.unwrap(); let moves = bot_process.communicate(&req.content).await.unwrap();
let resp = pb::PlayerRequestResponse { let action = pb::PlayerAction {
request_id: req.request_id, action_request_id: req.action_request_id,
content: moves.as_bytes().to_vec(), content: moves.as_bytes().to_vec(),
}; };
let msg = pb::ClientMessage { let msg = pb::PlayerApiClientMessage {
client_message: Some(ClientMessage::RequestResponse(resp)), client_message: Some(pb::PlayerApiClientMessageType::Action(action)),
}; };
tx.send(msg).unwrap(); tx.send(msg).unwrap();
} }

View file

@ -4,6 +4,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure() tonic_build::configure()
.build_server(true) .build_server(true)
.build_client(false) .build_client(false)
.compile(&["../proto/bot_api.proto"], &["../proto"])?; .compile(&["../proto/client_api.proto"], &["../proto"])?;
Ok(()) Ok(())
} }

View file

@ -17,7 +17,7 @@ use bb8::{Pool, PooledConnection};
use bb8_diesel::{self, DieselConnectionManager}; use bb8_diesel::{self, DieselConnectionManager};
use config::ConfigError; use config::ConfigError;
use diesel::{Connection, PgConnection}; use diesel::{Connection, PgConnection};
use modules::bot_api::run_bot_api; use modules::client_api::run_client_api;
use modules::ranking::run_ranker; use modules::ranking::run_ranker;
use modules::registry::registry_service; use modules::registry::registry_service;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -172,7 +172,7 @@ pub async fn run_app() {
tokio::spawn(run_ranker(global_config.clone(), db_pool.clone())); tokio::spawn(run_ranker(global_config.clone(), db_pool.clone()));
} }
tokio::spawn(run_registry(global_config.clone(), db_pool.clone())); tokio::spawn(run_registry(global_config.clone(), db_pool.clone()));
tokio::spawn(run_bot_api(global_config.clone(), db_pool.clone())); tokio::spawn(run_client_api(global_config.clone(), db_pool.clone()));
let api_service = Router::new() let api_service = Router::new()
.nest("/api", api()) .nest("/api", api())

View file

@ -1,5 +1,8 @@
pub mod pb { pub mod pb {
tonic::include_proto!("grpc.planetwars.bot_api"); tonic::include_proto!("grpc.planetwars.client_api");
pub use player_api_client_message::ClientMessage as PlayerApiClientMessageType;
pub use player_api_server_message::ServerMessage as PlayerApiServerMessageType;
} }
use std::collections::HashMap; use std::collections::HashMap;
@ -24,7 +27,7 @@ use crate::GlobalConfig;
use super::matches::{MatchPlayer, RunMatch}; use super::matches::{MatchPlayer, RunMatch};
pub struct BotApiServer { pub struct ClientApiServer {
conn_pool: ConnectionPool, conn_pool: ConnectionPool,
runner_config: Arc<GlobalConfig>, runner_config: Arc<GlobalConfig>,
router: PlayerRouter, router: PlayerRouter,
@ -65,12 +68,12 @@ impl PlayerRouter {
} }
#[tonic::async_trait] #[tonic::async_trait]
impl pb::bot_api_service_server::BotApiService for BotApiServer { impl pb::client_api_service_server::ClientApiService for ClientApiServer {
type ConnectPlayerStream = UnboundedReceiverStream<Result<pb::ServerMessage, Status>>; type ConnectPlayerStream = UnboundedReceiverStream<Result<pb::PlayerApiServerMessage, Status>>;
async fn connect_player( async fn connect_player(
&self, &self,
req: Request<Streaming<pb::ClientMessage>>, req: Request<Streaming<pb::PlayerApiClientMessage>>,
) -> Result<Response<Self::ConnectPlayerStream>, Status> { ) -> Result<Response<Self::ConnectPlayerStream>, Status> {
// TODO: clean up errors // TODO: clean up errors
let player_key = req let player_key = req
@ -97,8 +100,8 @@ impl pb::bot_api_service_server::BotApiService for BotApiServer {
async fn create_match( async fn create_match(
&self, &self,
req: Request<pb::MatchRequest>, req: Request<pb::CreateMatchRequest>,
) -> Result<Response<pb::CreatedMatch>, Status> { ) -> Result<Response<pb::CreateMatchResponse>, Status> {
// TODO: unify with matchrunner module // TODO: unify with matchrunner module
let conn = self.conn_pool.get().await.unwrap(); let conn = self.conn_pool.get().await.unwrap();
@ -131,7 +134,7 @@ impl pb::bot_api_service_server::BotApiService for BotApiServer {
.await .await
.expect("failed to create match"); .expect("failed to create match");
Ok(Response::new(pb::CreatedMatch { Ok(Response::new(pb::CreateMatchResponse {
match_id: created_match.base.id, match_id: created_match.base.id,
player_key, player_key,
// TODO: can we avoid hardcoding this? // TODO: can we avoid hardcoding this?
@ -145,8 +148,8 @@ impl pb::bot_api_service_server::BotApiService for BotApiServer {
// TODO: please rename me // TODO: please rename me
struct SyncThingData { struct SyncThingData {
tx: oneshot::Sender<Streaming<pb::ClientMessage>>, tx: oneshot::Sender<Streaming<pb::PlayerApiClientMessage>>,
server_messages: mpsc::UnboundedReceiver<Result<pb::ServerMessage, Status>>, server_messages: mpsc::UnboundedReceiver<Result<pb::PlayerApiServerMessage, Status>>,
} }
struct RemoteBotSpec { struct RemoteBotSpec {
@ -203,13 +206,13 @@ impl runner::BotSpec for RemoteBotSpec {
async fn handle_bot_messages( async fn handle_bot_messages(
player_id: u32, player_id: u32,
event_bus: Arc<Mutex<EventBus>>, event_bus: Arc<Mutex<EventBus>>,
mut messages: Streaming<pb::ClientMessage>, mut messages: Streaming<pb::PlayerApiClientMessage>,
) { ) {
// TODO: can this be writte nmore nicely? // TODO: can this be writte nmore nicely?
while let Some(message) = messages.message().await.unwrap() { while let Some(message) = messages.message().await.unwrap() {
match message.client_message { match message.client_message {
Some(pb::client_message::ClientMessage::RequestResponse(resp)) => { Some(pb::PlayerApiClientMessageType::Action(resp)) => {
let request_id = (player_id, resp.request_id as u32); let request_id = (player_id, resp.action_request_id as u32);
event_bus event_bus
.lock() .lock()
.unwrap() .unwrap()
@ -221,20 +224,20 @@ async fn handle_bot_messages(
} }
struct RemoteBotHandle { struct RemoteBotHandle {
sender: mpsc::UnboundedSender<Result<pb::ServerMessage, Status>>, sender: mpsc::UnboundedSender<Result<pb::PlayerApiServerMessage, Status>>,
player_id: u32, player_id: u32,
event_bus: Arc<Mutex<EventBus>>, event_bus: Arc<Mutex<EventBus>>,
} }
impl PlayerHandle for RemoteBotHandle { impl PlayerHandle for RemoteBotHandle {
fn send_request(&mut self, r: RequestMessage) { fn send_request(&mut self, r: RequestMessage) {
let req = pb::PlayerRequest { let req = pb::PlayerActionRequest {
request_id: r.request_id as i32, action_request_id: r.request_id as i32,
content: r.content, content: r.content,
}; };
let server_message = pb::ServerMessage { let server_message = pb::PlayerApiServerMessage {
server_message: Some(pb::server_message::ServerMessage::PlayerRequest(req)), server_message: Some(pb::PlayerApiServerMessageType::ActionRequest(req)),
}; };
let res = self.sender.send(Ok(server_message)); let res = self.sender.send(Ok(server_message));
@ -282,9 +285,9 @@ async fn schedule_timeout(
.resolve_request(request_id, Err(RequestError::Timeout)); .resolve_request(request_id, Err(RequestError::Timeout));
} }
pub async fn run_bot_api(runner_config: Arc<GlobalConfig>, pool: ConnectionPool) { pub async fn run_client_api(runner_config: Arc<GlobalConfig>, pool: ConnectionPool) {
let router = PlayerRouter::new(); let router = PlayerRouter::new();
let server = BotApiServer { let server = ClientApiServer {
router, router,
conn_pool: pool, conn_pool: pool,
runner_config, runner_config,
@ -292,7 +295,9 @@ pub async fn run_bot_api(runner_config: Arc<GlobalConfig>, pool: ConnectionPool)
let addr = SocketAddr::from(([127, 0, 0, 1], 50051)); let addr = SocketAddr::from(([127, 0, 0, 1], 50051));
Server::builder() Server::builder()
.add_service(pb::bot_api_service_server::BotApiServiceServer::new(server)) .add_service(pb::client_api_service_server::ClientApiServiceServer::new(
server,
))
.serve(addr) .serve(addr)
.await .await
.unwrap() .unwrap()

View file

@ -1,7 +1,7 @@
// This module implements general domain logic, not directly // This module implements general domain logic, not directly
// tied to the database or API layers. // tied to the database or API layers.
pub mod bot_api;
pub mod bots; pub mod bots;
pub mod client_api;
pub mod matches; pub mod matches;
pub mod ranking; pub mod ranking;
pub mod registry; pub mod registry;

View file

@ -1,40 +0,0 @@
syntax = "proto3";
package grpc.planetwars.bot_api;
message ServerMessage {
oneof server_message {
PlayerRequest player_request = 1;
}
}
message PlayerRequest {
int32 request_id = 1;
bytes content = 2;
}
message ClientMessage {
oneof client_message {
PlayerRequestResponse request_response = 1;
}
}
message PlayerRequestResponse {
int32 request_id = 1;
bytes content = 2;
}
message MatchRequest {
string opponent_name = 1;
}
message CreatedMatch {
int32 match_id = 1;
string player_key = 2;
string match_url = 3;
}
service BotApiService {
rpc CreateMatch(MatchRequest) returns (CreatedMatch);
// server sends requests to the player, player responds
rpc ConnectPlayer(stream ClientMessage) returns (stream ServerMessage);
}

45
proto/client_api.proto Normal file
View file

@ -0,0 +1,45 @@
syntax = "proto3";
package grpc.planetwars.client_api;
// Provides the planetwars client API, allowing for remote play.
service ClientApiService {
rpc CreateMatch(CreateMatchRequest) returns (CreateMatchResponse);
rpc ConnectPlayer(stream PlayerApiClientMessage) returns (stream PlayerApiServerMessage);
}
message CreateMatchRequest {
string opponent_name = 1;
}
message CreateMatchResponse {
int32 match_id = 1;
string player_key = 2;
string match_url = 3;
}
// Server messages
message PlayerApiServerMessage {
oneof server_message {
PlayerActionRequest action_request = 1;
}
}
message PlayerActionRequest {
int32 action_request_id = 1;
bytes content = 2;
}
// Player messages
message PlayerApiClientMessage {
oneof client_message {
PlayerAction action = 1;
}
}
message PlayerAction {
int32 action_request_id = 1;
bytes content = 2;
}