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

            
7
use derive_deftly::Deftly;
8
use futures::FutureExt as _;
9
use std::sync::Arc;
10
use 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))]
19
struct RpcRelease {}
20

            
21
impl rpc::RpcMethod for RpcRelease {
22
    type Output = rpc::Nil;
23
    type Update = rpc::NoUpdates;
24
}
25

            
26
impl 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))]
53
struct 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

            
66
impl rpc::RpcMethod for RpcCloneId {
67
    type Output = rpc::SingleIdResponse;
68
    type Update = rpc::NoUpdates;
69
}
70

            
71
impl 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
}