From 53bab6857ee69e764d655f821da8d201e4f587ec Mon Sep 17 00:00:00 2001 From: Patrick Auernig Date: Thu, 22 Mar 2018 22:54:49 +0100 Subject: [PATCH] Add Connection trait and implement UnixConnection --- examples/discord_presence/src/main.rs | 3 +- src/client.rs | 58 ++++++------------------ src/connection/base.rs | 15 +++++++ src/connection/mod.rs | 8 ++++ src/connection/unix.rs | 65 +++++++++++++++++++++++++++ src/lib.rs | 6 ++- 6 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 src/connection/base.rs create mode 100644 src/connection/mod.rs create mode 100644 src/connection/unix.rs diff --git a/examples/discord_presence/src/main.rs b/examples/discord_presence/src/main.rs index 76db7a9..1e967f6 100644 --- a/examples/discord_presence/src/main.rs +++ b/examples/discord_presence/src/main.rs @@ -4,12 +4,13 @@ extern crate discord_rpc_client; use simplelog::*; use std::{thread, time}; use discord_rpc_client::Client as DiscordRPC; +use discord_rpc_client::UnixConnection as Connection; fn main() { TermLogger::init(LevelFilter::Debug, Config::default()).unwrap(); let mut drpc = - DiscordRPC::new(425407036495495169) + DiscordRPC::::new(425407036495495169) .and_then(|rpc| rpc.start()) .expect("Failed to start client"); diff --git a/src/client.rs b/src/client.rs index 0d5b6a5..67c29f0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,26 +1,24 @@ -use std::env; -use std::io::{Write, Read, Result}; -use std::os::unix::net::UnixStream; -use std::time; -use std::fmt::Debug; -use models::{Message, Handshake, Payload}; +use std::io::Result; +use connection::Connection; +use models::Handshake; #[cfg(feature = "rich_presence")] use models::{SetActivityArgs, SetActivity}; #[derive(Debug)] -pub struct Client { +pub struct Client + where T: Connection +{ client_id: u64, version: u32, - socket: UnixStream, + socket: T, } -impl Client { +impl Client + where T: Connection +{ pub fn new(client_id: u64) -> Result { - let connection_name = Self::ipc_path(); - let socket = UnixStream::connect(connection_name)?; - socket.set_write_timeout(Some(time::Duration::from_secs(30)))?; - socket.set_read_timeout(Some(time::Duration::from_secs(30)))?; - Ok(Self { version: 1, client_id, socket }) + let socket = T::connect()?; + Ok(Self { version: 1, client_id, socket}) } pub fn start(mut self) -> Result { @@ -33,7 +31,7 @@ impl Client { where F: FnOnce(SetActivity) -> SetActivity { let args = SetActivityArgs::command(f(SetActivity::new())); - self.send(1, args)?; + self.socket.send(1, args)?; Ok(()) } @@ -42,35 +40,7 @@ impl Client { fn handshake(&mut self) -> Result<()> { let client_id = self.client_id; let version = self.version; - self.send(0, Handshake::new(client_id, version))?; - Ok(()) - } - - fn ipc_path() -> String { - let tmp = env::var("XDG_RUNTIME_DIR").unwrap_or("/tmp".into()); - format!("{}/discord-ipc-0", tmp) - } - - fn send(&mut self, opcode: u32, payload: T) -> Result<()> - where T: Payload + Debug - { - debug!("payload: {:#?}", payload); - match Message::new(opcode, payload).encode() { - Err(why) => error!("{:?}", why), - Ok(bytes) => { - self.socket.write_all(bytes.as_ref())?; - debug!("sent opcode: {}", opcode); - self.receive()?; - } - }; - - Ok(()) - } - - fn receive(&mut self) -> Result<()> { - let mut buf: Vec = Vec::with_capacity(1024); - self.socket.read(buf.as_mut_slice())?; - debug!("{:?}", buf); + self.socket.send(0, Handshake::new(client_id, version))?; Ok(()) } } diff --git a/src/connection/base.rs b/src/connection/base.rs new file mode 100644 index 0000000..0a578e3 --- /dev/null +++ b/src/connection/base.rs @@ -0,0 +1,15 @@ +use std::io::Result; +use std::marker::Sized; +use std::fmt::Debug; +use models::Payload; + +pub trait Connection + where Self: Sized +{ + fn connect() -> Result; + + fn send(&mut self, opcode: u32, payload: T) -> Result<()> + where T: Payload + Debug; + + fn recv(&mut self) -> Result>; +} diff --git a/src/connection/mod.rs b/src/connection/mod.rs new file mode 100644 index 0000000..0b692f6 --- /dev/null +++ b/src/connection/mod.rs @@ -0,0 +1,8 @@ +mod base; + +#[cfg(unix)] +mod unix; + +pub use self::base::Connection; +#[cfg(unix)] +pub use self::unix::UnixConnection; diff --git a/src/connection/unix.rs b/src/connection/unix.rs new file mode 100644 index 0000000..ce843a2 --- /dev/null +++ b/src/connection/unix.rs @@ -0,0 +1,65 @@ +use std::os::unix::net::UnixStream; +use std::io::{Write, Read, Result}; +use std::time; +use std::path::PathBuf; +use std::env; +use std::fmt::Debug; +use models::Payload; + +use models::Message; +use super::base::Connection; + +pub struct UnixConnection { + socket: UnixStream, +} + +impl UnixConnection { + fn ipc_path() -> PathBuf { + let tmp = env::var("XDG_RUNTIME_DIR") + .or_else(|_| env::var("TMPDIR")) + .or_else(|_| { + match env::temp_dir().to_str() { + None => Err("Failed to convert temp_dir"), + Some(tmp) => Ok(tmp.to_string()) + } + }) + .unwrap_or("/tmp".to_string()); + PathBuf::from(tmp) + } + + fn socket_path(n: u8) -> PathBuf { + Self::ipc_path().join(format!("discord-ipc-{}", n)) + } +} + +impl Connection for UnixConnection { + fn connect() -> Result { + let connection_name = Self::socket_path(0); + let socket = UnixStream::connect(connection_name)?; + socket.set_write_timeout(Some(time::Duration::from_secs(30)))?; + socket.set_read_timeout(Some(time::Duration::from_secs(30)))?; + Ok(Self { socket }) + } + + fn send(&mut self, opcode: u32, payload: T) -> Result<()> + where T: Payload + Debug + { + debug!("payload: {:#?}", payload); + match Message::new(opcode, payload).encode() { + Err(why) => error!("{:?}", why), + Ok(bytes) => { + self.socket.write_all(bytes.as_ref())?; + debug!("sent opcode: {}", opcode); + self.recv()?; + } + }; + Ok(()) + } + + fn recv(&mut self) -> Result> { + let mut buf: Vec = Vec::with_capacity(1024); + self.socket.read(buf.as_mut_slice())?; + debug!("{:?}", buf); + Ok(buf) + } +} diff --git a/src/lib.rs b/src/lib.rs index 093a0f6..74a9854 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,8 +12,12 @@ extern crate uuid; #[macro_use] mod macros; +mod connection; mod models; pub mod client; -pub use models::prelude; pub use client::Client; +pub use models::prelude; + +#[cfg(unix)] +pub use connection::UnixConnection;