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 localpart: 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(localpart: impl Into<String>, sub: impl Into<String>) -> Self {
50 Self {
51 localpart: localpart.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 localpart(&self) -> &str {
68 &self.localpart
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, localpart: &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 upsert_device(
258 &self,
259 localpart: &str,
260 device_id: &str,
261 initial_display_name: Option<&str>,
262 ) -> Result<(), anyhow::Error>;
263
264 async fn update_device_display_name(
277 &self,
278 localpart: &str,
279 device_id: &str,
280 display_name: &str,
281 ) -> Result<(), anyhow::Error>;
282
283 async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error>;
295
296 async fn sync_devices(
308 &self,
309 localpart: &str,
310 devices: HashSet<String>,
311 ) -> Result<(), anyhow::Error>;
312
313 async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error>;
325
326 async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error>;
337
338 async fn set_displayname(
350 &self,
351 localpart: &str,
352 displayname: &str,
353 ) -> Result<(), anyhow::Error>;
354
355 async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error>;
366
367 async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error>;
379}
380
381#[async_trait::async_trait]
382impl<T: HomeserverConnection + Send + Sync + ?Sized> HomeserverConnection for &T {
383 fn homeserver(&self) -> &str {
384 (**self).homeserver()
385 }
386
387 async fn query_user(&self, localpart: &str) -> Result<MatrixUser, anyhow::Error> {
388 (**self).query_user(localpart).await
389 }
390
391 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error> {
392 (**self).provision_user(request).await
393 }
394
395 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error> {
396 (**self).is_localpart_available(localpart).await
397 }
398
399 async fn upsert_device(
400 &self,
401 localpart: &str,
402 device_id: &str,
403 initial_display_name: Option<&str>,
404 ) -> Result<(), anyhow::Error> {
405 (**self)
406 .upsert_device(localpart, device_id, initial_display_name)
407 .await
408 }
409
410 async fn update_device_display_name(
411 &self,
412 localpart: &str,
413 device_id: &str,
414 display_name: &str,
415 ) -> Result<(), anyhow::Error> {
416 (**self)
417 .update_device_display_name(localpart, device_id, display_name)
418 .await
419 }
420
421 async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> {
422 (**self).delete_device(localpart, device_id).await
423 }
424
425 async fn sync_devices(
426 &self,
427 localpart: &str,
428 devices: HashSet<String>,
429 ) -> Result<(), anyhow::Error> {
430 (**self).sync_devices(localpart, devices).await
431 }
432
433 async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> {
434 (**self).delete_user(localpart, erase).await
435 }
436
437 async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> {
438 (**self).reactivate_user(localpart).await
439 }
440
441 async fn set_displayname(
442 &self,
443 localpart: &str,
444 displayname: &str,
445 ) -> Result<(), anyhow::Error> {
446 (**self).set_displayname(localpart, displayname).await
447 }
448
449 async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> {
450 (**self).unset_displayname(localpart).await
451 }
452
453 async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> {
454 (**self).allow_cross_signing_reset(localpart).await
455 }
456}
457
458#[async_trait::async_trait]
460impl<T: HomeserverConnection + ?Sized> HomeserverConnection for Arc<T> {
461 fn homeserver(&self) -> &str {
462 (**self).homeserver()
463 }
464
465 async fn query_user(&self, localpart: &str) -> Result<MatrixUser, anyhow::Error> {
466 (**self).query_user(localpart).await
467 }
468
469 async fn provision_user(&self, request: &ProvisionRequest) -> Result<bool, anyhow::Error> {
470 (**self).provision_user(request).await
471 }
472
473 async fn is_localpart_available(&self, localpart: &str) -> Result<bool, anyhow::Error> {
474 (**self).is_localpart_available(localpart).await
475 }
476
477 async fn upsert_device(
478 &self,
479 localpart: &str,
480 device_id: &str,
481 initial_display_name: Option<&str>,
482 ) -> Result<(), anyhow::Error> {
483 (**self)
484 .upsert_device(localpart, device_id, initial_display_name)
485 .await
486 }
487
488 async fn update_device_display_name(
489 &self,
490 localpart: &str,
491 device_id: &str,
492 display_name: &str,
493 ) -> Result<(), anyhow::Error> {
494 (**self)
495 .update_device_display_name(localpart, device_id, display_name)
496 .await
497 }
498
499 async fn delete_device(&self, localpart: &str, device_id: &str) -> Result<(), anyhow::Error> {
500 (**self).delete_device(localpart, device_id).await
501 }
502
503 async fn sync_devices(
504 &self,
505 localpart: &str,
506 devices: HashSet<String>,
507 ) -> Result<(), anyhow::Error> {
508 (**self).sync_devices(localpart, devices).await
509 }
510
511 async fn delete_user(&self, localpart: &str, erase: bool) -> Result<(), anyhow::Error> {
512 (**self).delete_user(localpart, erase).await
513 }
514
515 async fn reactivate_user(&self, localpart: &str) -> Result<(), anyhow::Error> {
516 (**self).reactivate_user(localpart).await
517 }
518
519 async fn set_displayname(
520 &self,
521 localpart: &str,
522 displayname: &str,
523 ) -> Result<(), anyhow::Error> {
524 (**self).set_displayname(localpart, displayname).await
525 }
526
527 async fn unset_displayname(&self, localpart: &str) -> Result<(), anyhow::Error> {
528 (**self).unset_displayname(localpart).await
529 }
530
531 async fn allow_cross_signing_reset(&self, localpart: &str) -> Result<(), anyhow::Error> {
532 (**self).allow_cross_signing_reset(localpart).await
533 }
534}