router: cli: store extra CLI args by type

The CLI environment can now contain ApiType structs which can be
accessed by their type.
The TypeId is used since the options inside must be unique anyway and
we can't have the same type specified multiple times. It also makes
for a somewhat convenient interface:

    env.take_global_option::<ConnectInfo>()

where ConnectInfo is a struct containing the server, user, port, ...
since these will not be passed as *parameters* to the API functions.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2024-06-13 12:44:54 +02:00
parent 41b08323a7
commit 59f1bdbe85

View File

@ -1,5 +1,10 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use serde_json::Value; use serde_json::Value;
use proxmox_schema::ApiType;
use crate::{RpcEnvironment, RpcEnvironmentType}; use crate::{RpcEnvironment, RpcEnvironmentType};
/// `RpcEnvironmet` implementation for command line tools /// `RpcEnvironmet` implementation for command line tools
@ -7,12 +12,53 @@ use crate::{RpcEnvironment, RpcEnvironmentType};
pub struct CliEnvironment { pub struct CliEnvironment {
result_attributes: Value, result_attributes: Value,
auth_id: Option<String>, auth_id: Option<String>,
pub(crate) global_options: HashMap<TypeId, Box<dyn Any + Send + Sync + 'static>>,
} }
impl CliEnvironment { impl CliEnvironment {
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
/// Get a specific command line argument type.
pub fn global_option<T>(&self) -> Option<&T>
where
T: ApiType + Any + Send + Sync + 'static,
{
Some(
self.global_options
.get(&TypeId::of::<T>())?
.downcast_ref::<T>()
.unwrap(), // the map must only store correctly typed items!
)
}
/// Get a mutable reference to a specific command line argument type.
pub fn global_option_mut<T>(&mut self) -> Option<&T>
where
T: ApiType + Any + Send + Sync + 'static,
{
Some(
self.global_options
.get_mut(&TypeId::of::<T>())?
.downcast_mut::<T>()
.unwrap(), // the map must only store correctly typed items!
)
}
/// Take a command line argument struct out of the argument list.
pub fn take_global_option<T>(&mut self) -> Option<T>
where
T: ApiType + Any + Send + Sync + 'static,
{
Some(
*self
.global_options
.remove(&TypeId::of::<T>())?
.downcast::<T>()
.unwrap(), // the map must only store correctly typed items!
)
}
} }
impl RpcEnvironment for CliEnvironment { impl RpcEnvironment for CliEnvironment {