Model restructuring
* Remove old Command payload and replace with generic one. * Move Rich Presence model back to src/models. * Add Subscription command, Ready event and Error event models. * Add subscribe method to client and implement simple error detection.
This commit is contained in:
parent
a585bb6495
commit
95d748f211
|
@ -1,8 +1,21 @@
|
||||||
use connection::{Connection, SocketConnection};
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
use models::{Handshake, OpCode};
|
|
||||||
|
use connection::{
|
||||||
|
Connection,
|
||||||
|
SocketConnection,
|
||||||
|
};
|
||||||
|
use models::{
|
||||||
|
OpCode,
|
||||||
|
Command,
|
||||||
|
Event,
|
||||||
|
payload::Payload,
|
||||||
|
commands::{SubscriptionArgs, Subscription},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(feature = "rich_presence")]
|
#[cfg(feature = "rich_presence")]
|
||||||
use rich_presence::{SetActivityArgs, SetActivity};
|
use models::rich_presence::{SetActivityArgs, Activity};
|
||||||
use error::Result;
|
use error::{Result, Error};
|
||||||
|
use utils;
|
||||||
|
|
||||||
|
|
||||||
pub struct Client<T>
|
pub struct Client<T>
|
||||||
|
@ -10,14 +23,14 @@ pub struct Client<T>
|
||||||
{
|
{
|
||||||
client_id: u64,
|
client_id: u64,
|
||||||
version: u32,
|
version: u32,
|
||||||
socket: T,
|
connection: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Client<T>
|
impl<T> Client<T>
|
||||||
where T: Connection
|
where T: Connection
|
||||||
{
|
{
|
||||||
pub fn with_connection(client_id: u64, socket: T) -> Result<Self> {
|
pub fn with_connection(client_id: u64, connection: T) -> Result<Self> {
|
||||||
Ok(Self { version: 1, client_id, socket })
|
Ok(Self { version: 1, client_id, connection })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(mut self) -> Result<Self> {
|
pub fn start(mut self) -> Result<Self> {
|
||||||
|
@ -25,13 +38,30 @@ impl<T> Client<T>
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rich_presence")]
|
pub fn execute<A, E>(&mut self, cmd: Command, args: A, evt: Option<Event>) -> Result<Payload<E>>
|
||||||
pub fn set_activity<F>(&mut self, f: F) -> Result<()>
|
where A: Serialize,
|
||||||
where F: FnOnce(SetActivity) -> SetActivity
|
E: Serialize + DeserializeOwned
|
||||||
{
|
{
|
||||||
let args = SetActivityArgs::command(f(SetActivity::new()));
|
self.connection.send(OpCode::Frame, Payload::with_nonce(cmd, Some(args), None, evt))?;
|
||||||
self.socket.send(OpCode::Frame, args)?;
|
let response: Payload<E> = self.connection.recv()?.into();
|
||||||
Ok(())
|
|
||||||
|
match response.evt {
|
||||||
|
Some(Event::Error) => Err(Error::SubscriptionFailed),
|
||||||
|
_ => Ok(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rich_presence")]
|
||||||
|
pub fn set_activity<F>(&mut self, f: F) -> Result<Payload<Activity>>
|
||||||
|
where F: FnOnce(Activity) -> Activity
|
||||||
|
{
|
||||||
|
self.execute(Command::SetActivity, SetActivityArgs::new(f), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subscribe<F>(&mut self, evt: Event, f: F) -> Result<Payload<Subscription>>
|
||||||
|
where F: FnOnce(SubscriptionArgs) -> SubscriptionArgs
|
||||||
|
{
|
||||||
|
self.execute(Command::Subscribe, f(SubscriptionArgs::new()), Some(evt))
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
|
@ -39,7 +69,13 @@ impl<T> Client<T>
|
||||||
fn handshake(&mut self) -> Result<()> {
|
fn handshake(&mut self) -> Result<()> {
|
||||||
let client_id = self.client_id;
|
let client_id = self.client_id;
|
||||||
let version = self.version;
|
let version = self.version;
|
||||||
self.socket.send(OpCode::Handshake, Handshake::new(client_id, version))?;
|
let hs = json![{
|
||||||
|
"client_id": client_id.to_string(),
|
||||||
|
"v": version,
|
||||||
|
"nonce": utils::nonce()
|
||||||
|
}];
|
||||||
|
self.connection.send(OpCode::Handshake, hs)?;
|
||||||
|
self.connection.recv()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use std::{
|
use std::{
|
||||||
io::{Write, Read},
|
io::{Write, Read},
|
||||||
marker::Sized,
|
marker::Sized,
|
||||||
fmt::Debug,
|
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
use models::{Payload, Message, OpCode};
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use models::message::{Message, OpCode};
|
||||||
use error::Result;
|
use error::Result;
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,25 +27,25 @@ pub trait Connection
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<T>(&mut self, opcode: OpCode, payload: T) -> Result<()>
|
fn send<T>(&mut self, opcode: OpCode, payload: T) -> Result<()>
|
||||||
where T: Payload + Debug
|
where T: Serialize
|
||||||
{
|
{
|
||||||
debug!("payload: {:#?}", payload);
|
let message = Message::new(opcode, payload);
|
||||||
match Message::new(opcode, payload).encode() {
|
debug!("{:?}", message);
|
||||||
|
match message.encode() {
|
||||||
Err(why) => error!("{:?}", why),
|
Err(why) => error!("{:?}", why),
|
||||||
Ok(bytes) => {
|
Ok(bytes) => {
|
||||||
self.socket().write_all(bytes.as_ref())?;
|
self.socket().write_all(bytes.as_ref())?;
|
||||||
debug!("sent opcode: {:?}", opcode);
|
|
||||||
self.recv()?;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv(&mut self) -> Result<Vec<u8>> {
|
fn recv(&mut self) -> Result<Message> {
|
||||||
let mut buf: Vec<u8> = vec![0; 1024];
|
let mut buf: Vec<u8> = vec![0; 1024];
|
||||||
let n = self.socket().read(buf.as_mut_slice())?;
|
let n = self.socket().read(buf.as_mut_slice())?;
|
||||||
buf.resize(n, 0);
|
buf.resize(n, 0);
|
||||||
debug!("{:?}", Message::decode(&buf));
|
let message = Message::decode(&buf)?;
|
||||||
Ok(buf)
|
debug!("{:?}", message);
|
||||||
|
Ok(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use std::{
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Io(IoError),
|
Io(IoError),
|
||||||
Conversion,
|
Conversion,
|
||||||
|
SubscriptionFailed,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
|
@ -26,6 +27,7 @@ impl StdError for Error {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Conversion => "Failed to convert values",
|
Error::Conversion => "Failed to convert values",
|
||||||
|
Error::SubscriptionFailed => "Failed to subscribe to event",
|
||||||
Error::Io(ref err) => err.description()
|
Error::Io(ref err) => err.description()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
|
#[macro_use]
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
|
@ -15,12 +16,8 @@ mod macros;
|
||||||
mod error;
|
mod error;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod connection;
|
mod connection;
|
||||||
mod models;
|
pub mod models;
|
||||||
mod rich_presence;
|
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
|
||||||
pub use client::Client;
|
pub use client::Client;
|
||||||
#[cfg(feature = "rich_presence")]
|
|
||||||
pub use rich_presence::*;
|
|
||||||
pub use connection::{Connection, SocketConnection};
|
pub use connection::{Connection, SocketConnection};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
macro_rules! message_func {
|
macro_rules! builder_func {
|
||||||
[ $name:ident, $type:tt func ] => {
|
[ $name:ident, $type:tt func ] => {
|
||||||
pub fn $name<F>(mut self, func: F) -> Self
|
pub fn $name<F>(mut self, func: F) -> Self
|
||||||
where F: FnOnce($type) -> $type
|
where F: FnOnce($type) -> $type
|
||||||
|
@ -22,9 +22,9 @@ macro_rules! message_func {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! message_format {
|
macro_rules! builder {
|
||||||
[ @st ( $name:ident $field:tt: $type:tt alias = $alias:tt, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
[ @st ( $name:ident $field:tt: $type:tt alias = $alias:tt, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
||||||
message_format![ @st
|
builder![ @st
|
||||||
( $name $($rest)* ) -> (
|
( $name $($rest)* ) -> (
|
||||||
$($out)*
|
$($out)*
|
||||||
#[serde(skip_serializing_if = "Option::is_none", rename = $alias)]
|
#[serde(skip_serializing_if = "Option::is_none", rename = $alias)]
|
||||||
|
@ -34,11 +34,11 @@ macro_rules! message_format {
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @st ( $name:ident $field:tt: $type:tt func, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
[ @st ( $name:ident $field:tt: $type:tt func, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
||||||
message_format![ @st ( $name $field: $type, $($rest)* ) -> ( $($out)* ) ];
|
builder![ @st ( $name $field: $type, $($rest)* ) -> ( $($out)* ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @st ( $name:ident $field:ident: $type:ty, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
[ @st ( $name:ident $field:ident: $type:ty, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
||||||
message_format![ @st
|
builder![ @st
|
||||||
( $name $($rest)* ) -> (
|
( $name $($rest)* ) -> (
|
||||||
$($out)*
|
$($out)*
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
@ -48,20 +48,20 @@ macro_rules! message_format {
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @st ( $name:ident ) -> ( $($out:tt)* ) ] => {
|
[ @st ( $name:ident ) -> ( $($out:tt)* ) ] => {
|
||||||
#[derive(Debug, Default, Serialize)]
|
#[derive(Debug, Default, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct $name { $($out)* }
|
pub struct $name { $($out)* }
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @im ( $name:ident $field:ident: $type:tt func, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
[ @im ( $name:ident $field:ident: $type:tt func, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
||||||
message_format![ @im ( $name $($rest)* ) -> ( message_func![$field, $type func]; $($out)* ) ];
|
builder![ @im ( $name $($rest)* ) -> ( builder_func![$field, $type func]; $($out)* ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @im ( $name:ident $field:ident: $type:tt alias = $modifier:tt, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
[ @im ( $name:ident $field:ident: $type:tt alias = $modifier:tt, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
||||||
message_format![ @im ( $name $field: $type, $($rest)* ) -> ( $($out)* ) ];
|
builder![ @im ( $name $field: $type, $($rest)* ) -> ( $($out)* ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @im ( $name:ident $field:ident: $type:tt, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
[ @im ( $name:ident $field:ident: $type:tt, $($rest:tt)* ) -> ( $($out:tt)* ) ] => {
|
||||||
message_format![ @im ( $name $($rest)* ) -> ( message_func![$field, $type]; $($out)* ) ];
|
builder![ @im ( $name $($rest)* ) -> ( builder_func![$field, $type]; $($out)* ) ];
|
||||||
};
|
};
|
||||||
|
|
||||||
[ @im ( $name:ident ) -> ( $($out:tt)* ) ] => {
|
[ @im ( $name:ident ) -> ( $($out:tt)* ) ] => {
|
||||||
|
@ -75,7 +75,7 @@ macro_rules! message_format {
|
||||||
};
|
};
|
||||||
|
|
||||||
[ $name:ident $($body:tt)* ] => {
|
[ $name:ident $($body:tt)* ] => {
|
||||||
message_format![@st ( $name $($body)* ) -> () ];
|
builder![@st ( $name $($body)* ) -> () ];
|
||||||
message_format![@im ( $name $($body)* ) -> () ];
|
builder![@im ( $name $($body)* ) -> () ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
use serde::Serialize;
|
|
||||||
|
|
||||||
use super::Payload;
|
|
||||||
use utils::nonce;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize)]
|
|
||||||
pub struct Command<T>
|
|
||||||
where T: Serialize
|
|
||||||
{
|
|
||||||
pub nonce: String,
|
|
||||||
pub cmd: String,
|
|
||||||
pub args: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Command<T>
|
|
||||||
where T: Serialize
|
|
||||||
{
|
|
||||||
pub fn new<S>(cmd: S, args: T) -> Self
|
|
||||||
where S: Into<String>
|
|
||||||
{
|
|
||||||
Command {
|
|
||||||
cmd: cmd.into(),
|
|
||||||
nonce: nonce(),
|
|
||||||
args: args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Payload for Command<T>
|
|
||||||
where T: Serialize {}
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
use super::shared::PartialUser;
|
||||||
|
|
||||||
|
|
||||||
|
builder!{SubscriptionArgs
|
||||||
|
secret: String, // Activity{Join,Spectate}
|
||||||
|
user: PartialUser, // ActivityJoinRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
builder!{Subscription
|
||||||
|
evt: String,
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
use super::shared::PartialUser;
|
||||||
|
|
||||||
|
|
||||||
|
builder!{ReadyEvent
|
||||||
|
v: u32,
|
||||||
|
config: RpcServerConfiguration,
|
||||||
|
user: PartialUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
builder!{ErrorEvent
|
||||||
|
code: u32,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
builder!{RpcServerConfiguration
|
||||||
|
cdn_host: String,
|
||||||
|
api_endpoint: String,
|
||||||
|
environment: String,
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
use super::Payload;
|
|
||||||
use utils::nonce;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize)]
|
|
||||||
pub struct Handshake {
|
|
||||||
nonce: String,
|
|
||||||
v: u32,
|
|
||||||
client_id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Handshake {
|
|
||||||
pub fn new(client_id: u64, version: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
nonce: nonce(),
|
|
||||||
v: version,
|
|
||||||
client_id: client_id.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Payload for Handshake {}
|
|
|
@ -30,40 +30,42 @@ impl OpCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Message {
|
pub struct Message {
|
||||||
opcode: OpCode,
|
pub opcode: OpCode,
|
||||||
message: String,
|
pub payload: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
pub fn new<T>(opcode: OpCode, message: T) -> Self
|
pub fn new<T>(opcode: OpCode, payload: T) -> Self
|
||||||
where T: Serialize
|
where T: Serialize
|
||||||
{
|
{
|
||||||
Message {
|
Self { opcode, payload: serde_json::to_string(&payload).unwrap() }
|
||||||
opcode: opcode,
|
|
||||||
message: serde_json::to_string(&message).unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self) -> Result<Vec<u8>> {
|
pub fn encode(&self) -> Result<Vec<u8>> {
|
||||||
let mut bytes: Vec<u8> = vec![];
|
let mut bytes: Vec<u8> = vec![];
|
||||||
|
|
||||||
bytes.write_u32::<LittleEndian>(self.opcode as u32)?;
|
bytes.write_u32::<LittleEndian>(self.opcode as u32)?;
|
||||||
bytes.write_u32::<LittleEndian>(self.message.len() as u32)?;
|
bytes.write_u32::<LittleEndian>(self.payload.len() as u32)?;
|
||||||
write!(bytes, "{}", self.message)?;
|
write!(bytes, "{}", self.payload)?;
|
||||||
|
|
||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(bytes: &[u8]) -> Result<Self> {
|
pub fn decode(bytes: &[u8]) -> Result<Self> {
|
||||||
let mut reader = io::Cursor::new(bytes);
|
let mut reader = io::Cursor::new(bytes);
|
||||||
let mut message = String::new();
|
let mut payload = String::new();
|
||||||
|
|
||||||
let opcode = OpCode::try_from(reader.read_u32::<LittleEndian>()?)?;
|
let opcode = OpCode::try_from(reader.read_u32::<LittleEndian>()?)?;
|
||||||
reader.read_u32::<LittleEndian>()?;
|
reader.read_u32::<LittleEndian>()?;
|
||||||
reader.read_to_string(&mut message)?;
|
reader.read_to_string(&mut payload)?;
|
||||||
Ok(Message { opcode, message })
|
|
||||||
|
Ok(Self { opcode, payload })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,11 +1,57 @@
|
||||||
mod message;
|
mod shared;
|
||||||
mod command;
|
pub mod message;
|
||||||
mod handshake;
|
pub mod payload;
|
||||||
|
pub mod commands;
|
||||||
|
pub mod events;
|
||||||
|
pub mod rich_presence;
|
||||||
|
|
||||||
use serde::Serialize;
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum Command {
|
||||||
|
Dispatch,
|
||||||
|
Authorize,
|
||||||
|
Subscribe,
|
||||||
|
Unsubscribe,
|
||||||
|
#[cfg(feature = "rich_presence")]
|
||||||
|
SetActivity,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
|
||||||
|
pub enum Event {
|
||||||
|
Ready,
|
||||||
|
Error,
|
||||||
|
#[cfg(feature = "rich_presence")]
|
||||||
|
ActivityJoin,
|
||||||
|
#[cfg(feature = "rich_presence")]
|
||||||
|
ActivitySpectate,
|
||||||
|
#[cfg(feature = "rich_presence")]
|
||||||
|
ActivityJoinRequest,
|
||||||
|
}
|
||||||
|
|
||||||
pub use self::message::{Message, OpCode};
|
pub use self::message::{Message, OpCode};
|
||||||
pub use self::command::Command;
|
pub use self::commands::*;
|
||||||
pub use self::handshake::Handshake;
|
pub use self::events::*;
|
||||||
|
|
||||||
pub trait Payload: Serialize {}
|
#[cfg(feature = "rich_presence")]
|
||||||
|
pub use self::rich_presence::*;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use super::Command;
|
||||||
|
pub use super::Event;
|
||||||
|
#[cfg(feature = "rich_presence")]
|
||||||
|
pub use super::rich_presence::{
|
||||||
|
SetActivityArgs,
|
||||||
|
ActivityJoinEvent,
|
||||||
|
ActivitySpectateEvent,
|
||||||
|
ActivityJoinRequestEvent
|
||||||
|
};
|
||||||
|
pub use super::commands::{
|
||||||
|
SubscriptionArgs, Subscription
|
||||||
|
};
|
||||||
|
pub use super::events::{
|
||||||
|
ReadyEvent,
|
||||||
|
ErrorEvent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
use std::{
|
||||||
|
convert::From,
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde::{Serialize, de::DeserializeOwned};
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
use super::{Command, Event, Message};
|
||||||
|
use utils;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
|
pub struct Payload<T>
|
||||||
|
where T: Serialize
|
||||||
|
{
|
||||||
|
pub cmd: Command,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub args: Option<T>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub data: Option<T>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub evt: Option<Event>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub nonce: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Payload<T>
|
||||||
|
where T: Serialize
|
||||||
|
{
|
||||||
|
pub fn with_nonce(cmd: Command, args: Option<T>, data: Option<T>, evt: Option<Event>) -> Self {
|
||||||
|
Self { cmd, args, data, evt, nonce: Some(utils::nonce()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Message> for Payload<T>
|
||||||
|
where T: Serialize + DeserializeOwned
|
||||||
|
{
|
||||||
|
fn from(message: Message) -> Self {
|
||||||
|
serde_json::from_str(&message.payload).unwrap()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,54 +1,69 @@
|
||||||
use models::Command;
|
#![cfg(feature = "rich_presence")]
|
||||||
use utils::pid;
|
|
||||||
|
use super::shared::PartialUser;
|
||||||
|
use utils;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize)]
|
#[derive(Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct SetActivityArgs {
|
pub struct SetActivityArgs {
|
||||||
pid: i32,
|
pid: i32,
|
||||||
activity: SetActivity,
|
activity: Activity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SetActivityArgs {
|
impl SetActivityArgs {
|
||||||
pub fn command(args: SetActivity) -> Command<Self> {
|
pub fn new<F>(f: F) -> Self
|
||||||
Command::new("SET_ACTIVITY", Self {
|
where F: FnOnce(Activity) -> Activity
|
||||||
pid: pid(),
|
{
|
||||||
activity: args
|
Self { pid: utils::pid(), activity: f(Activity::new()) }
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message_format![SetActivity
|
builder!{ActivityJoinEvent
|
||||||
state: String,
|
secret: String,
|
||||||
details: String,
|
}
|
||||||
instance: bool,
|
|
||||||
timestamps: SetActivityTimestamps func,
|
|
||||||
assets: SetActivityAssets func,
|
|
||||||
party: SetActivityParty func,
|
|
||||||
secrets: SetActivitySecrets func,
|
|
||||||
];
|
|
||||||
|
|
||||||
message_format![SetActivityTimestamps
|
builder!{ActivitySpectateEvent
|
||||||
|
secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
builder!{ActivityJoinRequestEvent
|
||||||
|
user: PartialUser,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
builder!{Activity
|
||||||
|
state: String,
|
||||||
|
details: String,
|
||||||
|
instance: bool,
|
||||||
|
timestamps: ActivityTimestamps func,
|
||||||
|
assets: ActivityAssets func,
|
||||||
|
party: ActivityParty func,
|
||||||
|
secrets: ActivitySecrets func,
|
||||||
|
}
|
||||||
|
|
||||||
|
builder!{ActivityTimestamps
|
||||||
start: u32,
|
start: u32,
|
||||||
end: u32,
|
end: u32,
|
||||||
];
|
}
|
||||||
|
|
||||||
message_format![SetActivityAssets
|
builder!{ActivityAssets
|
||||||
large_image: String,
|
large_image: String,
|
||||||
large_text: String,
|
large_text: String,
|
||||||
small_image: String,
|
small_image: String,
|
||||||
small_text: String,
|
small_text: String,
|
||||||
];
|
}
|
||||||
|
|
||||||
message_format![SetActivityParty
|
builder!{ActivityParty
|
||||||
id: u32,
|
id: u32,
|
||||||
size: (u32, u32),
|
size: (u32, u32),
|
||||||
];
|
}
|
||||||
|
|
||||||
message_format![SetActivitySecrets
|
builder!{ActivitySecrets
|
||||||
join: String,
|
join: String,
|
||||||
spectate: String,
|
spectate: String,
|
||||||
game: String alias = "match",
|
game: String alias = "match",
|
||||||
];
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -86,7 +101,7 @@ r###"{
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_full_activity() {
|
fn test_serialize_full_activity() {
|
||||||
let activity = SetActivity::new()
|
let activity = Activity::new()
|
||||||
.state("rusting")
|
.state("rusting")
|
||||||
.details("detailed")
|
.details("detailed")
|
||||||
.instance(true)
|
.instance(true)
|
||||||
|
@ -113,7 +128,7 @@ r###"{
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialize_empty_activity() {
|
fn test_serialize_empty_activity() {
|
||||||
let activity = SetActivity::new();
|
let activity = Activity::new();
|
||||||
let json = serde_json::to_string(&activity).unwrap();
|
let json = serde_json::to_string(&activity).unwrap();
|
||||||
assert_eq![json, "{}"];
|
assert_eq![json, "{}"];
|
||||||
}
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
builder!{PartialUser
|
||||||
|
id: String,
|
||||||
|
username: String,
|
||||||
|
discriminator: String,
|
||||||
|
avatar: String,
|
||||||
|
}
|
|
@ -1,5 +0,0 @@
|
||||||
#![cfg(feature = "rich_presence")]
|
|
||||||
|
|
||||||
mod set_activity;
|
|
||||||
|
|
||||||
pub use self::set_activity::*;
|
|
Loading…
Reference in New Issue