use arti_client::{
TorClient,
rpc::{ClientConnectionResult, ConnectWithPrefs, ResolvePtrWithPrefs, ResolveWithPrefs},
};
use derive_deftly::Deftly;
use std::{net::IpAddr, sync::Arc};
use tor_error::into_internal;
use tor_rtcompat::Runtime;
use tor_rpcbase::{self as rpc, static_rpc_invoke_fn, templates::*};
#[derive(Deftly)]
#[derive_deftly(Object)]
#[deftly(rpc(expose_outside_of_session))]
pub struct RpcSession {
#[allow(unused)]
client: Arc<dyn Client>,
}
trait Client: rpc::Object {
fn isolated_client(&self) -> Arc<dyn rpc::Object>;
fn upcast_arc(self: Arc<Self>) -> Arc<dyn rpc::Object>;
}
impl<R: Runtime> Client for TorClient<R> {
fn isolated_client(&self) -> Arc<dyn rpc::Object> {
Arc::new(TorClient::isolated_client(self))
}
fn upcast_arc(self: Arc<Self>) -> Arc<dyn rpc::Object> {
self
}
}
impl RpcSession {
pub fn new_with_client<R: Runtime>(client: Arc<arti_client::TorClient<R>>) -> Arc<Self> {
Arc::new(Self { client })
}
fn client_as_object(&self) -> Arc<dyn rpc::Object> {
self.client.clone().upcast_arc()
}
}
#[derive(Debug, serde::Deserialize, serde::Serialize, Deftly)]
#[derive_deftly(DynMethod)]
#[deftly(rpc(method_name = "arti:get_client"))]
struct GetClient {}
impl rpc::RpcMethod for GetClient {
type Output = rpc::SingleIdResponse;
type Update = rpc::NoUpdates;
}
async fn get_client_on_session(
session: Arc<RpcSession>,
_method: Box<GetClient>,
ctx: Arc<dyn rpc::Context>,
) -> Result<rpc::SingleIdResponse, rpc::RpcError> {
Ok(rpc::SingleIdResponse::from(
ctx.register_owned(session.client.clone().upcast_arc()),
))
}
async fn isolated_client_on_session(
session: Arc<RpcSession>,
_method: Box<arti_client::rpc::IsolatedClient>,
ctx: Arc<dyn rpc::Context>,
) -> Result<rpc::SingleIdResponse, rpc::RpcError> {
let new_client = session.client.isolated_client();
Ok(rpc::SingleIdResponse::from(ctx.register_owned(new_client)))
}
async fn session_connect_with_prefs(
session: Arc<RpcSession>,
method: Box<ConnectWithPrefs>,
ctx: Arc<dyn rpc::Context>,
) -> ClientConnectionResult<arti_client::DataStream> {
*rpc::invoke_special_method(ctx, session.client_as_object(), method)
.await
.map_err(|e| Box::new(into_internal!("unable to delegate to TorClient")(e)) as _)?
}
async fn session_resolve_with_prefs(
session: Arc<RpcSession>,
method: Box<ResolveWithPrefs>,
ctx: Arc<dyn rpc::Context>,
) -> ClientConnectionResult<Vec<IpAddr>> {
*rpc::invoke_special_method(ctx, session.client_as_object(), method)
.await
.map_err(|e| Box::new(into_internal!("unable to delegate to TorClient")(e)) as _)?
}
async fn session_resolve_ptr_with_prefs(
session: Arc<RpcSession>,
method: Box<ResolvePtrWithPrefs>,
ctx: Arc<dyn rpc::Context>,
) -> ClientConnectionResult<Vec<String>> {
*rpc::invoke_special_method(ctx, session.client_as_object(), method)
.await
.map_err(|e| Box::new(into_internal!("unable to delegate to TorClient")(e)) as _)?
}
static_rpc_invoke_fn! {
get_client_on_session;
isolated_client_on_session;
@special session_connect_with_prefs;
@special session_resolve_with_prefs;
@special session_resolve_ptr_with_prefs;
}
#[cfg(feature = "describe-methods")]
#[allow(clippy::missing_docs_in_private_items)] mod list_all_methods {
use std::{convert::Infallible, sync::Arc};
use derive_deftly::Deftly;
use tor_rpcbase::{self as rpc, RpcDispatchInformation, static_rpc_invoke_fn, templates::*};
#[derive(Debug, serde::Deserialize, Deftly)]
#[derive_deftly(DynMethod)]
#[deftly(rpc(method_name = "arti:x_list_all_rpc_methods"))]
struct ListAllRpcMethods {}
impl rpc::RpcMethod for ListAllRpcMethods {
type Output = RpcDispatchInformation;
type Update = rpc::NoUpdates;
}
async fn session_list_all_rpc_methods(
_session: Arc<super::RpcSession>,
_method: Box<ListAllRpcMethods>,
ctx: Arc<dyn rpc::Context>,
) -> Result<RpcDispatchInformation, Infallible> {
Ok(ctx
.dispatch_table()
.read()
.expect("poisoned lock")
.dispatch_information())
}
static_rpc_invoke_fn! { session_list_all_rpc_methods; }
}