rpc: Make the top-level returned object a "session".

This will make it easier to change the semantics of what exactly we
return, whether it has to be/contain a client, whether you can use
it to look up all the live objects, &etc.
This commit is contained in:
Nick Mathewson 2023-05-23 09:58:32 -04:00
parent 0993672cb2
commit fef8342be3
4 changed files with 67 additions and 38 deletions

View File

@ -8,7 +8,6 @@ use std::{
sync::{Arc, Mutex},
};
use arti_client::TorClient;
use asynchronous_codec::JsonCodecError;
use futures::{
channel::mpsc,
@ -19,7 +18,6 @@ use pin_project::pin_project;
use rpc::dispatch::BoxedUpdateSink;
use serde_json::error::Category as JsonErrorCategory;
use tor_async_utils::SinkExt as _;
use tor_rtcompat::PreferredRuntime;
use crate::{
cancel::{Cancel, CancelHandle},
@ -34,7 +32,7 @@ use tor_rpcbase as rpc;
///
/// Tracks information that persists from one request to another.
pub struct Connection {
/// The mutable state of this connection
/// The mutable state of this connection.
inner: Mutex<Inner>,
/// Lookup table to find the implementations for methods
@ -94,7 +92,7 @@ impl Connection {
}
/// Look up a given object by its object ID relative to this connection.
fn lookup_object(
pub(crate) fn lookup_object(
self: &Arc<Self>,
id: &rpc::ObjectId,
) -> Result<Arc<dyn rpc::Object>, rpc::LookupError> {
@ -380,34 +378,6 @@ impl rpc::Context for RequestContext {
}
}
/// A simple temporary method to echo a reply.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct Echo {
/// A message to echo.
msg: String,
}
rpc::decl_method! { "arti:x-echo" => Echo}
impl rpc::Method for Echo {
type Output = Echo;
type Update = rpc::NoUpdates;
}
/// Implementation for calling "echo" on a TorClient.
///
/// TODO RPC: Remove this. It shouldn't exist.
async fn echo_on_session(
_obj: Arc<TorClient<PreferredRuntime>>,
method: Box<Echo>,
_ctx: Box<dyn rpc::Context>,
) -> Result<Echo, rpc::RpcError> {
Ok(*method)
}
rpc::rpc_invoke_fn! {
echo_on_session(TorClient<PreferredRuntime>,Echo);
}
/// An error given when an RPC request is cancelled.
///
/// This is a separate type from [`crate::cancel::Cancelled`] since eventually

View File

@ -122,8 +122,8 @@ struct Authenticate {
/// A reply from the `Authenticate` method.
#[derive(Debug, serde::Serialize)]
struct AuthenticateReply {
/// An owned reference to a `TorClient` object.
client: Option<rpc::ObjectId>,
/// An owned reference to a `Session` object.
session: rpc::ObjectId,
}
rpc::decl_method! {"auth:authenticate" => Authenticate}
@ -159,10 +159,16 @@ async fn authenticate_connection(
AuthenticationScheme::InherentUnixPath => {}
}
let client = Arc::clone(&unauth.inner.lock().expect("Poisoned lock").client);
let client = Some(ctx.register_weak(client));
Ok(AuthenticateReply { client })
// TODO RPC: I'm actually not totally sure about the semantics of creating a
// new session object here, since it will _look_ separate from other
// sessions, but in fact they will all share the same object map.
//
// Perhaps we need to think more about the semantics of authenticating more
// then once on the same connection.
let client = unauth.inner.lock().expect("lock poisoned").client.clone();
let session = crate::session::Session::new(client);
let session = ctx.register_owned(session);
Ok(AuthenticateReply { session })
}
rpc::rpc_invoke_fn! {
authenticate_connection(Connection, Authenticate);

View File

@ -43,6 +43,7 @@ mod err;
mod mgr;
mod msgs;
mod objmap;
mod session;
mod streams;
pub use connection::{Connection, ConnectionError};

View File

@ -0,0 +1,52 @@
//! High-level APIs for an RPC session
//!
//! A "session" is created when a user authenticates on an RPC connection. It
//! is the root for all other RPC capabilities.
use std::sync::Arc;
use tor_rpcbase as rpc;
/// An authenticated RPC session.
pub(crate) struct Session {
/// An inner TorClient object that we use to implement remaining
/// functionality.
#[allow(unused)]
client: Arc<dyn rpc::Object>,
}
impl rpc::Object for Session {}
rpc::decl_object! {Session}
impl Session {
/// Create a new session object.
pub(crate) fn new(client: Arc<dyn rpc::Object>) -> Arc<Self> {
Arc::new(Self { client })
}
}
/// A simple temporary method to echo a reply.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct Echo {
/// A message to echo.
msg: String,
}
rpc::decl_method! { "arti:x-echo" => Echo}
impl rpc::Method for Echo {
type Output = Echo;
type Update = rpc::NoUpdates;
}
/// Implementation for calling "echo" on a Session.
///
/// TODO RPC: Remove this. It shouldn't exist.
async fn echo_on_session(
_obj: Arc<Session>,
method: Box<Echo>,
_ctx: Box<dyn rpc::Context>,
) -> Result<Echo, rpc::RpcError> {
Ok(*method)
}
rpc::rpc_invoke_fn! {
echo_on_session(Session,Echo);
}