use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::Arc;
use coap_lite::link_format::LINK_ATTR_OBSERVABLE;
use coap_lite::RequestType;
use tokio::sync::Mutex;
use crate::app::app_builder::ConfigBuilder;
use crate::app::block_handler_util::new_block_handler;
use crate::app::core_link::{CoreLink, LinkAttributeValue};
use crate::app::observable_resource::ObservableResource;
use crate::app::observe_handler::ObserveHandler;
use crate::app::request_handler::RequestHandler;
use crate::app::request_type_key::RequestTypeKey;
use crate::app::resource_handler::ResourceHandler;
use crate::app::retransmission_manager::RetransmissionManager;
pub struct ResourceBuilder<Endpoint: Ord + Clone> {
path: String,
config: ConfigBuilder,
attributes: CoreLink,
handlers: HashMap<RequestTypeKey, Box<dyn RequestHandler<Endpoint> + Send + Sync>>,
observable: Option<Box<dyn ObservableResource + Send + Sync>>,
}
impl<Endpoint: Debug + Clone + Eq + Hash + Ord + Send + 'static> ResourceBuilder<Endpoint> {
pub fn new(path: &str) -> Self {
Self {
path: path.to_string(),
config: ConfigBuilder::default(),
attributes: CoreLink::new(path),
handlers: HashMap::new(),
observable: None,
}
}
pub fn not_discoverable(mut self) -> Self {
self.config.discoverable = Some(false);
self
}
pub fn disable_block_transfer(mut self) -> Self {
self.config.block_transfer = Some(false);
self
}
pub fn link_attr(
mut self,
attr_name: &'static str,
value: impl LinkAttributeValue<String> + 'static,
) -> Self {
self.attributes.attr(attr_name, value);
self
}
pub fn default_handler(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestTypeKey::new_match_all(), handler)
}
pub fn get(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::Get.into(), handler)
}
pub fn post(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::Post.into(), handler)
}
pub fn put(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::Put.into(), handler)
}
pub fn delete(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::Delete.into(), handler)
}
pub fn fetch(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::Fetch.into(), handler)
}
pub fn patch(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::Patch.into(), handler)
}
pub fn ipatch(self, handler: impl RequestHandler<Endpoint> + Send + Sync) -> Self {
self.handler(RequestType::IPatch.into(), handler)
}
pub fn method_handler(
self,
request_type: RequestType,
handler: impl RequestHandler<Endpoint> + Send + Sync,
) -> Self {
self.handler(request_type.into(), handler)
}
fn handler(
mut self,
key: RequestTypeKey,
handler: impl RequestHandler<Endpoint> + Send + Sync,
) -> Self {
self.handlers.insert(key, Box::new(handler));
self
}
pub fn observable(mut self, observable: impl ObservableResource + Send + Sync) -> Self {
self.observable = Some(Box::new(observable));
self.link_attr(LINK_ATTR_OBSERVABLE, ())
}
pub(crate) fn build(self, params: BuildParameters<Endpoint>) -> Resource<Endpoint> {
let discoverable = if self.config.discoverable.unwrap_or(true) {
Some(DiscoverableResource::from(self.attributes))
} else {
None
};
let observe_handler = self
.observable
.map(|x| Arc::new(Mutex::new(ObserveHandler::new(self.path.clone(), x))));
let block_transfer = self
.config
.block_transfer
.unwrap_or(crate::app::app_handler::DEFAULT_BLOCK_TRANSFER);
let block_handler = if block_transfer {
Some(Arc::new(Mutex::new(new_block_handler(params.mtu))))
} else {
None
};
let handler = ResourceHandler {
handlers: self.handlers,
observe_handler,
block_handler,
retransmission_manager: params.retransmission_manager,
};
Resource {
path: self.path,
discoverable,
handler,
}
}
}
#[derive(Clone)]
pub(crate) struct BuildParameters<Endpoint: Debug + Clone + Eq + Hash> {
pub mtu: Option<u32>,
pub retransmission_manager: Arc<Mutex<RetransmissionManager<Endpoint>>>,
}
#[derive(Clone)]
pub(crate) struct DiscoverableResource {
pub link_str: String,
pub attributes_as_string: HashMap<&'static str, String>,
}
pub(crate) struct Resource<Endpoint: Debug + Clone + Ord + Eq + Hash> {
pub path: String,
pub discoverable: Option<DiscoverableResource>,
pub handler: ResourceHandler<Endpoint>,
}