1use crate::framework::Framework;
2use std::sync::Arc;
3use titanium_cache::{Cache, InMemoryCache};
4use titanium_gateway::{Event, Shard, ShardConfig};
5use titanium_http::HttpClient;
6use titanium_model::Intents;
7
8#[derive(Clone)]
13pub struct Client {
14 pub shard: Arc<Shard>, pub http: Arc<HttpClient>,
16 pub cache: Arc<InMemoryCache>,
17 pub framework: Option<Arc<Framework>>,
18 pub event_handler: Option<Arc<dyn EventHandler>>,
19 #[allow(dead_code)]
20 token: String,
21}
22
23impl Client {
24 #[inline]
26 pub fn builder(token: impl Into<String>) -> ClientBuilder {
27 ClientBuilder::new(token)
28 }
29
30 pub async fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
34 let (tx, rx) = flume::unbounded();
35
36 let shard = self.shard.clone();
37 let cache = self.cache.clone();
38 let http = self.http.clone();
39 let event_handler = self.event_handler.clone();
40
41 let tx_clone = tx.clone();
43 tokio::spawn(async move {
44 if let Err(e) = shard.run(tx_clone).await {
45 eprintln!("Shard error: {:?}", e);
46 }
47 });
48
49 while let Ok(event) = rx.recv_async().await {
51 match &event {
53 Event::Ready(ready) => {
54 cache.insert_user(ready.user.clone());
55 }
57 Event::GuildCreate(guild) => {
58 cache.insert_guild(*guild.clone());
59 }
60 _ => {}
62 }
63
64 if let Some(handler) = &event_handler {
66 match event {
67 Event::Ready(ready) => {
68 let ctx =
69 Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
70 handler.ready(ctx, *ready).await;
71 }
72 Event::MessageCreate(msg) => {
73 let ctx =
74 Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
75 handler.message_create(ctx, *msg).await;
76 }
77 Event::InteractionCreate(interaction) => {
78 let interaction_val = *interaction;
79 let ctx = Context::new(
80 http.clone(),
81 cache.clone(),
82 self.shard.clone(),
83 Some(interaction_val.clone()),
84 );
85 handler.interaction_create(ctx, interaction_val).await;
86 }
87 Event::MessageReactionAdd(ev) => {
88 let ctx = Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
89 handler.reaction_add(ctx, *ev).await;
90 }
91 Event::ThreadCreate(thread) => {
92 let ctx = Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
93 handler.thread_create(ctx, *thread).await;
94 }
95 Event::GuildRoleCreate(ev) => {
96 let ctx = Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
97 handler.role_create(ctx, *ev).await;
98 }
99 _ => {}
100 }
101 }
102 }
103
104 Ok(())
105 }
106}
107
108use crate::prelude::*;
109use async_trait::async_trait;
110
111#[async_trait]
112pub trait EventHandler: Send + Sync {
113 async fn ready(&self, _ctx: Context, _ready: ReadyEventData<'_>) {}
114 async fn message_create(&self, _ctx: Context, _msg: Message<'_>) {}
115 async fn interaction_create(&self, _ctx: Context, _interaction: Interaction<'_>) {}
116 async fn reaction_add(&self, _ctx: Context, _add: titanium_model::MessageReactionAddEvent<'async_trait>) {}
117 async fn thread_create(&self, _ctx: Context, _thread: Channel<'async_trait>) {}
118 async fn role_create(&self, _ctx: Context, _role: GuildRoleEvent<'async_trait>) {}
119}
120
121pub struct ClientBuilder {
122 token: String,
123 intents: Intents,
124 framework: Option<Framework>,
125 event_handler: Option<Arc<dyn EventHandler>>,
126}
127
128impl ClientBuilder {
129 #[inline]
130 pub fn new(token: impl Into<String>) -> Self {
131 Self {
132 token: token.into(),
133 intents: Intents::default(),
134 framework: None,
135 event_handler: None,
136 }
137 }
138
139 pub fn intents(mut self, intents: Intents) -> Self {
140 self.intents = intents;
141 self
142 }
143
144 pub fn framework(mut self, framework: Framework) -> Self {
145 self.framework = Some(framework);
146 self
147 }
148
149 pub fn event_handler<H: EventHandler + 'static>(mut self, handler: H) -> Self {
150 self.event_handler = Some(Arc::new(handler));
151 self
152 }
153
154 pub async fn build(self) -> Result<Client, Box<dyn std::error::Error>> {
155 let http = Arc::new(HttpClient::new(self.token.clone())?);
156 let cache = Arc::new(titanium_cache::InMemoryCache::new());
157
158 let config = ShardConfig::new(self.token.clone(), self.intents);
159 let shard = Arc::new(Shard::new(0, 1, config));
160
161 Ok(Client {
162 shard,
163 http,
164 cache,
165 framework: self.framework.map(Arc::new),
166 event_handler: self.event_handler,
167 token: self.token,
168 })
169 }
170}