use crate::error::{Result, StatusCode};
use crate::{FromIBinder, SIBinder, Strong};
pub trait Registry {
fn add_service(&self, name: &str, binder: SIBinder) -> Result<()>;
}
pub trait Broker {
fn lookup(&self, name: &str) -> Result<SIBinder>;
fn get_interface<T: FromIBinder + ?Sized>(&self, name: &str) -> Result<Strong<T>>
where
Self: Sized,
{
FromIBinder::try_from(self.lookup(name)?)
}
}
pub mod kernel {
use super::*;
use crate::process_state::{CallRestriction, ProcessState};
fn init(driver: Option<&std::path::Path>, max_threads: u32) -> Result<()> {
let pre = ProcessState::is_initialized();
let ps = match driver {
Some(p) => ProcessState::init(&p.to_string_lossy(), max_threads),
None => ProcessState::init_default(),
}
.map_err(|e| {
log::error!("kernel::Host: ProcessState init failed: {e}");
StatusCode::NoInit
})?;
if pre {
let want_driver = driver.map(|p| p.to_path_buf());
let driver_mismatch = want_driver
.as_deref()
.is_some_and(|d| d != ps.driver_name());
let threads_mismatch = max_threads != 0
&& ProcessState::clamp_max_threads(max_threads) != ps.max_threads();
if driver_mismatch || threads_mismatch {
log::warn!(
"kernel::Host: ProcessState already initialized; requested \
driver={driver:?} max_threads={max_threads} ignored, using \
existing driver={:?} max_threads={}",
ps.driver_name(),
ps.max_threads()
);
}
}
Ok(())
}
pub struct Host {
_priv: (),
}
impl Host {
pub fn new() -> Result<Self> {
init(None, 0)?;
Ok(Host { _priv: () })
}
pub fn builder() -> HostBuilder {
HostBuilder::default()
}
pub fn serve(&self) -> Result<()> {
ProcessState::start_thread_pool();
ProcessState::join_thread_pool()
}
}
impl Registry for Host {
fn add_service(&self, name: &str, binder: SIBinder) -> Result<()> {
crate::hub::add_service(name, binder).map_err(StatusCode::from)
}
}
#[derive(Default)]
pub struct HostBuilder {
driver: Option<std::path::PathBuf>,
max_threads: u32,
call_restriction: Option<CallRestriction>,
}
impl HostBuilder {
pub fn driver(mut self, path: impl Into<std::path::PathBuf>) -> Self {
self.driver = Some(path.into());
self
}
pub fn max_threads(mut self, n: u32) -> Self {
self.max_threads = n;
self
}
pub fn call_restriction(mut self, cr: CallRestriction) -> Self {
self.call_restriction = Some(cr);
self
}
pub fn build(self) -> Result<Host> {
init(self.driver.as_deref(), self.max_threads)?;
if let Some(cr) = self.call_restriction {
ProcessState::as_self().set_call_restriction(cr);
}
Ok(Host { _priv: () })
}
}
pub struct Broker {
_priv: (),
}
impl Broker {
pub fn new() -> Result<Self> {
init(None, 0)?;
Ok(Broker { _priv: () })
}
}
impl super::Broker for Broker {
fn lookup(&self, name: &str) -> Result<SIBinder> {
crate::hub::get_service(name).ok_or(StatusCode::NameNotFound)
}
}
}
#[cfg(feature = "rpc")]
pub mod rpc {
use super::*;
use crate::rpc::transport::PeerIdentity;
use crate::rpc::{RpcServer, RpcSession};
use std::sync::Arc;
pub struct Host {
server: Arc<RpcServer>,
}
impl Host {
pub fn unix(path: impl Into<std::path::PathBuf>) -> Result<Self> {
Ok(Host {
server: RpcServer::setup_unix_server(path)?,
})
}
pub fn builder() -> HostBuilder {
HostBuilder::default()
}
pub fn server(&self) -> &Arc<RpcServer> {
&self.server
}
pub fn serve(&self) -> Result<()> {
self.server.run()
}
pub fn serve_background(&self) -> std::thread::JoinHandle<()> {
self.server.run_background()
}
}
impl Registry for Host {
fn add_service(&self, name: &str, binder: SIBinder) -> Result<()> {
self.server.add_service(name, binder)
}
}
type Authorizer = Box<dyn Fn(&PeerIdentity) -> bool + Send + Sync + 'static>;
#[derive(Default)]
pub struct HostBuilder {
path: Option<std::path::PathBuf>,
max_threads: Option<u32>,
max_connections: Option<usize>,
authorizer: Option<Authorizer>,
}
impl HostBuilder {
pub fn unix(mut self, path: impl Into<std::path::PathBuf>) -> Self {
self.path = Some(path.into());
self
}
pub fn max_threads(mut self, n: u32) -> Self {
self.max_threads = Some(n);
self
}
pub fn max_connections(mut self, n: usize) -> Self {
self.max_connections = Some(n);
self
}
pub fn authorizer<F>(mut self, f: F) -> Self
where
F: Fn(&PeerIdentity) -> bool + Send + Sync + 'static,
{
self.authorizer = Some(Box::new(f));
self
}
pub fn build(self) -> Result<Host> {
let path = self.path.ok_or(StatusCode::BadValue)?;
let server = RpcServer::setup_unix_server(path)?;
if let Some(n) = self.max_threads {
server.set_max_threads(n);
}
if let Some(n) = self.max_connections {
server.set_max_connections(n);
}
if let Some(f) = self.authorizer {
server.set_authorizer(f);
}
Ok(Host { server })
}
}
pub struct Broker {
session: RpcSession,
}
impl Broker {
pub fn unix(path: impl AsRef<std::path::Path>) -> Result<Self> {
Ok(Broker {
session: RpcSession::setup_unix_client(path)?,
})
}
pub fn session(&self) -> &RpcSession {
&self.session
}
}
impl super::Broker for Broker {
fn lookup(&self, name: &str) -> Result<SIBinder> {
self.session.get_service(name)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn traits_are_object_safe() {
fn _registry(_: &dyn Registry) {}
fn _broker(_: &dyn Broker) {}
}
}