Skip to main content

io_msgraph/v1/rest/users/messages/attachments/
get_raw.rs

1//! Get the raw content of a Microsoft Graph attachment
2//! (`GET /me/messages/{id}/attachments/{aid}/$value`).
3//!
4//! Like the message `$value` endpoint, this returns the decoded
5//! attachment bytes rather than JSON, so it runs the HTTP send
6//! directly and yields the body bytes.
7//!
8//! <https://learn.microsoft.com/en-us/graph/api/attachment-get>
9
10use alloc::{format, vec::Vec};
11
12use io_http::{
13    coroutine::{HttpCoroutine, HttpCoroutineState},
14    rfc6750::bearer::HttpAuthBearer,
15    rfc9110::{
16        request::HttpRequest,
17        send::{HttpSendOutput, HttpSendYield},
18    },
19    rfc9112::send::Http11Send,
20};
21use log::{debug, trace};
22use url::Url;
23
24use crate::{
25    coroutine::*,
26    v1::send::{MSGRAPH_API_BASE, MsgraphSendError, MsgraphSendOutput, parse_api_error, user_path},
27};
28
29/// Gets the raw content of a Microsoft Graph attachment.
30pub struct MsgraphAttachmentGetRaw {
31    send: Http11Send,
32}
33
34impl MsgraphAttachmentGetRaw {
35    /// Gets the raw content of the attachment `attachment_id` of the
36    /// message `message_id`.
37    pub fn new(
38        auth: &HttpAuthBearer,
39        user_id: &str,
40        message_id: &str,
41        attachment_id: &str,
42    ) -> Result<Self, MsgraphSendError> {
43        debug!("prepare microsoft graph attachment raw retrieval");
44        trace!("message_id: {message_id:?}");
45        trace!("attachment_id: {attachment_id:?}");
46
47        let user = user_path(user_id);
48        let url = Url::parse(MSGRAPH_API_BASE)?.join(&format!(
49            "{user}/messages/{message_id}/attachments/{attachment_id}/$value"
50        ))?;
51
52        let request = HttpRequest::get(url.clone())
53            .header("Authorization", auth.to_authorization())
54            .body(Vec::new());
55
56        Ok(Self {
57            send: Http11Send::new(request),
58        })
59    }
60}
61
62impl MsgraphCoroutine for MsgraphAttachmentGetRaw {
63    type Yield = MsgraphYield;
64    type Return = Result<MsgraphSendOutput<Vec<u8>>, MsgraphSendError>;
65
66    fn resume(&mut self, arg: Option<&[u8]>) -> MsgraphCoroutineState<Self::Yield, Self::Return> {
67        match self.send.resume(arg) {
68            HttpCoroutineState::Yielded(HttpSendYield::WantsRead) => {
69                MsgraphCoroutineState::Yielded(MsgraphYield::WantsRead)
70            }
71            HttpCoroutineState::Yielded(HttpSendYield::WantsWrite(bytes)) => {
72                MsgraphCoroutineState::Yielded(MsgraphYield::WantsWrite(bytes))
73            }
74            HttpCoroutineState::Yielded(HttpSendYield::WantsRedirect { .. }) => {
75                MsgraphCoroutineState::Complete(Err(MsgraphSendError::UnexpectedRedirect))
76            }
77            HttpCoroutineState::Complete(Err(err)) => {
78                MsgraphCoroutineState::Complete(Err(err.into()))
79            }
80            HttpCoroutineState::Complete(Ok(HttpSendOutput {
81                response,
82                keep_alive,
83                ..
84            })) => {
85                if response.status.is_success() {
86                    debug!("attachment raw retrieved");
87                    MsgraphCoroutineState::Complete(Ok(MsgraphSendOutput {
88                        response: response.body,
89                        keep_alive,
90                    }))
91                } else {
92                    let (status, code, message) = parse_api_error(*response.status, &response.body);
93                    MsgraphCoroutineState::Complete(Err(MsgraphSendError::Api {
94                        status,
95                        code,
96                        message,
97                    }))
98                }
99            }
100        }
101    }
102}