aranya_client/client/
device.rs1use std::slice;
2
3use aranya_daemon_api as api;
4use aranya_id::custom_id;
5use serde::{Deserialize, Serialize};
6use tracing::instrument;
7
8use crate::{
9 client::{create_ctx, ChanOp, Client, Label, LabelId, Labels, Role, RoleId},
10 error::{aranya_error, IpcError, Result},
11 util::{impl_slice_iter_wrapper, ApiConv as _, ApiId},
12};
13
14#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
16#[serde(transparent)]
17pub struct PublicKeyBundle(api::PublicKeyBundle);
18
19#[deprecated(note = "use `PublicKeyBundle`")]
21pub type KeyBundle = PublicKeyBundle;
22
23impl PublicKeyBundle {
24 #[doc(hidden)]
25 pub fn from_api(api: api::PublicKeyBundle) -> Self {
26 Self(api)
27 }
28
29 #[doc(hidden)]
30 pub fn into_api(self) -> api::PublicKeyBundle {
31 self.0
32 }
33
34 pub fn encryption(&self) -> &[u8] {
36 &self.0.encryption
37 }
38}
39
40custom_id! {
41 pub struct DeviceId;
43}
44impl ApiId<api::DeviceId> for DeviceId {}
45
46#[derive(Debug)]
48pub struct Devices {
49 pub(super) data: Box<[DeviceId]>,
50}
51
52impl Devices {
53 pub fn iter(&self) -> IterDevices<'_> {
55 IterDevices(self.data.iter())
56 }
57
58 #[doc(hidden)]
59 pub fn __data(&self) -> &[DeviceId] {
60 &self.data
61 }
62}
63
64#[derive(Clone, Debug)]
66pub struct IterDevices<'a>(slice::Iter<'a, DeviceId>);
67
68impl_slice_iter_wrapper!(IterDevices<'a> for DeviceId);
69
70#[derive(Debug)]
72pub struct Device<'a> {
73 pub(super) client: &'a Client,
74 pub(super) id: api::DeviceId,
75 pub(super) team_id: api::TeamId,
76}
77
78impl Device<'_> {
79 pub fn id(&self) -> DeviceId {
81 DeviceId::from_api(self.id)
82 }
83
84 #[deprecated(note = "Use `public_key_bundle`.")]
86 pub async fn keybundle(&self) -> Result<PublicKeyBundle> {
87 self.public_key_bundle().await
88 }
89
90 pub async fn public_key_bundle(&self) -> Result<PublicKeyBundle> {
92 self.client
93 .daemon
94 .device_public_key_bundle(create_ctx(), self.team_id, self.id)
95 .await
96 .map_err(IpcError::new)?
97 .map_err(aranya_error)
98 .map(PublicKeyBundle::from_api)
99 }
100
101 #[instrument(skip(self))]
103 pub async fn remove_from_team(&self) -> Result<()> {
104 self.client
105 .daemon
106 .remove_device_from_team(create_ctx(), self.team_id, self.id)
107 .await
108 .map_err(IpcError::new)?
109 .map_err(aranya_error)
110 }
111
112 #[instrument(skip(self))]
114 pub async fn assign_role(&self, role: RoleId) -> Result<()> {
115 self.client
116 .daemon
117 .assign_role(create_ctx(), self.team_id, self.id, role.into_api())
118 .await
119 .map_err(IpcError::new)?
120 .map_err(aranya_error)
121 }
122
123 #[instrument(skip(self))]
125 pub async fn revoke_role(&self, role: RoleId) -> Result<()> {
126 self.client
127 .daemon
128 .revoke_role(create_ctx(), self.team_id, self.id, role.into_api())
129 .await
130 .map_err(IpcError::new)?
131 .map_err(aranya_error)
132 }
133
134 #[instrument(skip(self))]
136 pub async fn change_role(&self, old_role: RoleId, new_role: RoleId) -> Result<()> {
137 self.client
138 .daemon
139 .change_role(
140 create_ctx(),
141 self.team_id,
142 self.id,
143 old_role.into_api(),
144 new_role.into_api(),
145 )
146 .await
147 .map_err(IpcError::new)?
148 .map_err(aranya_error)
149 }
150
151 pub async fn role(&self) -> Result<Option<Role>> {
153 let role = self
154 .client
155 .daemon
156 .device_role(create_ctx(), self.team_id, self.id)
157 .await
158 .map_err(IpcError::new)?
159 .map_err(aranya_error)?
160 .map(Role::from_api);
161 Ok(role)
162 }
163
164 pub async fn label_assignments(&self) -> Result<Labels> {
166 let data = self
167 .client
168 .daemon
169 .labels_assigned_to_device(create_ctx(), self.team_id, self.id)
170 .await
171 .map_err(IpcError::new)?
172 .map_err(aranya_error)?
173 .into_vec()
177 .into_iter()
178 .map(Label::from_api)
179 .collect();
180 Ok(Labels { labels: data })
181 }
182
183 #[instrument(skip(self))]
185 pub async fn assign_label(&self, label: LabelId, op: ChanOp) -> Result<()> {
186 self.client
187 .daemon
188 .assign_label_to_device(create_ctx(), self.team_id, self.id, label.into_api(), op)
189 .await
190 .map_err(IpcError::new)?
191 .map_err(aranya_error)
192 }
193
194 #[instrument(skip(self))]
196 pub async fn revoke_label(&self, label: LabelId) -> Result<()> {
197 self.client
198 .daemon
199 .revoke_label_from_device(create_ctx(), self.team_id, self.id, label.into_api())
200 .await
201 .map_err(IpcError::new)?
202 .map_err(aranya_error)
203 }
204}