implement PlayerRouter
This commit is contained in:
parent
90ecb13a17
commit
d0faec7d1f
1 changed files with 45 additions and 26 deletions
|
@ -2,8 +2,8 @@ pub mod pb {
|
||||||
tonic::include_proto!("grpc.planetwars.bot_api");
|
tonic::include_proto!("grpc.planetwars.bot_api");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::ops::DerefMut;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
@ -23,7 +23,35 @@ use crate::{ConnectionPool, MAPS_DIR, MATCHES_DIR};
|
||||||
use super::matches::code_bundle_to_botspec;
|
use super::matches::code_bundle_to_botspec;
|
||||||
|
|
||||||
pub struct BotApiServer {
|
pub struct BotApiServer {
|
||||||
sync_thing: ServerSyncThing,
|
router: PlayerRouter,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Routes players to their handler
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PlayerRouter {
|
||||||
|
routing_table: Arc<Mutex<HashMap<String, SyncThingData>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlayerRouter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
PlayerRouter {
|
||||||
|
routing_table: Arc::new(Mutex::new(HashMap::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement a way to expire entries
|
||||||
|
impl PlayerRouter {
|
||||||
|
fn put(&self, player_id: String, entry: SyncThingData) {
|
||||||
|
let mut routing_table = self.routing_table.lock().unwrap();
|
||||||
|
routing_table.insert(player_id, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, player_id: &str) -> Option<SyncThingData> {
|
||||||
|
// TODO: this design does not allow for reconnects. Is this desired?
|
||||||
|
let mut routing_table = self.routing_table.lock().unwrap();
|
||||||
|
routing_table.remove(player_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
|
@ -36,7 +64,8 @@ impl pb::bot_api_service_server::BotApiService for BotApiServer {
|
||||||
) -> Result<Response<Self::ConnectBotStream>, Status> {
|
) -> Result<Response<Self::ConnectBotStream>, Status> {
|
||||||
println!("bot connected");
|
println!("bot connected");
|
||||||
let stream = req.into_inner();
|
let stream = req.into_inner();
|
||||||
let sync_data = self.sync_thing.streams.lock().unwrap().take().unwrap();
|
// TODO: return error when player does not exist
|
||||||
|
let sync_data = self.router.get("test_player").unwrap();
|
||||||
sync_data.tx.send(stream).unwrap();
|
sync_data.tx.send(stream).unwrap();
|
||||||
Ok(Response::new(UnboundedReceiverStream::new(
|
Ok(Response::new(UnboundedReceiverStream::new(
|
||||||
sync_data.server_messages,
|
sync_data.server_messages,
|
||||||
|
@ -44,26 +73,13 @@ impl pb::bot_api_service_server::BotApiService for BotApiServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
struct ServerSyncThing {
|
|
||||||
streams: Arc<Mutex<Option<SyncThingData>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SyncThingData {
|
struct SyncThingData {
|
||||||
tx: oneshot::Sender<Streaming<pb::PlayerRequestResponse>>,
|
tx: oneshot::Sender<Streaming<pb::PlayerRequestResponse>>,
|
||||||
server_messages: mpsc::UnboundedReceiver<Result<pb::PlayerRequest, Status>>,
|
server_messages: mpsc::UnboundedReceiver<Result<pb::PlayerRequest, Status>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerSyncThing {
|
|
||||||
fn new() -> Self {
|
|
||||||
ServerSyncThing {
|
|
||||||
streams: Arc::new(Mutex::new(None)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RemoteBotSpec {
|
struct RemoteBotSpec {
|
||||||
sync_thing: ServerSyncThing,
|
router: PlayerRouter,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
|
@ -76,10 +92,13 @@ impl runner::BotSpec for RemoteBotSpec {
|
||||||
) -> Box<dyn PlayerHandle> {
|
) -> Box<dyn PlayerHandle> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let (server_msg_snd, server_msg_recv) = mpsc::unbounded_channel();
|
let (server_msg_snd, server_msg_recv) = mpsc::unbounded_channel();
|
||||||
*self.sync_thing.streams.lock().unwrap().deref_mut() = Some(SyncThingData {
|
self.router.put(
|
||||||
tx,
|
"test_player".to_string(),
|
||||||
server_messages: server_msg_recv,
|
SyncThingData {
|
||||||
});
|
tx,
|
||||||
|
server_messages: server_msg_recv,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
let client_messages = rx.await.unwrap();
|
let client_messages = rx.await.unwrap();
|
||||||
tokio::spawn(handle_bot_messages(player_id, event_bus, client_messages));
|
tokio::spawn(handle_bot_messages(player_id, event_bus, client_messages));
|
||||||
|
@ -119,7 +138,7 @@ impl PlayerHandle for RemoteBotHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_match(sync_thing: ServerSyncThing, pool: ConnectionPool) {
|
async fn run_match(router: PlayerRouter, pool: ConnectionPool) {
|
||||||
let conn = pool.get().await.unwrap();
|
let conn = pool.get().await.unwrap();
|
||||||
|
|
||||||
let opponent = db::bots::find_bot_by_name("simplebot", &conn).unwrap();
|
let opponent = db::bots::find_bot_by_name("simplebot", &conn).unwrap();
|
||||||
|
@ -127,7 +146,7 @@ async fn run_match(sync_thing: ServerSyncThing, pool: ConnectionPool) {
|
||||||
|
|
||||||
let log_file_name = "remote_match.log";
|
let log_file_name = "remote_match.log";
|
||||||
|
|
||||||
let remote_bot_spec = RemoteBotSpec { sync_thing };
|
let remote_bot_spec = RemoteBotSpec { router };
|
||||||
|
|
||||||
let match_config = runner::MatchConfig {
|
let match_config = runner::MatchConfig {
|
||||||
map_path: PathBuf::from(MAPS_DIR).join("hex.json"),
|
map_path: PathBuf::from(MAPS_DIR).join("hex.json"),
|
||||||
|
@ -147,9 +166,9 @@ async fn run_match(sync_thing: ServerSyncThing, pool: ConnectionPool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_bot_api(pool: ConnectionPool) {
|
pub async fn run_bot_api(pool: ConnectionPool) {
|
||||||
let sync_thing = ServerSyncThing::new();
|
let router = PlayerRouter::new();
|
||||||
tokio::spawn(run_match(sync_thing.clone(), pool));
|
tokio::spawn(run_match(router.clone(), pool));
|
||||||
let server = BotApiServer { sync_thing };
|
let server = BotApiServer { router };
|
||||||
|
|
||||||
let addr = SocketAddr::from(([127, 0, 0, 1], 50051));
|
let addr = SocketAddr::from(([127, 0, 0, 1], 50051));
|
||||||
Server::builder()
|
Server::builder()
|
||||||
|
|
Loading…
Reference in a new issue