use chrono::Local;
use crate::player::PlayerState;
use rocket::response::NamedFile;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::collections::VecDeque;
use std::fmt::{self, Debug, Formatter};
use std::path::{Path, PathBuf};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use std::vec::Vec;
use std::{io, thread};
use ws::{CloseCode, Handler, Handshake, Message, Result};
pub trait Communication {
fn read_message(&mut self) -> (u32, String);
fn send_message(&self, token: &u32, message: &str, state: &PlayerState);
fn send_message_from(&self, token: &u32, from: &str, bg: &str, fg: &str, message: &str, level: i32);
fn send_messages(&self, token: &u32, messages: &Vec<String>, state: &PlayerState);
fn disconnect(&mut self, token: &u32);
fn get_identifier(&self, token: &u32) -> String;
}
impl Debug for dyn Communication {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "Debug required for RefCell")
}
}
pub struct ChannelCommunication {
send: mpsc::Sender<(u32, String)>,
read: mpsc::Receiver<(u32, String)>,
to_send: Option<mpsc::Sender<(u32, String)>>,
messages: HashMap<u32, Vec<String>>,
expected: i32,
can_log: bool,
}
impl ChannelCommunication {
pub fn new(can_log: bool) -> ChannelCommunication {
let (send, read) = mpsc::channel();
ChannelCommunication {
send,
read,
to_send: None,
messages: HashMap::new(),
can_log,
expected: 0,
}
}
pub fn bind(left: &mut ChannelCommunication, right: &mut ChannelCommunication) {
right.to_send = Some(left.send.clone());
left.to_send = Some(right.send.clone());
}
fn add_message(&mut self, token: u32, msg: String) {
if !self.messages.contains_key(&token) {
self.messages.insert(token, Vec::new());
}
let message = self.messages.get_mut(&token).unwrap();
message.push(msg.clone());
}
pub fn read_all(&mut self) {
while self.expected > 0 {
thread::sleep(Duration::from_millis(500));
while let Ok((token, msg)) = self.read.try_recv() {
self.add_message(token.clone(), msg.clone());
if self.can_log {
println!("client|{}|{}{}|{}", Local::now(), ">", &token, &msg);
}
self.expected -= 1;
}
}
}
pub fn last(&self, token: u32) -> String {
let msg = self
.messages
.get(&token)
.expect("Token does not exist for last")
.last()
.expect("Messages does not have last element");
let json: Value = serde_json::from_str(&*msg).expect("Not valid JSON");
let msg = json["message"]
.as_str()
.expect("Message is not string")
.to_string();
msg
}
pub fn last_bg(&self, token: u32) -> String {
let msg = self
.messages
.get(&token)
.expect("Token does not exist for last")
.last()
.expect("Messages does not have last element");
let json: Value = serde_json::from_str(&*msg).expect("Not valid JSON");
let bg = json["bg"]
.as_str()
.expect("Message is not string")
.to_string();
bg
}
pub fn last_fg(&self, token: u32) -> String {
let msg = self
.messages
.get(&token)
.expect("Token does not exist for last")
.last()
.expect("Messages does not have last element");
let json: Value = serde_json::from_str(&*msg).expect("Not valid JSON");
let fg = json["fg"]
.as_str()
.expect("Message is not string")
.to_string();
fg
}
pub fn last_from(&self, token: u32) -> String {
let msg = self
.messages
.get(&token)
.expect("Token does not exist for last")
.last()
.expect("Messages does not have last element");
let json: Value = serde_json::from_str(&*msg).expect("Not valid JSON");
let from = json["from"]
.as_str()
.expect("Message is not string")
.to_string();
from
}
pub fn last_state(&self, token: u32) -> String {
let msg = self
.messages
.get(&token)
.expect("Token does not exist for last")
.last()
.expect("Messages does not have last element");
let json: Value = serde_json::from_str(&*msg).expect("Not valid JSON");
let msg = json["state"]
.as_str()
.expect("State is not string")
.to_string();
msg
}
pub fn thrust(&mut self, token: u32) {
self.send(token.clone(), ".t 1");
self.send(token.clone(), ".t 1 1");
self.send(token.clone(), ".t 1 1 1");
self.send(token.clone(), ".t 1 1 1 1");
self.send(token.clone(), ".t 1 1 1 1 1");
}
pub fn send(&mut self, token: u32, msg: &str) {
self.send_message(&token, msg, &PlayerState::ChooseName);
if self.can_log {
println!("client|{}|{}{}|{}", Local::now(), &token, ">", &msg);
}
if self.expected < 0 {
self.expected = 0;
}
self.expected += 1;
}
}
impl Communication for ChannelCommunication {
fn read_message(&mut self) -> (u32, String) {
let (token, msg) = self.read.recv().expect("Failed to send message.");
let json: Value = serde_json::from_str(&*msg).expect("Not valid JSON");
let msg = json["message"]
.as_str()
.expect("Received message is not string")
.to_string();
(token, msg)
}
fn send_message(&self, token: &u32, message: &str, state: &PlayerState) {
let msg = json!({
"bg": "000",
"fg": "b7410e",
"from": "THRUSTY",
"message": message,
"state": state.to_string()
})
.to_string();
self.to_send
.as_ref()
.expect("to_send not set")
.send((token.clone(), msg))
.expect("Failed to send message.");
}
fn send_message_from(&self, token: &u32, from: &str, bg: &str, fg: &str, message: &str, level: i32) {
let msg = json!({
"bg": bg,
"fg": fg,
"from": from,
"message": message,
"level": level
})
.to_string();
self.to_send
.as_ref()
.expect("to_send not set")
.send((token.clone(), msg))
.expect("Failed to send message.");
}
fn send_messages(&self, token: &u32, messages: &Vec<String>, state: &PlayerState) {
let message = messages.join("<br/>");
self.send_message(token, &message, state);
}
fn get_identifier(&self, token: &u32) -> String {
token.to_string()
}
fn disconnect(&mut self, _token: &u32) {
self.to_send = None;
}
}
#[get("/")]
fn index() -> io::Result<NamedFile> {
NamedFile::open("../frontend/build/index.html")
}
#[get("/<file..>")]
fn file(file: PathBuf) -> Option<NamedFile> {
NamedFile::open(Path::new("../frontend/build/").join(file)).ok()
}
struct WebSocketListener {
out: ws::Sender,
connections: Arc<Mutex<HashMap<u32, (String, ws::Sender)>>>,
send: mpsc::Sender<(u32, String)>,
uuid: u32,
}
impl Handler for WebSocketListener {
fn on_open(&mut self, handshake: Handshake) -> Result<()> {
let mut ip_addr = String::new();
if let Ok(remote_addr) = handshake.remote_addr() {
if let Some(remote_addr) = remote_addr {
ip_addr = remote_addr
}
}
let mut connections_lock = self.connections.lock().unwrap();
connections_lock.insert(self.uuid, (ip_addr, self.out.clone()));
Ok(())
}
fn on_message(&mut self, msg: Message) -> Result<()> {
self.send
.send((self.uuid, msg.to_string()))
.expect("Unable to send on message");
Ok(())
}
fn on_close(&mut self, code: CloseCode, reason: &str) {
let mut connections_lock = self.connections.lock().unwrap();
connections_lock.remove(&self.uuid).unwrap();
match code {
CloseCode::Normal => self
.send
.send((
self.uuid,
format!(".disconnect CloseCode::Normal {}", reason),
))
.expect("Unable to sent disconnect Normal"),
CloseCode::Away => self
.send
.send((self.uuid, format!(".disconnect CloseCode::Away {}", reason)))
.expect("Unable to send disconnect Away"),
_ => self
.send
.send((self.uuid, format!(".disconnect Error {}", reason)))
.expect("Unable to send disconnect Error"),
};
}
}
#[derive(Debug)]
pub struct WebSocketCommunication {
commands: Arc<Mutex<VecDeque<(u32, String)>>>,
connections: Arc<Mutex<HashMap<u32, (String, ws::Sender)>>>,
send: mpsc::Sender<(u32, String)>,
recv: mpsc::Receiver<(u32, String)>,
uuid: Arc<Mutex<u32>>,
}
impl WebSocketCommunication {
pub fn new() -> WebSocketCommunication {
let (sender, receiver) = std::sync::mpsc::channel();
let communication = WebSocketCommunication {
commands: Arc::new(Mutex::new(VecDeque::new())),
connections: Arc::new(Mutex::new(HashMap::new())),
send: sender,
recv: receiver,
uuid: Arc::new(Mutex::new(1)),
};
communication.spawn();
communication
}
fn spawn(&self) {
if cfg!(debug_assertions) {
thread::spawn(|| {
rocket::ignite().mount("/", routes![index, file]).launch();
});
}
let connections_clone = Arc::clone(&self.connections);
let send_clone = self.send.clone();
let uuid_clone = Arc::clone(&self.uuid);
thread::spawn(move || {
ws::listen("0.0.0.0:3012", |out| WebSocketListener {
out: out,
connections: connections_clone.clone(),
send: send_clone.clone(),
uuid: {
let mut uuid_lock = uuid_clone.lock().unwrap();
let uuid = uuid_lock.clone();
*uuid_lock += 1;
uuid
},
})
.unwrap()
});
}
}
impl Communication for WebSocketCommunication {
fn read_message(&mut self) -> (u32, String) {
match self.recv.recv() {
Ok((token, message)) => {
let connections_lock = self.connections.lock().unwrap();
if let Some((ip_addr, _)) = connections_lock.get(&token) {
println!(
"{}|{}|{}{}|{}",
Local::now(),
ip_addr,
&token,
">",
&message
);
}
else {
println!("{}|_|{}{}|{}", Local::now(), &token, ">", &message);
}
(token, message)
}
Err(_) => {
println!("{}|_|_|{}|_", Local::now(), ">");
println!("Catastrophic failure if this fails probably.");
(0, "".to_string())
}
}
}
fn send_message(&self, token: &u32, message: &str, state: &PlayerState) {
let msg = json!({
"bg": "000",
"fg": "b7410e",
"from": "THRUSTY",
"message": message,
"state": state.to_string()
})
.to_string();
let connections_lock = self.connections.lock().unwrap();
if let Some((ip_addr, sender)) = connections_lock.get(&token) {
sender.send(&*msg).unwrap();
println!("{}|{}|{}{}|{}", Local::now(), ip_addr, ">", token, msg);
}
}
fn send_message_from(&self, token: &u32, from: &str, bg: &str, fg: &str, message: &str, level: i32) {
let msg = json!({
"bg": bg,
"fg": fg,
"from": from,
"message": message,
"level": level
})
.to_string();
let connections_lock = self.connections.lock().unwrap();
if let Some((ip_addr, sender)) = connections_lock.get(&token) {
sender.send(&*msg).unwrap();
println!("{}|{}|{}{}|{}", Local::now(), ip_addr, ">", token, msg);
}
}
fn send_messages(&self, token: &u32, messages: &Vec<String>, state: &PlayerState) {
let message = messages.join("<br/>");
self.send_message(token, &message, state);
}
fn get_identifier(&self, token: &u32) -> String {
let connections_lock = self.connections.lock().unwrap();
if let Some((ip_addr, _)) = connections_lock.get(&token) {
ip_addr.clone()
} else {
String::new()
}
}
fn disconnect(&mut self, token: &u32) {
let connections_lock = self.connections.lock().unwrap();
if let Some((_ip_addr, sender)) = connections_lock.get(&token) {
match sender.close(CloseCode::Normal) {
_ => {}
};
}
}
}