sparkle_impostor/thread.rs
1//! Handling the message being in a thread
2
3use twilight_model::{
4 channel::{Channel, ChannelType},
5 id::{marker::ChannelMarker, Id},
6};
7
8use crate::{error::Error, MessageSource};
9
10/// Info about the thread the message is in
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum Info {
13 /// Message is in a thread, but the thread hasn't been created from the
14 /// message
15 ///
16 /// Wrapped value is the thread's ID
17 In(Id<ChannelMarker>),
18 /// A non-post thread has been created from the message
19 ///
20 /// Wrapped value is the thread
21 Created(Box<Channel>),
22 /// A post in a forum channel has been created from the message
23 ///
24 /// Wrapped value is the thread
25 CreatedPost(Box<Channel>),
26 /// A thread has been created from the message, but it's not known whether
27 /// it's a forum channel post or not
28 ///
29 /// Wrapped value is the thread
30 CreatedUnknown(Box<Channel>),
31 /// The message is not in a thread
32 NotIn,
33 /// Thread info hasn't been checked
34 Unknown,
35}
36
37impl Info {
38 pub(crate) fn id(&self) -> Option<Id<ChannelMarker>> {
39 match self {
40 Self::In(id) => Some(*id),
41 Self::Created(thread) | Self::CreatedPost(thread) | Self::CreatedUnknown(thread) => {
42 Some(thread.id)
43 }
44 _ => None,
45 }
46 }
47}
48
49impl<'a> MessageSource<'a> {
50 /// Handle the message being in a thread
51 ///
52 /// This requires getting the channel with another HTTP request
53 ///
54 /// # Warnings
55 ///
56 /// Must be called before [`MessageSource::create`]
57 ///
58 /// # Errors
59 ///
60 /// Returns [`Error::Http`] if getting the channel fails
61 ///
62 /// Returns [`Error::DeserializeBody`] if deserializing the channel fails
63 #[allow(clippy::missing_panics_doc)]
64 pub async fn handle_thread(mut self) -> Result<MessageSource<'a>, Error> {
65 if !matches!(self.thread_info, Info::Unknown | Info::CreatedUnknown(_)) {
66 return Ok(self);
67 }
68
69 let thread = if let Info::CreatedUnknown(thread) = self.thread_info {
70 thread
71 } else {
72 Box::new(self.http.channel(self.channel_id).await?.model().await?)
73 };
74
75 if !thread.kind.is_thread() {
76 self.thread_info = Info::NotIn;
77 return Ok(self);
78 }
79
80 self.channel_id = thread.parent_id.unwrap();
81
82 self.thread_info = if self.source_id == thread.id.cast() {
83 let channel = self.http.channel(self.channel_id).await?.model().await?;
84
85 if channel.kind == ChannelType::GuildForum {
86 Info::CreatedPost(thread)
87 } else {
88 Info::Created(thread)
89 }
90 } else {
91 Info::In(thread.id)
92 };
93
94 self.source_thread_id = self.thread_info.id();
95
96 Ok(self)
97 }
98
99 /// Handle a thread being created from the message
100 ///
101 /// # Errors
102 ///
103 /// Returns [`Error::ChannelValidation`] if the thread is invalid, shouldn't
104 /// happen unless the it was mutated
105 ///
106 /// Returns [`Error::Http`] if creating the thread fails
107 ///
108 /// Returns [`Error::DeserializeBody`] if deserializing the thread fails
109 ///
110 /// # Panics
111 ///
112 /// If called before [`MessageSource::create`]
113 pub async fn handle_thread_created(mut self) -> Result<MessageSource<'a>, Error> {
114 if let Info::Created(thread) = &self.thread_info {
115 let thread_new = self
116 .http
117 .create_thread_from_message(
118 self.channel_id,
119 self.response.as_mut().unwrap().model().await?.id,
120 thread.name.as_ref().unwrap(),
121 )?
122 .await?
123 .model()
124 .await?;
125
126 self.thread_info = Info::Created(Box::new(thread_new));
127 }
128
129 Ok(self)
130 }
131}