aranya_daemon_api/
service.rs#![allow(clippy::disallowed_macros)] use core::{fmt, net::SocketAddr, time::Duration};
use aranya_crypto::{
afc::{BidiChannelId, UniChannelId},
custom_id,
default::DefaultCipherSuite,
Id,
};
use aranya_fast_channels::{Label, NodeId};
use aranya_util::Addr;
use serde::{Deserialize, Serialize};
use tracing::error;
pub type CS = DefaultCipherSuite;
#[derive(Serialize, Deserialize, Debug)]
pub struct Error(String);
impl From<anyhow::Error> for Error {
fn from(err: anyhow::Error) -> Self {
error!(?err);
Self(format!("{err:?}"))
}
}
impl From<aranya_crypto::id::IdError> for Error {
fn from(err: aranya_crypto::id::IdError) -> Self {
error!(%err);
Self(err.to_string())
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl core::error::Error for Error {}
pub type Result<T, E = Error> = core::result::Result<T, E>;
custom_id! {
pub struct DeviceId;
}
custom_id! {
pub struct TeamId;
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct KeyBundle {
pub identity: Vec<u8>,
pub signing: Vec<u8>,
pub encoding: Vec<u8>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub enum Role {
Owner,
Admin,
Operator,
Member,
}
#[derive(Clone, Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
pub struct NetIdentifier(pub String);
const AFC_ID_LEN: usize = 16;
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, Eq, Ord, PartialEq, PartialOrd)]
pub struct AfcId {
id: [u8; AFC_ID_LEN],
}
fn truncate<const BIG: usize, const SMALL: usize>(arr: &[u8; BIG]) -> &[u8; SMALL] {
const { assert!(BIG >= SMALL) };
arr[..SMALL].try_into().expect("array must fit")
}
impl From<BidiChannelId> for AfcId {
fn from(value: BidiChannelId) -> Self {
Self {
id: *truncate(value.as_array()),
}
}
}
impl From<UniChannelId> for AfcId {
fn from(value: UniChannelId) -> Self {
Self {
id: *truncate(value.as_array()),
}
}
}
impl From<Id> for AfcId {
fn from(value: Id) -> Self {
Self {
id: *truncate(value.as_array()),
}
}
}
pub type AfcCtrl = Vec<Box<[u8]>>;
#[tarpc::service]
pub trait DaemonApi {
async fn aranya_local_addr() -> Result<SocketAddr>;
async fn get_key_bundle() -> Result<KeyBundle>;
async fn get_device_id() -> Result<DeviceId>;
async fn add_sync_peer(addr: Addr, team: TeamId, interval: Duration) -> Result<()>;
async fn remove_sync_peer(addr: Addr, team: TeamId) -> Result<()>;
async fn add_team(team: TeamId) -> Result<()>;
async fn remove_team(team: TeamId) -> Result<()>;
async fn create_team() -> Result<TeamId>;
async fn close_team(team: TeamId) -> Result<()>;
async fn add_device_to_team(team: TeamId, keys: KeyBundle) -> Result<()>;
async fn remove_device_from_team(team: TeamId, device: DeviceId) -> Result<()>;
async fn assign_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
async fn revoke_role(team: TeamId, device: DeviceId, role: Role) -> Result<()>;
async fn assign_net_identifier(
team: TeamId,
device: DeviceId,
name: NetIdentifier,
) -> Result<()>;
async fn remove_net_identifier(
team: TeamId,
device: DeviceId,
name: NetIdentifier,
) -> Result<()>;
async fn create_label(team: TeamId, label: Label) -> Result<()>;
async fn delete_label(team: TeamId, label: Label) -> Result<()>;
async fn assign_label(team: TeamId, device: DeviceId, label: Label) -> Result<()>;
async fn revoke_label(team: TeamId, device: DeviceId, label: Label) -> Result<()>;
async fn create_bidi_channel(
team: TeamId,
peer: NetIdentifier,
node_id: NodeId,
label: Label,
) -> Result<(AfcId, AfcCtrl)>;
async fn delete_channel(chan: AfcId) -> Result<AfcCtrl>;
async fn receive_afc_ctrl(
team: TeamId,
node_id: NodeId,
ctrl: AfcCtrl,
) -> Result<(AfcId, NetIdentifier, Label)>;
}