use std::ops::{Bound, RangeBounds};
use std::sync::{Arc, Mutex};
use std::fmt::Debug;
use futures::future::{ready, BoxFuture};
use futures::stream::BoxStream;
use crate::dev::{AttrConfig, AttrInfo, AttrRead, AttrReady, AttrValueEvent, CommandInfo, DevInfo, DevSource, DevState, Named, NamedResult, RecordedResult};
use crate::value::{Scalar, Spectrum, Value};
use crate::error::{Error, Result};
pub trait Backend: Debug + Send + Sync {
fn connect(&self, itr: &str) -> BoxFuture<'_, Result<Arc<dyn BackendDev>>>;
fn connect_at(&self, host: &str, port: u16, name: &str) -> BoxFuture<'_, Result<Arc<dyn BackendDev>>>;
fn serve<'a>(&'a self, config: &'a BackendServerConfig) -> BoxFuture<'a, Result<Arc<dyn BackendServer>>>;
}
pub trait BackendDev: Debug + Send + Sync {
fn name(&self) -> BoxFuture<'_, Result<Arc<str>>>;
fn admin_dev_name(&self) -> BoxFuture<'_, Result<Arc<str>>>;
fn description(&self) -> BoxFuture<'_, Result<Arc<str>>>;
fn info(&self) -> BoxFuture<'_, Result<DevInfo>>;
fn ping(&self) -> BoxFuture<'_, Result<()>>;
fn state(&self) -> BoxFuture<'_, Result<DevState>>;
fn status(&self) -> BoxFuture<'_, Result<Scalar<str>>>;
fn black_box(&self, max: Option<usize>) -> BoxFuture<'_, Result<Spectrum<str>>>;
fn command(&self, name: Scalar<str>, input: Value, source: DevSource) -> BoxFuture<'_, Result<Value>>;
fn read_attr(&self, names: Option<Spectrum<str>>, source: DevSource) -> BoxFuture<'_, Result<Vec<NamedResult<AttrRead<Value>>>>>;
fn write_attr(&self, values: Vec<Named<Value>>) -> BoxFuture<'_, Result<Vec<Result<()>>>>;
fn write_read_attr(&self, values: Vec<Named<Value>>) -> BoxFuture<'_, Result<Vec<NamedResult<AttrRead<Value>>>>>;
fn command_info(&self, names: Option<Spectrum<str>>) -> BoxFuture<'_, Result<Vec<NamedResult<CommandInfo>>>>;
fn attr_info(&self, names: Option<Spectrum<str>>) -> BoxFuture<'_, Result<Vec<NamedResult<AttrInfo>>>>;
fn set_attr_config(&self, configs: Vec<Named<AttrConfig>>) -> BoxFuture<'_, Result<Vec<Result<()>>>>;
fn command_history(&self, name: Scalar<str>, max: usize) -> BoxFuture<'_, Result<Vec<RecordedResult<Value>>>>;
fn attr_history(&self, name: Scalar<str>, max: usize) -> BoxFuture<'_, Result<Vec<RecordedResult<AttrRead<Value>>>>>;
fn subscribe_attr_value(&self, admin: Arc<dyn BackendDev>, name: Scalar<str>, event: AttrValueEvent) -> BoxFuture<'_, Result<BoxStream<'static, Result<AttrRead<Value>>>>>;
fn subscribe_attr_ready(&self, admin: Arc<dyn BackendDev>, name: Scalar<str>) -> BoxFuture<'_, Result<BoxStream<'static, Result<AttrReady>>>>;
fn subscribe_attr_config(&self, admin: Arc<dyn BackendDev>, name: Scalar<str>) -> BoxFuture<'_, Result<BoxStream<'static, Result<AttrInfo>>>>;
}
pub trait BackendServer: Debug + Send + Sync {
fn add(&self, name: &str, dev: Arc<dyn BackendDev>) -> Result<Arc<str>>;
fn remove(&self, name: &str) -> bool;
fn host(&self) -> Arc<str>;
fn port(&self) -> u16;
fn version(&self) -> i32;
fn stop(&self);
fn wait(&self) -> BoxFuture<'_, ()>;
fn zmq_event_subscription_change(&self, _args: Spectrum<str>) -> BoxFuture<'_, Result<(Spectrum<i32>, Spectrum<str>)>> {
Box::pin(ready(Err(Error::not_implemented()
.with_description("Publishing events over ZMQ is not implemented by this server"))))
}
fn event_confirm_subscription(&self, _args: Spectrum<str>) -> BoxFuture<'_, Result<()>> {
Box::pin(ready(Err(Error::not_implemented()
.with_description("Publishing events over ZMQ is not implemented by this server"))))
}
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct BackendServerConfig {
pub host: Option<String>,
pub port: Option<(u16, u16)>,
pub admin_name: Option<Arc<str>>,
pub tango_host: Option<(Arc<str>, u16)>,
pub zmq_heartbeat_port: Option<(u16, u16)>,
pub zmq_event_port: Option<(u16, u16)>,
}
impl BackendServerConfig {
pub fn new() -> Self {
Self::default()
}
pub fn host(mut self, host: &str) -> Self {
self.host = Some(host.to_string());
self
}
pub fn port<R: RangeBounds<u16>>(mut self, port: R) -> Self {
self.port = Some(port_range_bounds(port));
self
}
pub fn admin_name(mut self, admin_name: impl Into<Arc<str>>) -> Self {
self.admin_name = Some(admin_name.into());
self
}
pub fn tango_host(mut self, host: impl Into<Arc<str>>, port: u16) -> Self {
self.tango_host = Some((host.into(), port));
self
}
pub fn zmq_heartbeat_port<R: RangeBounds<u16>>(mut self, port: R) -> Self {
self.zmq_heartbeat_port = Some(port_range_bounds(port));
self
}
pub fn zmq_event_port<R: RangeBounds<u16>>(mut self, port: R) -> Self {
self.zmq_event_port = Some(port_range_bounds(port));
self
}
}
fn port_range_bounds<R: RangeBounds<u16>>(range: R) -> (u16, u16) {
let start = match range.start_bound() {
Bound::Included(&start) => start,
Bound::Excluded(&start) => start.checked_add(1).expect("range start overflow"),
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(&end) => end,
Bound::Excluded(&end) => end.checked_sub(1).expect("range end underflow"),
Bound::Unbounded => u16::MAX,
};
assert!(start <= end, "slice index starts at {start} but ends at {end}");
(start, end)
}
static DEFAULT_BACKEND: Mutex<Option<Arc<dyn Backend>>> = Mutex::new(None);
pub fn default_backend() -> Arc<dyn Backend> {
match &mut *DEFAULT_BACKEND.lock().unwrap() {
Some(backend) => Arc::clone(backend),
opt @ None => {
let backend = crate::corba::CorbaBackend::new();
*opt = Some(Arc::clone(&backend) as Arc<dyn Backend>);
backend
}
}
}
pub fn set_default_backend(backend: Arc<dyn Backend>) {
*DEFAULT_BACKEND.lock().unwrap() = Some(backend);
}