use tonic::transport::Channel;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct CallerId(String);
impl CallerId {
pub fn local_owner() -> Self {
Self("local-owner".to_string())
}
pub fn paired_device(pair_id: &str) -> Self {
Self(format!("paired-device:{pair_id}"))
}
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RunnerRoute {
pub device_id: Option<String>,
pub run_id: Option<String>,
pub runner_class: String,
}
pub trait OperationPermit: Send {}
impl<T: Send> OperationPermit for T {}
pub struct RoutedOperation {
pub channel: Channel,
pub permit: Box<dyn OperationPermit>,
}
#[derive(Debug, thiserror::Error)]
pub enum ControlError {
#[error("failed to generate control-plane identity: {0}")]
Identity(String),
#[error("invalid control-plane argument: {0}")]
InvalidArgument(&'static str),
#[error("unknown Device: {0}")]
UnknownDevice(String),
#[error("unknown Run: {0}")]
UnknownRun(String),
#[error("unknown Runner: {0}")]
UnknownRunner(String),
#[error("no RunnerProvider is registered for RunnerClass: {0}")]
RunnerProviderUnavailable(String),
#[error("Runner operation failed: {0}")]
RunnerOperation(String),
}
#[derive(Debug, thiserror::Error)]
pub enum PairingError {
#[error("pairing is not configured")]
NotConfigured,
#[error("pairing request is invalid: {0}")]
Invalid(String),
#[error("pairing token is invalid, expired, or has already been consumed")]
InvalidToken,
#[error("paired Device was not found: {0}")]
NotFound(String),
#[error("paired Device selector is ambiguous: {0}")]
Ambiguous(String),
#[error("Device credential is not paired or has been revoked")]
Unauthenticated,
#[error("pairing persistence failed: {0}")]
Persistence(String),
}
pub struct PairingToken {
pub token: String,
}
pub struct Enrollment {
pub device_id: String,
pub credential: String,
}
pub trait Pairing: Send + Sync {
fn authenticate_bearer(&self, credential: &str) -> Result<CallerId, PairingError>;
fn issue_token(&self, lifetime: Option<std::time::Duration>) -> Result<PairingToken, PairingError>;
fn enroll(&self, token: &str, device_id: String, label: String) -> Result<Enrollment, PairingError>;
fn revoke_device_credentials(&self, selector: &str) -> Result<bool, PairingError>;
fn set_enabled(&self, selector: &str, enabled: bool) -> Result<bool, PairingError>;
fn unpair(&self, selector: &str) -> Result<bool, PairingError>;
}
#[tonic::async_trait]
pub trait Control: Send + Sync {
fn list_devices(&self) -> Result<Vec<auv::devices::Device>, ControlError>;
fn get_device(&self, device_id: &str) -> Result<Option<auv::devices::Device>, ControlError>;
fn create_run(&self, caller: &CallerId, request: auv::runs::CreateRun) -> Result<auv::runs::Run, ControlError>;
async fn stop_run(&self, caller: &CallerId, run_id: &str, outcome: auv::runs::RunOutcome) -> Result<auv::runs::Run, ControlError>;
fn list_runs(&self, caller: &CallerId) -> Result<Vec<auv::runs::Run>, ControlError>;
fn get_run(&self, caller: &CallerId, run_id: &str) -> Result<auv::runs::Run, ControlError>;
fn list_runners(&self) -> Result<Vec<auv::runners::Runner>, ControlError>;
async fn create_runner(&self, request: auv::runners::CreateRunner) -> Result<auv::runners::Runner, ControlError>;
fn get_runner(&self, runner_id: &str) -> Result<auv::runners::Runner, ControlError>;
fn list_runner_classes(&self, device_id: Option<&str>) -> Result<Vec<auv::runners::RunnerClass>, ControlError>;
fn get_runner_class(&self, device_id: Option<&str>, runner_class: &str) -> Result<auv::runners::RunnerClass, ControlError>;
async fn delete_runner(&self, runner_id: &str, options: auv::runners::StopRunner) -> Result<auv::runners::Runner, ControlError>;
async fn admit_routed_channel(
&self,
caller: &CallerId,
route: RunnerRoute,
service: &str,
method: &str,
) -> Result<RoutedOperation, ControlError>;
async fn shutdown(&self);
fn has_live_runners(&self) -> bool;
}