Skip to main content

io_msgraph/v1/rest/users/contacts/
delta.rs

1//! Track changes to Microsoft Graph contacts (`GET /me/contacts/delta`
2//! or `GET /me/contactFolders/{id}/contacts/delta`).
3//!
4//! An initial request (no delta link) enumerates every contact and
5//! ends with an `@odata.deltaLink`; feeding that link back through
6//! [`MsgraphSend`] returns only what changed since, removals arriving
7//! as `@removed`-marked rows. An expired link answers HTTP 410; the
8//! consumer falls back to an initial request.
9//!
10//! <https://learn.microsoft.com/en-us/graph/api/contact-delta>
11
12use alloc::format;
13
14use io_http::rfc6750::bearer::HttpAuthBearer;
15use log::{debug, trace};
16use url::Url;
17
18use crate::{
19    coroutine::*,
20    msgraph_try,
21    v1::{
22        rest::users::contacts::MsgraphContactsDeltaResponse,
23        send::{MSGRAPH_API_BASE, MsgraphSend, MsgraphSendError, MsgraphSendOutput, user_path},
24    },
25};
26
27/// I/O-free coroutine for the initial contacts delta request; later
28/// rounds feed the returned links through [`MsgraphSend`] directly.
29pub struct MsgraphContactsDelta {
30    send: MsgraphSend<MsgraphContactsDeltaResponse>,
31}
32
33impl MsgraphContactsDelta {
34    /// Starts a delta round over the default Contacts folder, or over
35    /// `folder` when given (a contact folder id).
36    ///
37    /// `select` trims each row to the named properties (the id always
38    /// rides along).
39    pub fn new(
40        auth: &HttpAuthBearer,
41        user_id: &str,
42        folder: Option<&str>,
43        select: Option<&str>,
44    ) -> Result<Self, MsgraphSendError> {
45        debug!("prepare microsoft graph contacts delta");
46        trace!("folder: {folder:?}");
47
48        let user = user_path(user_id);
49        let path = match folder {
50            Some(folder) => format!("{user}/contactFolders/{folder}/contacts/delta"),
51            None => format!("{user}/contacts/delta"),
52        };
53        let mut url = Url::parse(MSGRAPH_API_BASE)?.join(&path)?;
54        if let Some(select) = select {
55            url.query_pairs_mut().append_pair("$select", select);
56        }
57
58        let send = MsgraphSend::get(auth, url);
59
60        Ok(Self { send })
61    }
62}
63
64impl MsgraphCoroutine for MsgraphContactsDelta {
65    type Yield = MsgraphYield;
66    type Return = Result<MsgraphSendOutput<MsgraphContactsDeltaResponse>, MsgraphSendError>;
67
68    fn resume(&mut self, arg: Option<&[u8]>) -> MsgraphCoroutineState<Self::Yield, Self::Return> {
69        let out = msgraph_try!(&mut self.send, arg);
70        debug!("contacts delta page received");
71        trace!("out: {out:?}");
72        MsgraphCoroutineState::Complete(Ok(out))
73    }
74}