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