use std::{marker::Sized, path::PathBuf}; use bytes::BytesMut; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use crate::error::{Error, Result}; use crate::models::message::{Message, OpCode}; use crate::utils; #[async_trait::async_trait] pub trait Connection: Sized + Send { type Socket: AsyncWrite + AsyncRead + Unpin + Send; fn socket(&mut self) -> &mut Self::Socket; fn ipc_path() -> PathBuf; async fn connect() -> Result; async fn disconnect(self) -> Result<()>; fn socket_path(n: u8) -> PathBuf { Self::ipc_path().join(format!("discord-ipc-{}", n)) } async fn handshake(&mut self, client_id: u64) -> Result<()> { let hs = json![{ "client_id": client_id.to_string(), "v": 1, "nonce": utils::nonce() }]; self.send(Message::new(OpCode::Handshake, hs.clone())) .await?; self.recv().await?; Ok(()) } async fn ping(&mut self) -> Result { let message = Message::new(OpCode::Ping, json![{}]); self.send(message).await?; let response = self.recv().await?; Ok(response.opcode) } async fn send(&mut self, message: Message) -> Result<()> { let bytes = message.encode()?; match self.socket().write_all(bytes.as_ref()).await { Ok(()) => {} Err(e) => { return match e.kind() { std::io::ErrorKind::BrokenPipe => { Err(Error::ConnectionClosedWhileSending(message)) } _ => Err(e.into()), } } } debug!("-> {:?}", message); Ok(()) } async fn recv(&mut self) -> Result { let mut buf = BytesMut::new(); buf.resize(1024, 0); let n = match self.socket().read(&mut buf).await { Ok(n) => n, Err(e) => { return match e.kind() { std::io::ErrorKind::BrokenPipe => Err(Error::ConnectionClosed), _ => Err(e.into()), } } }; debug!("Received {} bytes", n); if n == 0 { return Err(Error::ConnectionClosed); } buf = buf.split_to(n); let message = Message::decode(&buf)?; debug!("<- {:?}", message); Ok(message) } }