use crate::wkc::{write_link_format, Reporting};
use coap_handler::Handler;
use coap_message::{MessageOption, MutableWritableMessage, ReadableMessage};
const LINK_FORMAT: u16 = 40;
pub struct WellKnownCore<H: Reporting + Handler>(H);
impl<H: Reporting + Handler> WellKnownCore<H> {
pub(crate) fn new(handler: H) -> Self {
WellKnownCore(handler)
}
}
pub enum WkcData<T> {
Wkc {
code: u8,
block2: crate::helpers::Block2RequestData,
},
Other(T),
}
impl<H: Reporting + Handler> Handler for WellKnownCore<H> {
type RequestData = WkcData<H::RequestData>;
fn extract_request_data(&mut self, req: &impl ReadableMessage) -> Self::RequestData {
use crate::option_processing::OptionsExt;
let mut block2 = None;
let mut pathmatch = 0;
let mut accept: Option<u16> = None;
let opts = req
.options()
.ignore_uri_host()
.filter(|o| match o.number() {
coap_numbers::option::ACCEPT if accept.is_none() => {
accept = o.value_uint();
accept.is_none()
}
_ => true,
})
.ignore_uri_query()
.take_block2(&mut block2)
.take_uri_path(|p| {
pathmatch = match (pathmatch, p) {
(0, ".well-known") => 1,
(1, "core") => 2,
_ => -1,
}
});
let remaining = opts.ignore_elective_others();
let block2 = block2.unwrap_or_default();
if pathmatch == 2 {
let code;
if remaining.is_err() {
code = coap_numbers::code::BAD_OPTION;
} else if accept.unwrap_or(LINK_FORMAT) != LINK_FORMAT {
code = coap_numbers::code::NOT_ACCEPTABLE;
} else {
code = coap_numbers::code::CONTENT;
}
WkcData::Wkc { code, block2 }
} else {
WkcData::Other(self.0.extract_request_data(req))
}
}
fn estimate_length(&mut self, req: &Self::RequestData) -> usize {
match req {
WkcData::Wkc { .. } => 1024,
WkcData::Other(req) => self.0.estimate_length(req),
}
}
fn build_response(&mut self, m: &mut impl MutableWritableMessage, req: Self::RequestData) {
match req {
WkcData::Wkc { code, block2 } => {
m.set_code(crate::helpers::codeconvert(code));
if code == coap_numbers::code::CONTENT {
crate::helpers::block2_write_with_cf(
block2,
m,
|w| {
write_link_format(w, &self.0, &[]).expect("Block writers do not err.");
},
Some(40),
);
} else {
m.truncate(0);
}
}
WkcData::Other(req) => self.0.build_response(m, req),
}
}
}
impl<H: Reporting + Handler> Reporting for WellKnownCore<H> {
type Record<'res> = H::Record<'res>
where
H: 'res,
;
type Reporter<'res> = H::Reporter<'res>
where
H: 'res,
;
fn report(&self) -> Self::Reporter<'_> {
self.0.report()
}
}