use parking_lot::RwLock;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use serde_json;
use std::sync::Arc;
use super::utils::*;
use super::prelude::*;
use bitflags::bitflags;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct BotGateway {
pub session_start_limit: SessionStartLimit,
pub shards: u64,
pub url: String,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
#[derive(Clone, Debug, Serialize)]
pub struct Activity {
pub application_id: Option<ApplicationId>,
pub assets: Option<ActivityAssets>,
pub details: Option<String>,
pub flags: Option<ActivityFlags>,
pub instance: Option<bool>,
#[serde(default = "ActivityType::default", rename = "type")]
pub kind: ActivityType,
pub name: String,
pub party: Option<ActivityParty>,
pub secrets: Option<ActivitySecrets>,
pub state: Option<String>,
pub emoji: Option<ActivityEmoji>,
pub timestamps: Option<ActivityTimestamps>,
pub url: Option<String>,
#[serde(skip_serializing)]
pub(crate) _nonexhaustive: (),
}
#[cfg(feature = "model")]
impl Activity {
pub fn playing(name: &str) -> Activity {
Activity {
application_id: None,
assets: None,
details: None,
flags: None,
instance: None,
kind: ActivityType::Playing,
name: name.to_string(),
party: None,
secrets: None,
state: None,
emoji: None,
timestamps: None,
url: None,
_nonexhaustive: (),
}
}
pub fn streaming(name: &str, url: &str) -> Activity {
Activity {
application_id: None,
assets: None,
details: None,
flags: None,
instance: None,
kind: ActivityType::Streaming,
name: name.to_string(),
party: None,
secrets: None,
state: None,
emoji: None,
timestamps: None,
url: Some(url.to_string()),
_nonexhaustive: (),
}
}
pub fn listening(name: &str) -> Activity {
Activity {
application_id: None,
assets: None,
details: None,
flags: None,
instance: None,
kind: ActivityType::Listening,
name: name.to_string(),
party: None,
secrets: None,
state: None,
emoji: None,
timestamps: None,
url: None,
_nonexhaustive: (),
}
}
}
impl<'de> Deserialize<'de> for Activity {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;
let application_id = match map.remove("application_id") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let assets = match map.remove("assets") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let details = match map.remove("details") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let flags = match map.remove("flags") {
Some(v) => serde_json::from_value::<Option<u64>>(v)
.map_err(DeError::custom)?
.map(ActivityFlags::from_bits_truncate),
None => None,
};
let instance = match map.remove("instance") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let kind = map.remove("type")
.and_then(|v| ActivityType::deserialize(v).ok())
.unwrap_or(ActivityType::Playing);
let name = map.remove("name")
.and_then(|v| String::deserialize(v).ok())
.unwrap_or_else(String::new);
let party = match map.remove("party") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let secrets = match map.remove("secrets") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let state = match map.remove("state") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let emoji = match map.remove("emoji") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let timestamps = match map.remove("timestamps") {
Some(v) => serde_json::from_value::<Option<_>>(v).map_err(DeError::custom)?,
None => None,
};
let url = map.remove("url")
.and_then(|v| serde_json::from_value::<String>(v).ok());
Ok(Activity {
application_id,
assets,
details,
flags,
instance,
kind,
name,
party,
secrets,
state,
emoji,
timestamps,
url,
_nonexhaustive: (),
})
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivityAssets {
pub large_image: Option<String>,
pub large_text: Option<String>,
pub small_image: Option<String>,
pub small_text: Option<String>,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
bitflags! {
#[derive(Deserialize, Serialize)]
pub struct ActivityFlags: u64 {
const INSTANCE = 0b001;
const JOIN = 0b010;
const SPECTATE = 0b011;
const JOIN_REQUEST = 0b100;
const SYNC = 0b101;
const PLAY = 0b110;
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivityParty {
pub id: Option<String>,
pub size: Option<[u64; 2]>,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivitySecrets {
pub join: Option<String>,
#[serde(rename = "match")]
pub match_: Option<String>,
pub spectate: Option<String>,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivityEmoji {
pub name: String,
pub id: Option<EmojiId>,
pub animated: Option<bool>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ActivityType {
Playing = 0,
Streaming = 1,
Listening = 2,
Custom = 4,
#[doc(hidden)]
__Nonexhaustive,
}
enum_number!(
ActivityType {
Playing,
Streaming,
Listening,
Custom,
}
);
impl ActivityType {
pub fn num(self) -> u64 {
use self::ActivityType::*;
match self {
Playing => 0,
Streaming => 1,
Listening => 2,
Custom => 4,
__Nonexhaustive => unreachable!(),
}
}
}
impl Default for ActivityType {
fn default() -> Self { ActivityType::Playing }
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Gateway {
pub url: String,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ClientStatus {
pub desktop: Option<OnlineStatus>,
pub mobile: Option<OnlineStatus>,
pub web: Option<OnlineStatus>,
}
#[derive(Clone, Debug)]
pub struct Presence {
pub activity: Option<Activity>,
pub client_status: Option<ClientStatus>,
pub last_modified: Option<u64>,
pub nick: Option<String>,
pub status: OnlineStatus,
pub user_id: UserId,
pub user: Option<Arc<RwLock<User>>>,
pub(crate) _nonexhaustive: (),
}
impl<'de> Deserialize<'de> for Presence {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Presence, D::Error> {
let mut map = JsonMap::deserialize(deserializer)?;
let mut user_map = map.remove("user")
.ok_or_else(|| DeError::custom("expected presence user"))
.and_then(JsonMap::deserialize)
.map_err(DeError::custom)?;
let (user_id, user) = if user_map.len() > 1 {
let user = User::deserialize(Value::Object(user_map))
.map_err(DeError::custom)?;
(user.id, Some(Arc::new(RwLock::new(user))))
} else {
let user_id = user_map
.remove("id")
.ok_or_else(|| DeError::custom("Missing presence user id"))
.and_then(UserId::deserialize)
.map_err(DeError::custom)?;
(user_id, None)
};
let activity = match map.remove("game") {
Some(v) => serde_json::from_value::<Option<Activity>>(v)
.map_err(DeError::custom)?,
None => None,
};
let client_status = match map.remove("client_status") {
Some(v) => {
serde_json::from_value::<Option<ClientStatus>>(v).map_err(DeError::custom)?
}
None => None,
};
let last_modified = match map.remove("last_modified") {
Some(v) => serde_json::from_value::<Option<u64>>(v)
.map_err(DeError::custom)?,
None => None,
};
let nick = match map.remove("nick") {
Some(v) => serde_json::from_value::<Option<String>>(v)
.map_err(DeError::custom)?,
None => None,
};
let status = map
.remove("status")
.ok_or_else(|| DeError::custom("expected presence status"))
.and_then(OnlineStatus::deserialize)
.map_err(DeError::custom)?;
Ok(Presence {
activity,
client_status,
last_modified,
nick,
status,
user,
user_id,
_nonexhaustive: (),
})
}
}
impl Serialize for Presence {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where S: Serializer {
#[derive(Serialize)]
struct UserId {
id: u64,
}
let mut state = serializer.serialize_struct("Presence", 5)?;
state.serialize_field("game", &self.activity)?;
state.serialize_field("client_status", &self.client_status)?;
state.serialize_field("last_modified", &self.last_modified)?;
state.serialize_field("nick", &self.nick)?;
state.serialize_field("status", &self.status)?;
if let Some(ref user) = self.user {
state.serialize_field("user", &*user.read())?;
} else {
state.serialize_field(
"user",
&UserId {
id: *self.user_id.as_u64(),
},
)?;
}
state.end()
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Ready {
pub guilds: Vec<GuildStatus>,
#[serde(default, serialize_with = "serialize_presences", deserialize_with = "deserialize_presences")]
pub presences: HashMap<UserId, Presence>,
#[serde(default, serialize_with = "serialize_private_channels", deserialize_with = "deserialize_private_channels")]
pub private_channels: HashMap<ChannelId, Channel>,
pub session_id: String,
pub shard: Option<[u64; 2]>,
#[serde(default, rename = "_trace")]
pub trace: Vec<String>,
pub user: CurrentUser,
#[serde(rename = "v")]
pub version: u64,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SessionStartLimit {
pub remaining: u64,
pub reset_after: u64,
pub total: u64,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivityTimestamps {
pub end: Option<u64>,
pub start: Option<u64>,
#[serde(skip)]
pub(crate) _nonexhaustive: (),
}