1mod mock;
8mod readonly;
9
10use std::{collections::HashSet, sync::Arc};
11
12use ruma_common::UserId;
13
14pub use self::{
15 mock::HomeserverConnection as MockHomeserverConnection, readonly::ReadOnlyHomeserverConnection,
16};
17
18#[derive(Debug)]
19pub struct MatrixUser {
20 pub displayname: Option<String>,
21 pub avatar_url: Option<String>,
22 pub deactivated: bool,
23}
24
25#[derive(Debug, Default)]
26enum FieldAction<T> {
27 #[default]
28 DoNothing,
29 Set(T),
30 Unset,
31}
32
33pub struct ProvisionRequest {
34 mxid: String,
35 sub: String,
36 displayname: FieldAction<String>,
37 avatar_url: FieldAction<String>,
38 emails: FieldAction<Vec<String>>,
39}
40
41impl ProvisionRequest {
42 #[must_use]
49 pub fn new(mxid: impl Into<String>, sub: impl Into<String>) -> Self {
50 Self {
51 mxid: mxid.into(),
52 sub: sub.into(),
53 displayname: FieldAction::DoNothing,
54 avatar_url: FieldAction::DoNothing,
55 emails: FieldAction::DoNothing,
56 }
57 }
58
59 #[must_use]
61 pub fn sub(&self) -> &str {
62 &self.sub
63 }
64
65 #[must_use]
67 pub fn mxid(&self) -> &str {
68 &self.mxid
69 }
70
71 #[must_use]
77 pub fn set_displayname(mut self, displayname: String) -> Self {
78 self.displayname = FieldAction::Set(displayname);
79 self
80 }
81
82 #[must_use]
84 pub fn unset_displayname(mut self) -> Self {
85 self.displayname = FieldAction::Unset;
86 self
87 }
88
89 pub fn on_displayname<F>(&self, callback: F) -> &Self
95 where
96 F: FnOnce(Option<&str>),
97 {
98 match &self.displayname {
99 FieldAction::Unset => callback(None),
100 FieldAction::Set(displayname) => callback(Some(displayname)),
101 FieldAction::DoNothing => {}
102 }
103
104 self
105 }
106
107 #[must_use]
113 pub fn set_avatar_url(mut self, avatar_url: String) -> Self {
114 self.avatar_url = FieldAction::Set(avatar_url);
115 self
116 }
117
118 #[must_use]
120 pub fn unset_avatar_url(mut self) -> Self {
121 self.avatar_url = FieldAction::Unset;
122 self
123 }
124
125 pub fn on_avatar_url<F>(&self, callback: F) -> &Self
131 where
132 F: FnOnce(Option<&str>),
133 {
134 match &self.avatar_url {
135 FieldAction::Unset => callback(None),
136 FieldAction::Set(avatar_url) => callback(Some(avatar_url)),
137 FieldAction::DoNothing => {}
138 }
139
140 self
141 }
142
143 #[must_use]
149 pub fn set_emails(mut self, emails: Vec<String>) -> Self {
150 self.emails = FieldAction::Set(emails);
151 self
152 }
153
154 #[must_use]
156 pub fn unset_emails(mut self) -> Self {
157 self.emails = FieldAction::Unset;
158 self
159 }
160
161 pub fn on_emails<F>(&self, callback: F) -> &Self
167 where
168 F: FnOnce(Option<&[String]>),
169 {
170 match &self.emails {
171 FieldAction::Unset => callback(None),
172 FieldAction::Set(emails) => callback(Some(emails)),
173 FieldAction::DoNothing => {}
174 }
175
176 self
177 }
178}
179
180#[async_trait::async_trait]
181pub trait HomeserverConnection: Send + Sync {
182 fn homeserver(&self) -> &str;
184
185 fn mxid(&self, localpart: &str) -> String {
191 format!("@{}:{}", localpart, self.homeserver())
192 }
193
194 fn localpart<'a>(&self, mxid: &'a str) -> Option<&'a str> {
203 let mxid = <&UserId>::try_from(mxid).ok()?;
204 if mxid.server_name() != self.homeserver() {
205 return None;
206 }
207 Some(mxid.localpart())
208 }
209
210 async fn query_user(&self, mxid: &str) -> Result<MatrixUser, anyhow::Error>;
221
222 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error>;
234
235 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error>;
245
246 async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error>;
258
259 async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error>;
271
272 async fn sync_devices(&self, mxid: &str, devices: HashSet<String>)
284 -> Result<(), anyhow::Error>;
285
286 async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error>;
298
299 async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error>;
310
311 async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error>;
323
324 async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error>;
335
336 async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error>;
347}
348
349#[async_trait::async_trait]
350impl<T: HomeserverConnection + Send + Sync + ?Sized> HomeserverConnection for &T {
351 fn homeserver(&self) -> &str {
352 (**self).homeserver()
353 }
354
355 async fn query_user(&self, mxid: &str) -> Result<MatrixUser, anyhow::Error> {
356 (**self).query_user(mxid).await
357 }
358
359 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error> {
360 (**self).provision_user(request).await
361 }
362
363 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error> {
364 (**self).is_localpart_available(localpart).await
365 }
366
367 async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> {
368 (**self).create_device(mxid, device_id).await
369 }
370
371 async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> {
372 (**self).delete_device(mxid, device_id).await
373 }
374
375 async fn sync_devices(
376 &self,
377 mxid: &str,
378 devices: HashSet<String>,
379 ) -> Result<(), anyhow::Error> {
380 (**self).sync_devices(mxid, devices).await
381 }
382
383 async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error> {
384 (**self).delete_user(mxid, erase).await
385 }
386
387 async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error> {
388 (**self).reactivate_user(mxid).await
389 }
390
391 async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error> {
392 (**self).set_displayname(mxid, displayname).await
393 }
394
395 async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error> {
396 (**self).unset_displayname(mxid).await
397 }
398
399 async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error> {
400 (**self).allow_cross_signing_reset(mxid).await
401 }
402}
403
404#[async_trait::async_trait]
406impl<T: HomeserverConnection + ?Sized> HomeserverConnection for Arc<T> {
407 fn homeserver(&self) -> &str {
408 (**self).homeserver()
409 }
410
411 async fn query_user(&self, mxid: &str) -> Result<MatrixUser, anyhow::Error> {
412 (**self).query_user(mxid).await
413 }
414
415 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error> {
416 (**self).provision_user(request).await
417 }
418
419 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error> {
420 (**self).is_localpart_available(localpart).await
421 }
422
423 async fn create_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> {
424 (**self).create_device(mxid, device_id).await
425 }
426
427 async fn delete_device(&self, mxid: &str, device_id: &str) -> Result<(), anyhow::Error> {
428 (**self).delete_device(mxid, device_id).await
429 }
430
431 async fn sync_devices(
432 &self,
433 mxid: &str,
434 devices: HashSet<String>,
435 ) -> Result<(), anyhow::Error> {
436 (**self).sync_devices(mxid, devices).await
437 }
438
439 async fn delete_user(&self, mxid: &str, erase: bool) -> Result<(), anyhow::Error> {
440 (**self).delete_user(mxid, erase).await
441 }
442
443 async fn reactivate_user(&self, mxid: &str) -> Result<(), anyhow::Error> {
444 (**self).reactivate_user(mxid).await
445 }
446
447 async fn set_displayname(&self, mxid: &str, displayname: &str) -> Result<(), anyhow::Error> {
448 (**self).set_displayname(mxid, displayname).await
449 }
450
451 async fn unset_displayname(&self, mxid: &str) -> Result<(), anyhow::Error> {
452 (**self).unset_displayname(mxid).await
453 }
454
455 async fn allow_cross_signing_reset(&self, mxid: &str) -> Result<(), anyhow::Error> {
456 (**self).allow_cross_signing_reset(mxid).await
457 }
458}