use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::Duration;
use crate::messages::message::Message;
use crate::presence::packet::Packet;
use crate::protocol::json::Json;
pub struct RichClient {
pub client_id: u64,
#[cfg(target_os = "windows")]
pub pipe: Option<Arc<std::fs::File>>,
#[cfg(not(target_os = "windows"))]
pub read_pipe: Option<std::os::unix::net::UnixStream>,
#[cfg(not(target_os = "windows"))]
pub write_pipe: Option<std::os::unix::net::UnixStream>,
pub pid: u32,
pub is_ready: Arc<AtomicBool>,
pub thread_handle: Option<JoinHandle<()>>,
pub is_reconnecting: Arc<AtomicBool>,
}
pub trait Connection {
fn connect(client_id: u64) -> crate::Result<RichClient>;
fn close(&mut self);
fn start_read_thread(&mut self, tx: Sender<Message>) -> crate::Result<()>;
fn write(&self, opcode: u32, data: Option<&[u8]>) -> crate::Result<()>;
}
impl RichClient {
pub fn handshake(&self) -> crate::Result<()> {
self.write(
0,
Some(
format!("{{\"v\": 1,\"client_id\":\"{}\"}}", self.client_id)
.as_bytes(),
),
)
}
pub fn update(&self, packet: &Packet) -> crate::Result<()> {
let encoded = Json::serialize(packet)?;
match self.write(1, Some(encoded.as_bytes())) {
Err(_) => Err("The connection to Discord was lost".into()),
_ => Ok(()),
}
}
pub fn clear(&self) -> crate::Result<()> {
let packet = Packet::empty();
let encoded = Json::serialize(&packet)?;
match self.write(1, Some(encoded.as_bytes())) {
Err(_) => Err("The connection to Discord was lost".into()),
_ => Ok(()),
}
}
pub fn reconnect(
&mut self,
initial_interval: u64,
tx: Sender<Message>,
) -> crate::Result<()> {
self.is_reconnecting.store(true, Ordering::SeqCst);
self.close();
std::thread::sleep(Duration::from_millis(500));
while self.is_reconnecting.load(Ordering::SeqCst) {
if let Ok(mut client) = Self::connect(self.client_id) {
if client.handshake().is_ok() {
*self = client;
if let Err(e) = self.start_read_thread(tx) {
self.is_reconnecting.store(false, Ordering::SeqCst);
return Err(e);
};
break;
} else {
client.close();
}
};
std::thread::sleep(Duration::from_millis(initial_interval));
}
self.is_reconnecting.store(false, Ordering::SeqCst);
Ok(())
}
}