1#![doc = include_str!("../README.md")]
2
3#[macro_use]
4mod util;
5pub mod activity;
6pub mod error;
7mod handler;
8mod io;
9pub mod overlay;
10mod proto;
11pub mod registration;
12pub mod relations;
13mod types;
14pub mod user;
15
16pub use error::{DiscordApiErr, DiscordErr, Error};
17pub use handler::{handlers, wheel, DiscordHandler, DiscordMsg};
18pub use proto::event::Event;
19use proto::{Command, CommandKind};
20pub use time::OffsetDateTime;
21pub use types::Snowflake;
22pub type AppId = i64;
23
24pub use crossbeam_channel as cc;
25use parking_lot::Mutex;
26use std::sync::Arc;
27
28pub enum DiscordApp {
31 Register(registration::Application),
34 PlainId(AppId),
38}
39
40impl From<AppId> for DiscordApp {
41 fn from(id: AppId) -> Self {
42 Self::PlainId(id)
43 }
44}
45
46impl From<registration::Application> for DiscordApp {
47 fn from(app: registration::Application) -> Self {
48 Self::Register(app)
49 }
50}
51
52bitflags::bitflags! {
53 #[derive(Copy, Clone)]
54 pub struct Subscriptions: u32 {
55 const ACTIVITY = 0x1;
56 const USER = 0x4;
57 const OVERLAY = 0x8;
58 const RELATIONSHIPS = 0x10;
59
60 const ALL = Self::ACTIVITY.bits() | Self::USER.bits() | Self::OVERLAY.bits() | Self::RELATIONSHIPS.bits();
61 }
62}
63
64pub struct Discord {
65 nonce: std::sync::atomic::AtomicUsize,
66 send_queue: cc::Sender<Option<Vec<u8>>>,
68 io_task: tokio::task::JoinHandle<()>,
70 handler_task: tokio::task::JoinHandle<()>,
72 state: State,
73}
74
75impl Discord {
76 pub fn new(
79 app: impl Into<DiscordApp>,
80 subscriptions: Subscriptions,
81 handler: Box<dyn DiscordHandler>,
82 ) -> Result<Self, Error> {
83 let app_id = match app.into() {
84 DiscordApp::PlainId(id) => id,
85 DiscordApp::Register(inner) => {
86 let id = inner.id;
87 registration::register_app(inner)?;
88 id
89 }
90 };
91
92 let io_task = io::start_io_task(app_id);
93
94 let state = State::default();
95
96 let handler_task = handler::handler_task(
97 handler,
98 subscriptions,
99 io_task.stx.clone(),
100 io_task.rrx,
101 state.clone(),
102 );
103
104 Ok(Self {
105 nonce: std::sync::atomic::AtomicUsize::new(1),
106 send_queue: io_task.stx,
107 io_task: io_task.handle,
108 handler_task,
109 state,
110 })
111 }
112
113 pub async fn disconnect(self) {
116 let _ = self.send_queue.send(None);
117 let _ = self.io_task.await;
118 let _ = self.handler_task.await;
119 }
120
121 fn send_rpc<Msg>(
124 &self,
125 cmd: CommandKind,
126 msg: Msg,
127 ) -> Result<tokio::sync::oneshot::Receiver<Result<Command, Error>>, Error>
128 where
129 Msg: serde::Serialize,
130 {
131 let nonce = self
134 .nonce
135 .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
136
137 let rpc = proto::Rpc {
138 cmd,
139 args: Some(msg),
140 nonce: nonce.to_string(),
141 evt: None,
142 };
143
144 let (tx, rx) = tokio::sync::oneshot::channel();
145
146 self.state
147 .notify_queue
148 .lock()
149 .push(NotifyItem { nonce, tx, cmd });
150
151 let mut buffer = Vec::with_capacity(128);
152 io::serialize_message(io::OpCode::Frame, &rpc, &mut buffer)?;
153 self.send_queue.send(Some(buffer))?;
154
155 Ok(rx)
156 }
157}
158
159pub(crate) struct NotifyItem {
160 pub(crate) nonce: usize,
163 pub(crate) tx: tokio::sync::oneshot::Sender<Result<Command, Error>>,
165 pub(crate) cmd: CommandKind,
169}
170
171#[derive(Clone)]
173pub(crate) struct State {
174 notify_queue: Arc<Mutex<Vec<NotifyItem>>>,
176}
177
178impl Default for State {
179 fn default() -> Self {
180 Self {
181 notify_queue: Arc::new(Mutex::new(Vec::new())),
182 }
183 }
184}