viaduct/
new_backend.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3*
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6// Right now we're in a transition period where we have 2 backend traits.  The old `Backend`
7// trait is defined in `backend.rs` and the new `Backend` trait is bdefined here
8//
9// The new backend trait has a few of improvements to the old backend trait:
10//   - UniFFI-compatible
11//   - async-based
12//   - Inputs per-request settings for things like timeouts, rather than using global values
13//
14// See `README.md` for details about the transition from the old to new API.
15
16use std::sync::{Arc, OnceLock};
17
18use crate::{
19    backend as old_backend, settings::GLOBAL_SETTINGS, ClientSettings, Request, Response, Result,
20    ViaductError,
21};
22
23#[uniffi::export(with_foreign)]
24#[async_trait::async_trait]
25pub trait Backend: Send + Sync + 'static {
26    async fn send_request(&self, request: Request, settings: ClientSettings) -> Result<Response>;
27}
28
29static REGISTERED_BACKEND: OnceLock<Arc<dyn Backend>> = OnceLock::new();
30
31#[uniffi::export]
32pub fn init_backend(backend: Arc<dyn Backend>) -> Result<()> {
33    old_backend::set_backend(Box::leak(Box::new(backend.clone())))?;
34    REGISTERED_BACKEND
35        .set(backend)
36        .map_err(|_| ViaductError::BackendAlreadyInitialized)
37}
38
39pub fn get_backend() -> Result<&'static Arc<dyn Backend>> {
40    REGISTERED_BACKEND
41        .get()
42        .ok_or(ViaductError::BackendNotInitialized)
43}
44
45impl old_backend::Backend for Arc<dyn Backend> {
46    fn send(&self, request: crate::Request) -> Result<crate::Response, crate::ViaductError> {
47        let settings = GLOBAL_SETTINGS.read();
48        // Do our best to map the old settings to the new
49        //
50        // In practice this should be okay, since no component ever overwrites the default, so we
51        // we can assume things like the read/connect timeout are always the same.
52        let client_settings = ClientSettings {
53            timeout: match settings.read_timeout {
54                Some(d) => d.as_millis() as u32,
55                None => 0,
56            },
57            redirect_limit: if settings.follow_redirects { 10 } else { 0 },
58        };
59        pollster::block_on(self.send_request(request, client_settings))
60    }
61}