Skip to main content

arti_rpcserver/objmap/
methods.rs

1//! Implementations for rpc methods that interact with
2//! object IDs directly.
3//!
4//! (These methods do not use the regular dispatch system
5//! because they interact with the object map system in special ways.)
6
7use derive_deftly::Deftly;
8use futures::FutureExt as _;
9use std::sync::Arc;
10use tor_rpcbase::{self as rpc, SingleIdResponse, templates::*};
11
12/// Release a single ObjectID.
13///
14/// After calling this method, the provided ObjectID will no longer be usable,
15/// but other ObjectIDs for the same object may still exist.
16#[derive(Debug, serde::Deserialize, Deftly)]
17#[derive_deftly(DynMethod)]
18#[deftly(rpc(method_name = "rpc:release", bypass_method_dispatch))]
19struct RpcRelease {}
20
21impl rpc::RpcMethod for RpcRelease {
22    type Output = rpc::Nil;
23    type Update = rpc::NoUpdates;
24}
25
26impl rpc::DynMethod for RpcRelease {
27    fn invoke_without_dispatch(
28        &self,
29        ctx: Arc<dyn rpc::Context>,
30        obj_id: &rpc::ObjectId,
31    ) -> Result<tor_rpcbase::dispatch::RpcResultFuture, tor_rpcbase::InvokeError> {
32        let result = match ctx.release(obj_id) {
33            Ok(()) => Ok(Box::new(rpc::NIL) as _),
34            Err(e) => Err(rpc::RpcError::from(e)),
35        };
36        Ok(futures::future::ready(result).boxed())
37    }
38}
39
40/// Return a new object ID referring to an existing object.
41///
42/// This method does not clone the underlying object itself:
43/// the new ID as well as the old ID both refer to the same object.
44///
45/// Releases the original object ID if the `release` flag is true.
46/// Otherwise, makes no change to the original object ID.
47///
48/// This method can be used to create a weak ID from a strong ID,
49/// or vice versa.
50#[derive(Debug, serde::Deserialize, Deftly)]
51#[derive_deftly(DynMethod)]
52#[deftly(rpc(method_name = "rpc:clone_id", bypass_method_dispatch))]
53struct RpcCloneId {
54    /// If true, the new ID should be a weak reference.
55    /// If false, the new ID should be a strong reference.
56    ///
57    /// Defaults to "false".
58    #[serde(default)]
59    weak: bool,
60
61    /// If true, the original ID should be dropped.
62    #[serde(default)]
63    release: bool,
64}
65
66impl rpc::RpcMethod for RpcCloneId {
67    type Output = rpc::SingleIdResponse;
68    type Update = rpc::NoUpdates;
69}
70
71impl rpc::DynMethod for RpcCloneId {
72    fn invoke_without_dispatch(
73        &self,
74        ctx: Arc<dyn rpc::Context>,
75        obj_id: &rpc::ObjectId,
76    ) -> Result<tor_rpcbase::dispatch::RpcResultFuture, tor_rpcbase::InvokeError> {
77        let result = match ctx.lookup_object(obj_id) {
78            Ok(obj) => {
79                let new_id = if self.weak {
80                    ctx.register_weak(&obj)
81                } else {
82                    ctx.register_owned(obj)
83                };
84                if self.release {
85                    let _ignore = ctx.release(obj_id);
86                }
87                Ok(Box::new(SingleIdResponse::from(new_id)) as _)
88            }
89            Err(e) => Err(rpc::RpcError::from(e)),
90        };
91
92        Ok(futures::future::ready(result).boxed())
93    }
94}