ruma_client_api/threads/
get_thread_subscriptions_changes.rs

1//! `GET /_matrix/client/*/thread_subscriptions`
2//!
3//! Retrieve a paginated range of thread subscriptions across all rooms.
4
5pub mod unstable {
6    //! `/unstable/` ([spec])
7    //!
8    //! [spec]: https://github.com/matrix-org/matrix-spec-proposals/pull/4308
9
10    use std::collections::BTreeMap;
11
12    use js_int::UInt;
13    use ruma_common::{
14        api::{request, response, Direction, Metadata},
15        metadata, OwnedEventId, OwnedRoomId,
16    };
17    use serde::{Deserialize, Serialize};
18
19    const METADATA: Metadata = metadata! {
20        method: GET,
21        rate_limited: true,
22        authentication: AccessToken,
23        history: {
24            unstable("org.matrix.msc4308") => "/_matrix/client/unstable/io.element.msc4308/thread_subscriptions",
25        }
26    };
27
28    /// Request type for the `get_thread_subscriptions_changes` endpoint.
29    #[request(error = crate::Error)]
30    pub struct Request {
31        /// The direction to use for pagination.
32        ///
33        /// Always `b`ackwards at the time of implementation (2025-08-21).
34        #[ruma_api(query)]
35        dir: Direction,
36
37        /// A token to continue pagination from.
38        ///
39        /// This token can be acquired from a previous `/thread_subscriptions` response, or the
40        /// `prev_batch` in a sliding sync response's `thread_subscriptions` field.
41        ///
42        /// The token is opaque and has no client-discernible meaning.
43        ///
44        /// If not provided, then the pagination starts from the "end".
45        #[ruma_api(query)]
46        #[serde(skip_serializing_if = "Option::is_none")]
47        pub from: Option<String>,
48
49        /// A token used to limit the pagination.
50        ///
51        /// The token can be set to the value of a sliding sync `pos` field used in a request that
52        /// returned new thread subscriptions with a `prev_batch` token.
53        #[ruma_api(query)]
54        #[serde(skip_serializing_if = "Option::is_none")]
55        pub to: Option<String>,
56
57        /// A maximum number of thread subscriptions to fetch in one response.
58        ///
59        /// Defaults to 100, if not provided. Servers may impose a smaller limit than requested.
60        #[ruma_api(query)]
61        #[serde(skip_serializing_if = "Option::is_none")]
62        pub limit: Option<UInt>,
63    }
64
65    /// A thread has been subscribed to at some point.
66    #[derive(Clone, Debug, Serialize, Deserialize)]
67    #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
68    pub struct ThreadSubscription {
69        /// Whether the subscription was made automatically by a client, not by manual user choice.
70        pub automatic: bool,
71
72        /// The bump stamp of the thread subscription, to be used to compare with other changes
73        /// related to the same thread.
74        pub bump_stamp: UInt,
75    }
76
77    impl ThreadSubscription {
78        /// Create a new [`ThreadSubscription`] with the given values.
79        pub fn new(automatic: bool, bump_stamp: UInt) -> Self {
80            Self { automatic, bump_stamp }
81        }
82    }
83
84    /// A thread has been unsubscribed to at some point.
85    #[derive(Clone, Debug, Serialize, Deserialize)]
86    #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
87    pub struct ThreadUnsubscription {
88        /// The bump stamp of the thread subscription, to be used to compare with other changes
89        /// related to the same thread.
90        pub bump_stamp: UInt,
91    }
92
93    impl ThreadUnsubscription {
94        /// Create a new [`ThreadUnsubscription`] with the given bump stamp.
95        pub fn new(bump_stamp: UInt) -> Self {
96            Self { bump_stamp }
97        }
98    }
99
100    /// Response type for the `get_thread_subscriptions_changes` endpoint.
101    #[response(error = crate::Error)]
102    pub struct Response {
103        /// New thread subscriptions.
104        #[serde(skip_serializing_if = "BTreeMap::is_empty")]
105        pub subscribed: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadSubscription>>,
106
107        /// New thread unsubscriptions.
108        #[serde(skip_serializing_if = "BTreeMap::is_empty")]
109        pub unsubscribed: BTreeMap<OwnedRoomId, BTreeMap<OwnedEventId, ThreadUnsubscription>>,
110
111        /// If there are still more results to fetch, this is the token to use as the next `from`
112        /// value.
113        #[serde(skip_serializing_if = "Option::is_none")]
114        pub end: Option<String>,
115    }
116
117    impl Request {
118        /// Creates a new empty `Request`.
119        pub fn new() -> Self {
120            Self { dir: Direction::Backward, from: None, to: None, limit: None }
121        }
122    }
123
124    impl Response {
125        /// Creates a new empty `Response`.
126        pub fn new() -> Self {
127            Self { subscribed: BTreeMap::new(), unsubscribed: BTreeMap::new(), end: None }
128        }
129    }
130}