use std::{ marker::Sized, path::PathBuf, }; use bytes::BytesMut; use tokio::io::{AsyncWrite, AsyncRead, AsyncWriteExt, AsyncReadExt}; 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<()> { match message.encode() { Err(why) => error!("{:?}", why), Ok(bytes) => { self.socket().write_all(bytes.as_ref()).await?; } }; debug!("-> {:?}", message); Ok(()) } async fn recv(&mut self) -> Result { let mut buf = BytesMut::new(); buf.resize(1024, 0); let n = self.socket().read(&mut buf).await?; 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) } }