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}