odyssey-server/src/network.rs

94 lines
2.1 KiB
Rust

use crate::game::PlayerConnected;
use crate::Game;
use actix::prelude::*;
use futures_util::StreamExt;
use std::collections::HashMap;
use std::net::SocketAddr;
use tokio::net::{TcpListener, TcpStream};
use tokio_tungstenite::WebSocketStream;
#[derive(Message)]
#[rtype(result = "()")]
struct TcpConnect(pub TcpStream, pub SocketAddr);
#[derive(Message)]
#[rtype(result = "()")]
struct WSConnect(pub WebSocketStream<TcpStream>, pub SocketAddr);
struct Connection {
stream: WebSocketStream<TcpStream>,
addr: SocketAddr,
conn_id: usize,
}
struct Server {
game: Addr<Game>,
connections: HashMap<usize, Connection>,
}
impl Actor for Server {
type Context = Context<Self>;
}
impl Server {
pub fn new(game: Addr<Game>) -> Self {
Server {
game,
connections: HashMap::new(),
}
}
}
/// Handle stream of TcpStream's
impl Handler<TcpConnect> for Server {
/// this is response for message, which is defined by `ResponseType` trait
/// in this case we just return unit.
type Result = ();
fn handle(&mut self, msg: TcpConnect, ctx: &mut Context<Self>) {
accept_websocket(msg)
.into_actor(self)
.then(move |res, act, _| {
// Assign random id to player
let conn_id = rand::random();
act.connections.insert(
conn_id,
Connection {
stream: res.0,
addr: res.1,
conn_id,
},
);
act.game
.send(PlayerConnected { conn_id })
.into_actor(act)
.then(move |_, act, _| async {}.into_actor(act))
})
.wait(ctx);
}
}
async fn accept_websocket(msg: TcpConnect) -> WSConnect {
let stream = tokio_tungstenite::accept_async(msg.0)
.await
.expect("Could not accept as websocket");
WSConnect(stream, msg.1)
}
pub async fn listen_websocket(bind: String, game: Addr<Game>) {
let try_socket = TcpListener::bind(&bind).await;
let listener = Box::new(try_socket.expect("Failed to bind"));
log::info!("Listening on: {}", bind);
Server::create(move |ctx| {
ctx.add_message_stream(Box::leak(listener).incoming().map(|st| {
let st = st.expect("could not accept socket");
let addr = st
.peer_addr()
.expect("could not retrieve connection address");
TcpConnect(st, addr)
}));
Server::new(game)
});
}