1
//! A wrapper around an RPC Object that can be used as a connection target.
2

            
3
use arti_client::{
4
    rpc::{ClientConnectionResult, ConnectWithPrefs, ResolvePtrWithPrefs, ResolveWithPrefs},
5
    DataStream, StreamPrefs, TorAddr, TorClient,
6
};
7
use std::{net::IpAddr, sync::Arc};
8
use tor_error::into_internal;
9
use tor_rpcbase as rpc;
10
use tor_rtcompat::Runtime;
11

            
12
/// Wrapper around an RPC object that can be used as a connection target,
13
/// or around a TorClient if no RPC object is given.
14
///
15
/// Provides an API similar to TorClient, for use when opening SOCKS connections.
16
pub(crate) enum ConnTarget<R: Runtime> {
17
    /// An RPC object with accompanying context.
18
    Rpc {
19
        /// The RPC object on which to build our connections.
20
        object: Arc<dyn rpc::Object>,
21
        /// The RPC context in which to invoke methods
22
        context: Arc<dyn rpc::Context>,
23
    },
24
    /// A Tor client, without RPC information
25
    Client(TorClient<R>),
26
}
27

            
28
impl<R: Runtime> ConnTarget<R> {
29
    /// As [`TorClient::connect_with_prefs`].
30
    pub(crate) async fn connect_with_prefs(
31
        &self,
32
        target: &TorAddr,
33
        prefs: &StreamPrefs,
34
    ) -> ClientConnectionResult<DataStream> {
35
        match self {
36
            ConnTarget::Rpc {
37
                object: obj,
38
                context,
39
            } => {
40
                let method = ConnectWithPrefs {
41
                    target: target.clone(),
42
                    prefs: prefs.clone(),
43
                };
44
                *rpc::invoke_special_method(context.clone(), obj.clone(), Box::new(method) as _)
45
                    .await
46
                    .map_err(|e| {
47
                        Box::new(into_internal!("unable to delegate to RPC object")(e)) as _
48
                    })?
49
            }
50
            ConnTarget::Client(client) => client
51
                .connect_with_prefs(target, prefs)
52
                .await
53
                .map_err(|e| Box::new(e) as _),
54
        }
55
    }
56

            
57
    /// As [`TorClient::resolve_with_prefs`]
58
    pub(crate) async fn resolve_with_prefs(
59
        &self,
60
        hostname: &str,
61
        prefs: &StreamPrefs,
62
    ) -> ClientConnectionResult<Vec<IpAddr>> {
63
        match self {
64
            ConnTarget::Rpc {
65
                object: obj,
66
                context,
67
            } => {
68
                let method = ResolveWithPrefs {
69
                    hostname: hostname.to_string(),
70
                    prefs: prefs.clone(),
71
                };
72
                *rpc::invoke_special_method(context.clone(), obj.clone(), Box::new(method) as _)
73
                    .await
74
                    .map_err(|e| {
75
                        Box::new(into_internal!("unable to delegate to RPC object")(e)) as _
76
                    })?
77
            }
78
            ConnTarget::Client(client) => client
79
                .resolve_with_prefs(hostname, prefs)
80
                .await
81
                .map_err(|e| Box::new(e) as _),
82
        }
83
    }
84

            
85
    /// As [`TorClient::resolve_ptr_with_prefs`]
86
    pub(crate) async fn resolve_ptr_with_prefs(
87
        self,
88
        addr: IpAddr,
89
        prefs: &StreamPrefs,
90
    ) -> ClientConnectionResult<Vec<String>> {
91
        match self {
92
            ConnTarget::Rpc {
93
                object: obj,
94
                context,
95
            } => {
96
                let method = ResolvePtrWithPrefs {
97
                    addr,
98
                    prefs: prefs.clone(),
99
                };
100
                *rpc::invoke_special_method(context.clone(), obj.clone(), Box::new(method) as _)
101
                    .await
102
                    .map_err(|e| {
103
                        Box::new(into_internal!("unable to delegate to RPC object")(e)) as _
104
                    })?
105
            }
106
            ConnTarget::Client(client) => client
107
                .resolve_ptr_with_prefs(addr, prefs)
108
                .await
109
                .map_err(|e| Box::new(e) as _),
110
        }
111
    }
112
}