Added DiscordClient
This commit is contained in:
parent
fd3a4351c5
commit
4499858f40
2 changed files with 117 additions and 0 deletions
116
src/client/ipc.rs
Normal file
116
src/client/ipc.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use std::os::unix::net::UnixStream;
|
||||
use std::env::var;
|
||||
use std::error::Error;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||
use log::debug;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::models::client::{payload::Payload,
|
||||
payload::OpCode,
|
||||
commands::Commands};
|
||||
|
||||
pub struct DiscordClient {
|
||||
pub id: String,
|
||||
socket: Option<UnixStream>,
|
||||
}
|
||||
|
||||
impl DiscordClient {
|
||||
pub fn new(id: &str) -> Self {
|
||||
let mut client = Self {
|
||||
id: id.to_string(),
|
||||
socket: None,
|
||||
};
|
||||
|
||||
client.connect().expect("Could not connect to client. Is Discord running ?");
|
||||
client
|
||||
}
|
||||
|
||||
pub fn send_payload(&mut self, payload: Payload) -> Result<(u32, Value), Box<dyn Error>> {
|
||||
let payload = json!({
|
||||
"cmd": Commands::SetActivity.as_string(),
|
||||
"args": {
|
||||
"pid": std::process::id(),
|
||||
payload.event_name: payload.event_data,
|
||||
},
|
||||
"nonce": uuid::Uuid::new_v4().to_string(),
|
||||
});
|
||||
|
||||
Ok(self.send(payload, OpCode::MESSAGE as u8)?)
|
||||
}
|
||||
|
||||
fn socket(&mut self) -> &mut UnixStream {
|
||||
self.socket.as_mut().unwrap()
|
||||
}
|
||||
|
||||
fn connect(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
let path = self.fetch_process_pathbuf().join("discord-ipc-0");
|
||||
|
||||
match UnixStream::connect(&path) {
|
||||
Ok(socket) => {
|
||||
self.socket = Some(socket);
|
||||
|
||||
self.handshake().expect("Could not handshake.");
|
||||
}
|
||||
Err(_) => panic!("Could not connect to client. Is Discord running ?"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fetch_process_pathbuf(&mut self) -> PathBuf {
|
||||
let mut path = String::new();
|
||||
|
||||
for key in ["XDG_RUNTIME_DIR", "TMPDIR", "TMP"] {
|
||||
match var(key) {
|
||||
Ok(val) => {
|
||||
path = val;
|
||||
break;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
PathBuf::from(path)
|
||||
}
|
||||
|
||||
fn handshake(&mut self) -> Result<(u32, Value), Box<dyn Error>> {
|
||||
let payload = json!({ "v": 1, "client_id": self.id});
|
||||
|
||||
Ok(self.send(payload, OpCode::HANDSHAKE as u8)?)
|
||||
}
|
||||
|
||||
fn send(&mut self, payload: Value, opcode: u8) -> Result<(u32, Value), Box<dyn Error>> {
|
||||
let payload = payload.to_string();
|
||||
let mut data: Vec<u8> = Vec::new();
|
||||
|
||||
data.write_u32::<LittleEndian>(opcode as u32)?;
|
||||
data.write_u32::<LittleEndian>(payload.len() as u32)?;
|
||||
data.write_all(payload.as_bytes())?;
|
||||
|
||||
self.socket().write_all(&data)?;
|
||||
Ok(self.recv()?)
|
||||
}
|
||||
|
||||
fn recv(&mut self) -> Result<(u32, Value), Box<dyn Error>> {
|
||||
let mut buf = [0; 2048];
|
||||
|
||||
let byte_count = self.socket().read(&mut buf)?;
|
||||
let (op, payload) = self.extract_payload(&buf[..byte_count])?;
|
||||
let json_data = serde_json::from_str::<Value>(&payload)?;
|
||||
|
||||
debug!("{:?}", json_data);
|
||||
|
||||
Ok((op, json_data))
|
||||
}
|
||||
|
||||
fn extract_payload(&mut self, mut data: &[u8]) -> Result<(u32, String), Box<dyn Error>> {
|
||||
let opcode = data.read_u32::<LittleEndian>()?;
|
||||
let payload_len = data.read_u32::<LittleEndian>()? as usize;
|
||||
let mut payload = String::with_capacity(payload_len);
|
||||
data.read_to_string(&mut payload)?;
|
||||
|
||||
Ok((opcode, payload))
|
||||
}
|
||||
}
|
||||
1
src/client/mod.rs
Normal file
1
src/client/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod ipc;
|
||||
Loading…
Add table
Reference in a new issue