twilight_http/request/application/interaction/
create_response.rs

1use crate::{
2    client::Client,
3    error::Error,
4    request::{
5        application::interaction::CreateResponseWithResponse, attachment::AttachmentManager,
6        Request, TryIntoRequest,
7    },
8    response::{marker::EmptyBody, Response, ResponseFuture},
9    routing::Route,
10};
11use std::future::IntoFuture;
12use twilight_model::{
13    http::interaction::InteractionResponse,
14    id::{marker::InteractionMarker, Id},
15};
16
17/// Respond to an interaction, by its ID and token.
18///
19/// This endpoint is not bound to the application's global rate limit.
20#[must_use = "requests must be configured and executed"]
21pub struct CreateResponse<'a> {
22    interaction_id: Id<InteractionMarker>,
23    interaction_token: &'a str,
24    response: &'a InteractionResponse,
25    http: &'a Client,
26}
27
28impl<'a> CreateResponse<'a> {
29    pub(crate) const fn new(
30        http: &'a Client,
31        interaction_id: Id<InteractionMarker>,
32        interaction_token: &'a str,
33        response: &'a InteractionResponse,
34    ) -> Self {
35        Self {
36            interaction_id,
37            interaction_token,
38            response,
39            http,
40        }
41    }
42
43    pub const fn with_response(self) -> CreateResponseWithResponse<'a> {
44        CreateResponseWithResponse::new(
45            self.http,
46            self.interaction_id,
47            self.interaction_token,
48            self.response,
49        )
50    }
51}
52
53impl IntoFuture for CreateResponse<'_> {
54    type Output = Result<Response<EmptyBody>, Error>;
55
56    type IntoFuture = ResponseFuture<EmptyBody>;
57
58    fn into_future(self) -> Self::IntoFuture {
59        let http = self.http;
60
61        match self.try_into_request() {
62            Ok(request) => http.request(request),
63            Err(source) => ResponseFuture::error(source),
64        }
65    }
66}
67
68impl TryIntoRequest for CreateResponse<'_> {
69    fn try_into_request(self) -> Result<Request, Error> {
70        let mut request = Request::builder(&Route::InteractionCallback {
71            interaction_id: self.interaction_id.get(),
72            interaction_token: self.interaction_token,
73            with_response: false,
74        });
75
76        // Interaction executions don't need the authorization token, only the
77        // interaction token.
78        request = request.use_authorization_token(false);
79
80        // Determine whether we need to use a multipart/form-data body or a JSON
81        // body.
82        if let Some(attachments) = self
83            .response
84            .data
85            .as_ref()
86            .and_then(|data| data.attachments.as_ref())
87        {
88            let fields = crate::json::to_vec(&self.response).map_err(Error::json)?;
89
90            let form = AttachmentManager::new()
91                .set_files(attachments.iter().collect())
92                .build_form(&fields);
93
94            request = request.form(form);
95        } else {
96            request = request.json(&self.response);
97        }
98
99        request.build()
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use crate::{client::Client, request::TryIntoRequest};
106    use std::error::Error;
107    use twilight_http_ratelimiting::Path;
108    use twilight_model::{
109        http::interaction::{InteractionResponse, InteractionResponseType},
110        id::Id,
111    };
112
113    #[test]
114    fn interaction_callback() -> Result<(), Box<dyn Error>> {
115        let application_id = Id::new(1);
116        let interaction_id = Id::new(2);
117        let token = "foo".to_owned().into_boxed_str();
118
119        let client = Client::new(String::new());
120
121        let response = InteractionResponse {
122            kind: InteractionResponseType::DeferredUpdateMessage,
123            data: None,
124        };
125
126        let req = client
127            .interaction(application_id)
128            .create_response(interaction_id, &token, &response)
129            .try_into_request()?;
130
131        assert!(!req.use_authorization_token());
132        assert_eq!(
133            &Path::InteractionCallback(interaction_id.get()),
134            req.ratelimit_path()
135        );
136
137        Ok(())
138    }
139}