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 = Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
69 handler.ready(ctx, *ready).await;
70 }
71 Event::MessageCreate(msg) => {
72 let ctx = Context::new(http.clone(), cache.clone(), self.shard.clone(), None);
73 handler.message_create(ctx, *msg).await;
74 }
75 Event::InteractionCreate(interaction) => {
76 let interaction_val = *interaction;
77 let ctx = Context::new(
78 http.clone(),
79 cache.clone(),
80 self.shard.clone(),
81 Some(interaction_val.clone()),
82 );
83 handler.interaction_create(ctx, interaction_val).await;
84 }
85 _ => {}
86 }
87 }
88 }
89
90 Ok(())
91 }
92}
93
94
95use async_trait::async_trait;
96use crate::prelude::*;
97
98#[async_trait]
99pub trait EventHandler: Send + Sync {
100 async fn ready(&self, _ctx: Context, _ready: ReadyEventData<'_>) {}
101 async fn message_create(&self, _ctx: Context, _msg: Message<'_>) {}
102 async fn interaction_create(&self, _ctx: Context, _interaction: Interaction<'_>) {}
103 }
105
106pub struct ClientBuilder {
107 token: String,
108 intents: Intents,
109 framework: Option<Framework>,
110 event_handler: Option<Arc<dyn EventHandler>>,
111}
112
113impl ClientBuilder {
114 #[inline]
115 pub fn new(token: impl Into<String>) -> Self {
116 Self {
117 token: token.into(),
118 intents: Intents::default(),
119 framework: None,
120 event_handler: None,
121 }
122 }
123
124 pub fn intents(mut self, intents: Intents) -> Self {
125 self.intents = intents;
126 self
127 }
128
129 pub fn framework(mut self, framework: Framework) -> Self {
130 self.framework = Some(framework);
131 self
132 }
133
134 pub fn event_handler<H: EventHandler + 'static>(mut self, handler: H) -> Self {
135 self.event_handler = Some(Arc::new(handler));
136 self
137 }
138
139 pub async fn build(self) -> Result<Client, Box<dyn std::error::Error>> {
140 let http = Arc::new(HttpClient::new(self.token.clone())?);
141 let cache = Arc::new(titanium_cache::InMemoryCache::new());
142
143 let config = ShardConfig::new(self.token.clone(), self.intents);
144 let shard = Arc::new(Shard::new(0, 1, config));
145
146 Ok(Client {
147 shard,
148 http,
149 cache,
150 framework: self.framework.map(Arc::new),
151 event_handler: self.event_handler,
152 token: self.token,
153 })
154 }
155}
156