94 lines
2.1 KiB
Rust
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)
|
|
});
|
|
}
|