coap_handler_implementations/
wkc_implementation.rs1use crate::wkc::write_link_format;
7use coap_handler::{Handler, Reporting};
8use coap_message::{
9 Code as _, MessageOption, MinimalWritableMessage, MutableWritableMessage, ReadableMessage,
10 error::RenderableOnMinimal,
11};
12use coap_message_utils::{OptionsExt, option_value::Block2RequestData};
13use core::fmt::Debug;
14
15const LINK_FORMAT: u16 = 40;
16
17pub struct WellKnownCore<H: Reporting + Handler>(H);
23
24impl<H: Reporting + Handler> WellKnownCore<H> {
25 pub(crate) fn new(handler: H) -> Self {
26 WellKnownCore(handler)
27 }
28}
29
30pub enum WkcData<T> {
31 Wkc {
32 code: u8,
34 block2: Block2RequestData,
36 },
37 Other(T),
38}
39
40#[derive(Debug)]
43pub enum WkcBuildResponseError<IE: RenderableOnMinimal + Debug, HBRE: RenderableOnMinimal> {
44 Wkc(IE),
45 Other(HBRE),
46}
47
48impl<IE: RenderableOnMinimal + Debug, HBRE: RenderableOnMinimal + Debug> RenderableOnMinimal
49 for WkcBuildResponseError<IE, HBRE>
50{
51 type Error<IE2: RenderableOnMinimal + Debug> = WkcBuildResponseError<
52 <IE as RenderableOnMinimal>::Error<IE2>,
53 <HBRE as RenderableOnMinimal>::Error<IE2>,
54 >;
55 fn render<M: MinimalWritableMessage>(
56 self,
57 message: &mut M,
58 ) -> Result<(), Self::Error<M::UnionError>> {
59 match self {
60 WkcBuildResponseError::Wkc(e) => e.render(message).map_err(WkcBuildResponseError::Wkc),
61 WkcBuildResponseError::Other(e) => {
62 e.render(message).map_err(WkcBuildResponseError::Other)
63 }
64 }
65 }
66}
67
68impl<H: Reporting + Handler> Handler for WellKnownCore<H> {
69 type RequestData = WkcData<H::RequestData>;
70 type ExtractRequestError = H::ExtractRequestError;
71 type BuildResponseError<M: MinimalWritableMessage> =
72 WkcBuildResponseError<M::UnionError, H::BuildResponseError<M>>;
73
74 fn extract_request_data<M: ReadableMessage>(
75 &mut self,
76 req: &M,
77 ) -> Result<Self::RequestData, Self::ExtractRequestError> {
78 let mut block2 = None;
79
80 let mut pathmatch = 0;
81
82 let mut accept: Option<u16> = None;
83
84 let opts = req
85 .options()
86 .ignore_uri_host()
87 .filter(|o| match o.number() {
88 coap_numbers::option::ACCEPT if accept.is_none() => {
89 accept = o.value_uint();
90 accept.is_none()
92 }
93 _ => true,
94 })
95 .ignore_uri_query()
97 .take_block2(&mut block2)
98 .take_uri_path(|p| {
100 pathmatch = match (pathmatch, p) {
101 (0, ".well-known") => 1,
102 (1, "core") => 2,
103 _ => -1,
104 }
105 });
106
107 let remaining = opts.ignore_elective_others();
108
109 let block2 = block2.unwrap_or_default();
110
111 if pathmatch == 2 {
112 let code = if remaining.is_err() {
113 coap_numbers::code::BAD_OPTION
114 } else if accept.unwrap_or(LINK_FORMAT) != LINK_FORMAT {
115 coap_numbers::code::NOT_ACCEPTABLE
116 } else {
117 coap_numbers::code::CONTENT
118 };
119 Ok(WkcData::Wkc { code, block2 })
120 } else {
121 Ok(WkcData::Other(self.0.extract_request_data(req)?))
122 }
123 }
124 fn estimate_length(&mut self, req: &Self::RequestData) -> usize {
125 match req {
126 WkcData::Wkc { .. } => 1024,
128 WkcData::Other(req) => self.0.estimate_length(req),
129 }
130 }
131 fn build_response<M: MutableWritableMessage>(
132 &mut self,
133 m: &mut M,
134 req: Self::RequestData,
135 ) -> Result<(), Self::BuildResponseError<M>> {
136 match req {
137 WkcData::Wkc { code, block2 } => {
139 m.set_code(M::Code::new(code).map_err(|e| WkcBuildResponseError::Wkc(e.into()))?);
140 if code == coap_numbers::code::CONTENT {
141 crate::helpers::block2_write_with_cf(
142 block2,
143 m,
144 |w| {
145 write_link_format(w, &self.0, &[]).expect("Block writers do not err.");
146 },
147 Some(40),
148 );
149 } else {
150 m.truncate(0)
151 .map_err(|e| WkcBuildResponseError::Wkc(e.into()))?;
152 }
153 Ok(())
154 }
155 WkcData::Other(req) => self
156 .0
157 .build_response(m, req)
158 .map_err(WkcBuildResponseError::Other),
159 }
160 }
161}
162
163impl<H: Reporting + Handler> Reporting for WellKnownCore<H> {
171 type Record<'res>
172 = H::Record<'res>
173 where
174 H: 'res;
175 type Reporter<'res>
176 = H::Reporter<'res>
177 where
178 H: 'res;
179
180 fn report(&self) -> Self::Reporter<'_> {
181 self.0.report()
182 }
183}