use std::sync::Arc;
use std::time::SystemTime;
use actix::clock::Duration;
use actix::{Actor, AsyncContext, Handler, StreamHandler};
use actix_web_actors::ws::{Message as WebsocketMessage, ProtocolError, WebsocketContext};
use serde_json::to_string as json_to_string;
use crate::communication::{
ProxyRequest, ProxyResponse, WebsocketCommand, WebsocketSignal, WrappedMessage,
};
use crate::server::client_manager::ClientManager;
pub struct WebsocketHandler {
last_ping: SystemTime,
client_manager: Arc<ClientManager>,
client_id: String,
}
impl WebsocketHandler {
pub fn new(client_manager: Arc<ClientManager>, client_id: String) -> Self {
WebsocketHandler {
last_ping: SystemTime::now(),
client_manager,
client_id,
}
}
}
impl Actor for WebsocketHandler {
type Context = WebsocketContext<Self>;
}
impl StreamHandler<Result<WebsocketMessage, ProtocolError>> for WebsocketHandler {
fn handle(
&mut self,
message: Result<WebsocketMessage, ProtocolError>,
ctx: &mut Self::Context,
) {
match message {
Ok(WebsocketMessage::Text(message)) => {
if let Ok(message) = serde_json::from_str::<WrappedMessage<ProxyResponse>>(&message)
{
if let Err(error) = self
.client_manager
.response(message.id.clone(), message.into_inner())
{
println!("Could not respond to message: {}", error);
}
}
}
Ok(WebsocketMessage::Ping(_)) => {
self.last_ping = SystemTime::now();
ctx.pong(&[]);
}
_ => {}
}
}
fn started(&mut self, ctx: &mut Self::Context) {
self.last_ping = SystemTime::now();
if let Err(error) = self
.client_manager
.register_client(self.client_id.clone(), ctx.address())
{
println!("Client could not be registered: {}", error);
ctx.close(None);
}
}
fn finished(&mut self, _: &mut Self::Context) {
if let Err(_) = self.client_manager.unregister_client(&self.client_id) {}
}
}
impl Handler<WrappedMessage<ProxyRequest>> for WebsocketHandler {
type Result = ();
fn handle(
&mut self,
msg: WrappedMessage<ProxyRequest>,
ctx: &mut Self::Context,
) -> Self::Result {
ctx.text(json_to_string(&msg).unwrap_or_default());
()
}
}
impl Handler<WebsocketCommand> for WebsocketHandler {
type Result = ();
fn handle(&mut self, command: WebsocketCommand, ctx: &mut Self::Context) -> Self::Result {
match command.0 {
WebsocketSignal::Close => {
ctx.close(None);
self.client_manager
.unregister_client(&self.client_id)
.unwrap_or_default();
}
WebsocketSignal::CheckPing => {
let ping_age = SystemTime::now()
.duration_since(self.last_ping)
.unwrap_or(Duration::from_secs(99))
.as_millis();
if ping_age > 1500 {
ctx.close(None);
self.client_manager
.unregister_client(&self.client_id)
.unwrap_or_default();
}
}
_ => {}
}
}
}