Skip to main content

m4a_agent/backend/
attached.rs

1//! A backend over a session somebody else established: the host did its own login (a single
2//! sign-on page, say) and hands over the resulting token, or a test talks to a stock homeserver.
3//! It cannot log in by itself. Agents never get here with a secret of their own: only a host that
4//! already holds one for them.
5
6use std::time::Duration;
7
8use mail4agent_messenger::{HttpResponseDescriptor, OutgoingRequest};
9
10use super::live::Live;
11use super::{Backend, BackendKind, Capabilities, Session};
12use crate::engine::{HttpExec, News};
13use crate::error::{AgentError, Result};
14use crate::identity::{IdentityStore, SessionIdentity};
15
16pub struct AttachedBackend {
17    kind: BackendKind,
18    base: String,
19    live: Live,
20    #[cfg(feature = "tier-matrix")]
21    sliding: super::sliding::Sliding,
22}
23
24impl AttachedBackend {
25    /// `base` is the server's origin. The spec prefix and sliding sync are asked of the server.
26    pub fn new(kind: BackendKind, base: &str, token: &str) -> Result<Self> {
27        let mut exec = HttpExec::new(base)?;
28        exec.probe_prefix();
29        Self::from_exec(kind, base, token, exec)
30    }
31
32    /// No network at all: `keep_prefix` says whether the server serves the paths under `/_matrix`,
33    /// and sliding sync stays off.
34    pub fn with_prefix(kind: BackendKind, base: &str, token: &str, keep_prefix: bool) -> Result<Self> {
35        let mut exec = HttpExec::new(base)?;
36        exec.set_keep_prefix(keep_prefix);
37        let me = Self::from_exec(kind, base, token, exec)?;
38        #[cfg(feature = "tier-matrix")]
39        me.sliding.set_mode(super::matrix::SyncMode::V3);
40        #[cfg(feature = "tier-matrix")]
41        me.sliding.decide(&me.live);
42        Ok(me)
43    }
44
45    fn from_exec(kind: BackendKind, base: &str, token: &str, exec: HttpExec) -> Result<Self> {
46        let live = Live::new(exec);
47        live.set_token(token);
48        let me = Self {
49            kind,
50            base: base.trim_end_matches('/').to_string(),
51            live,
52            #[cfg(feature = "tier-matrix")]
53            sliding: super::sliding::Sliding::new(),
54        };
55        #[cfg(feature = "tier-matrix")]
56        if kind == BackendKind::Matrix {
57            me.sliding.decide(&me.live);
58        }
59        Ok(me)
60    }
61
62    /// Plain `/sync` v3 only.
63    #[cfg(feature = "tier-matrix")]
64    pub fn without_sliding_sync(self) -> Self {
65        self.sliding.set_mode(super::matrix::SyncMode::V3);
66        self.sliding.decide(&self.live);
67        self
68    }
69
70    #[cfg(feature = "tier-matrix")]
71    pub fn uses_sliding_sync(&self) -> bool {
72        self.sliding.active()
73    }
74}
75
76impl Backend for AttachedBackend {
77    fn kind(&self) -> BackendKind {
78        self.kind
79    }
80    fn capabilities(&self) -> Capabilities {
81        Capabilities { rooms: self.kind == BackendKind::Matrix, federation: self.kind == BackendKind::Matrix }
82    }
83    fn server_ref(&self) -> &str {
84        &self.base
85    }
86    fn ensure_session(&self, _: &IdentityStore, _: &mut SessionIdentity, _: Option<&str>) -> Result<Session> {
87        Err(AgentError::Identity("this backend was handed an established session and cannot log in".into()))
88    }
89    fn execute(&self, request: &OutgoingRequest) -> Result<HttpResponseDescriptor> {
90        #[cfg(feature = "tier-matrix")]
91        if request.kind == mail4agent_messenger::OutgoingRequestKind::Sync {
92            if let Some(answer) = self.sliding.sync(&self.live, request)? {
93                return Ok(answer);
94            }
95        }
96        self.live.execute(request)
97    }
98    fn whoami(&self) -> Result<(String, String)> {
99        self.live.whoami()
100    }
101    fn keep_prefix(&self) -> bool {
102        self.live.keep_prefix()
103    }
104    fn wait_for_news(&self, timeout: Duration) -> Result<News> {
105        self.live.wait_for_news(timeout)
106    }
107}