-
Notifications
You must be signed in to change notification settings - Fork 20
/
ws.rs
114 lines (102 loc) · 3.1 KB
/
ws.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::lobby::Lobby;
use crate::messages::{ClientActorMessage, Connect, Disconnect, WsMessage};
use actix::{fut, ActorContext, ActorFuture, ContextFutureSpawner, WrapFuture};
use actix::{Actor, Addr, Running, StreamHandler};
use actix::{AsyncContext, Handler};
use actix_web_actors::ws;
use actix_web_actors::ws::Message::Text;
use std::time::{Duration, Instant};
use uuid::Uuid;
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);
pub struct WsConn {
room: Uuid,
lobby_addr: Addr<Lobby>,
hb: Instant,
id: Uuid,
}
impl WsConn {
pub fn new(room: Uuid, lobby: Addr<Lobby>) -> WsConn {
WsConn {
id: Uuid::new_v4(),
room,
hb: Instant::now(),
lobby_addr: lobby,
}
}
}
impl Actor for WsConn {
type Context = ws::WebsocketContext<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
self.hb(ctx);
let addr = ctx.address();
self.lobby_addr
.send(Connect {
addr: addr.recipient(),
lobby_id: self.room,
self_id: self.id,
})
.into_actor(self)
.then(|res, _, ctx| {
match res {
Ok(_res) => (),
_ => ctx.stop(),
}
fut::ready(())
})
.wait(ctx);
}
fn stopping(&mut self, _: &mut Self::Context) -> Running {
self.lobby_addr.do_send(Disconnect {
id: self.id,
room_id: self.room,
});
Running::Stop
}
}
impl WsConn {
fn hb(&self, ctx: &mut ws::WebsocketContext<Self>) {
ctx.run_interval(HEARTBEAT_INTERVAL, |act, ctx| {
if Instant::now().duration_since(act.hb) > CLIENT_TIMEOUT {
println!("Disconnecting failed heartbeat");
ctx.stop();
return;
}
ctx.ping(b"hi");
});
}
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WsConn {
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
match msg {
Ok(ws::Message::Ping(msg)) => {
self.hb = Instant::now();
ctx.pong(&msg);
}
Ok(ws::Message::Pong(_)) => {
self.hb = Instant::now();
}
Ok(ws::Message::Binary(bin)) => ctx.binary(bin),
Ok(ws::Message::Close(reason)) => {
ctx.close(reason);
ctx.stop();
}
Ok(ws::Message::Continuation(_)) => {
ctx.stop();
}
Ok(ws::Message::Nop) => (),
Ok(Text(s)) => self.lobby_addr.do_send(ClientActorMessage {
id: self.id,
msg: s,
room_id: self.room,
}),
Err(e) => std::panic::panic_any(e),
}
}
}
impl Handler<WsMessage> for WsConn {
type Result = ();
fn handle(&mut self, msg: WsMessage, ctx: &mut Self::Context) {
ctx.text(msg.0);
}
}