1pub mod events;
4
5use crate::{Command, CommandKind, Error};
6use serde::Serialize;
7
8#[derive(Serialize)]
9struct OverlayToggle {
10 pid: u32,
13 #[serde(rename = "locked")]
14 visibility: Visibility,
15}
16
17impl OverlayToggle {
18 fn new(visibility: Visibility) -> Self {
19 Self {
20 pid: std::process::id(),
21 visibility,
22 }
23 }
24}
25
26#[derive(Copy, Clone, Debug, PartialEq, Eq)]
27pub enum Visibility {
28 Visible,
29 Hidden,
30}
31
32impl Serialize for Visibility {
33 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34 where
35 S: serde::Serializer,
36 {
37 serializer.serialize_bool(!(*self == Self::Visible))
38 }
39}
40
41impl<'de> serde::Deserialize<'de> for Visibility {
42 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
43 where
44 D: serde::Deserializer<'de>,
45 {
46 use serde::de;
47
48 struct Visitor;
49
50 impl de::Visitor<'_> for Visitor {
51 type Value = Visibility;
52
53 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 formatter.write_str("a boolean")
55 }
56
57 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
58 where
59 E: de::Error,
60 {
61 Ok(if value {
62 Visibility::Hidden
63 } else {
64 Visibility::Visible
65 })
66 }
67 }
68
69 deserializer.deserialize_bool(Visitor)
70 }
71}
72
73#[derive(Copy, Clone, PartialEq, Eq, serde_repr::Serialize_repr)]
74#[repr(u8)]
75pub enum InviteAction {
76 Join = 1,
77 Spectate = 2,
78}
79
80#[derive(Serialize)]
81pub(crate) struct OverlayPidArgs {
82 pid: u32,
83}
84
85impl OverlayPidArgs {
86 pub(crate) fn new() -> Self {
87 Self {
88 pid: std::process::id(),
89 }
90 }
91}
92
93impl crate::Discord {
94 pub async fn set_overlay_visibility(&self, visibility: Visibility) -> Result<(), Error> {
99 let rx = self.send_rpc(
100 CommandKind::SetOverlayVisibility,
101 OverlayToggle::new(visibility),
102 )?;
103
104 handle_response!(rx, Command::SetOverlayVisibility => {
105 Ok(())
106 })
107 }
108
109 pub async fn open_activity_invite(&self, action: InviteAction) -> Result<(), Error> {
120 #[derive(Serialize)]
121 struct OpenInviteModal {
122 pid: u32,
125 #[serde(rename = "type")]
126 kind: InviteAction,
127 }
128
129 let rx = self.send_rpc(
130 CommandKind::OpenOverlayActivityInvite,
131 OpenInviteModal {
132 pid: std::process::id(),
133 kind: action,
134 },
135 )?;
136
137 handle_response!(rx, Command::OpenOverlayActivityInvite => {
138 Ok(())
139 })
140 }
141
142 pub async fn open_guild_invite(&self, code: impl AsRef<str>) -> Result<(), Error> {
151 let mut code = code.as_ref();
152
153 if let Some(rest) = code.strip_prefix("https://") {
154 code = rest;
155 }
156
157 if let Some(rest) = code.strip_prefix("discord.gg/") {
158 code = rest;
159 } else if let Some(rest) = code.strip_prefix("discordapp.com/invite/") {
160 code = rest;
161 }
162
163 #[derive(Serialize)]
164 struct OpenGuildInviteModal<'stack> {
165 pid: u32,
166 code: &'stack str,
167 }
168
169 let rx = self.send_rpc(
170 CommandKind::OpenOverlayGuildInvite,
171 OpenGuildInviteModal {
172 pid: std::process::id(),
173 code,
174 },
175 )?;
176
177 handle_response!(rx, Command::OpenOverlayGuildInvite => {
178 Ok(())
179 })
180 }
181
182 pub async fn open_voice_settings(&self) -> Result<(), Error> {
186 let rx = self.send_rpc(CommandKind::OpenOverlayVoiceSettings, OverlayPidArgs::new())?;
187
188 handle_response!(rx, Command::OpenOverlayVoiceSettings => {
189 Ok(())
190 })
191 }
192}