use std::slice;
use aranya_daemon_api as api;
use aranya_id::custom_id;
use serde::{Deserialize, Serialize};
use tracing::instrument;
use crate::{
client::{ChanOp, Client, Label, LabelId, Labels, Role, RoleId},
error::{aranya_error, IpcError, Result},
util::{impl_slice_iter_wrapper, rpc_context, ApiConv as _, ApiId},
};
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
#[serde(transparent)]
pub struct PublicKeyBundle(api::PublicKeyBundle);
#[deprecated(note = "use `PublicKeyBundle`")]
pub type KeyBundle = PublicKeyBundle;
impl PublicKeyBundle {
pub(crate) fn from_api(api: api::PublicKeyBundle) -> Self {
Self(api)
}
pub(crate) fn into_api(self) -> api::PublicKeyBundle {
self.0
}
pub fn encryption(&self) -> &[u8] {
&self.0.encryption
}
}
custom_id! {
pub struct DeviceId;
}
impl ApiId<api::DeviceId> for DeviceId {}
#[derive(Debug)]
pub struct Devices {
pub(super) data: Box<[DeviceId]>,
}
impl Devices {
pub fn iter(&self) -> IterDevices<'_> {
IterDevices(self.data.iter())
}
#[doc(hidden)]
pub fn __data(&self) -> &[DeviceId] {
&self.data
}
}
#[derive(Clone, Debug)]
pub struct IterDevices<'a>(slice::Iter<'a, DeviceId>);
impl_slice_iter_wrapper!(IterDevices<'a> for DeviceId);
#[derive(Debug)]
pub struct Device<'a> {
pub(super) client: &'a Client,
pub(super) id: api::DeviceId,
pub(super) team_id: api::TeamId,
}
impl Device<'_> {
pub fn id(&self) -> DeviceId {
DeviceId::from_api(self.id)
}
#[deprecated(note = "Use `public_key_bundle`.")]
pub async fn keybundle(&self) -> Result<PublicKeyBundle> {
self.public_key_bundle().await
}
pub async fn public_key_bundle(&self) -> Result<PublicKeyBundle> {
self.client
.daemon
.device_public_key_bundle(rpc_context(), self.team_id, self.id)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
.map(PublicKeyBundle::from_api)
}
#[instrument(skip(self))]
pub async fn remove_from_team(&self) -> Result<()> {
self.client
.daemon
.remove_device_from_team(rpc_context(), self.team_id, self.id)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
}
#[instrument(skip(self))]
pub async fn assign_role(&self, role: RoleId) -> Result<()> {
self.client
.daemon
.assign_role(rpc_context(), self.team_id, self.id, role.into_api())
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
}
#[instrument(skip(self))]
pub async fn revoke_role(&self, role: RoleId) -> Result<()> {
self.client
.daemon
.revoke_role(rpc_context(), self.team_id, self.id, role.into_api())
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
}
#[instrument(skip(self))]
pub async fn change_role(&self, old_role: RoleId, new_role: RoleId) -> Result<()> {
self.client
.daemon
.change_role(
rpc_context(),
self.team_id,
self.id,
old_role.into_api(),
new_role.into_api(),
)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
}
pub async fn role(&self) -> Result<Option<Role>> {
let role = self
.client
.daemon
.device_role(rpc_context(), self.team_id, self.id)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)?
.map(Role::from_api);
Ok(role)
}
pub async fn label_assignments(&self) -> Result<Labels> {
let data = self
.client
.daemon
.labels_assigned_to_device(rpc_context(), self.team_id, self.id)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)?
.into_vec()
.into_iter()
.map(Label::from_api)
.collect();
Ok(Labels { labels: data })
}
#[instrument(skip(self))]
pub async fn assign_label(&self, label: LabelId, op: ChanOp) -> Result<()> {
self.client
.daemon
.assign_label_to_device(rpc_context(), self.team_id, self.id, label.into_api(), op)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
}
#[instrument(skip(self))]
pub async fn revoke_label(&self, label: LabelId) -> Result<()> {
self.client
.daemon
.revoke_label_from_device(rpc_context(), self.team_id, self.id, label.into_api())
.await
.map_err(IpcError::new)?
.map_err(aranya_error)
}
#[cfg(test)]
pub async fn generation(&self) -> Result<Option<i64>> {
let gen = self
.client
.daemon
.query_device_generation(rpc_context(), self.team_id, self.id)
.await
.map_err(IpcError::new)?
.map_err(aranya_error)?;
Ok(gen)
}
}