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;
113 if remaining.is_err() {
114 code = coap_numbers::code::BAD_OPTION;
115 } else if accept.unwrap_or(LINK_FORMAT) != LINK_FORMAT {
116 code = coap_numbers::code::NOT_ACCEPTABLE;
117 } else {
118 code = coap_numbers::code::CONTENT;
119 }
120 Ok(WkcData::Wkc { code, block2 })
121 } else {
122 Ok(WkcData::Other(self.0.extract_request_data(req)?))
123 }
124 }
125 fn estimate_length(&mut self, req: &Self::RequestData) -> usize {
126 match req {
127 WkcData::Wkc { .. } => 1024,
129 WkcData::Other(req) => self.0.estimate_length(req),
130 }
131 }
132 fn build_response<M: MutableWritableMessage>(
133 &mut self,
134 m: &mut M,
135 req: Self::RequestData,
136 ) -> Result<(), Self::BuildResponseError<M>> {
137 match req {
138 WkcData::Wkc { code, block2 } => {
140 m.set_code(M::Code::new(code).map_err(|e| WkcBuildResponseError::Wkc(e.into()))?);
141 if code == coap_numbers::code::CONTENT {
142 crate::helpers::block2_write_with_cf(
143 block2,
144 m,
145 |w| {
146 write_link_format(w, &self.0, &[]).expect("Block writers do not err.");
147 },
148 Some(40),
149 );
150 } else {
151 m.truncate(0)
152 .map_err(|e| WkcBuildResponseError::Wkc(e.into()))?;
153 }
154 Ok(())
155 }
156 WkcData::Other(req) => self
157 .0
158 .build_response(m, req)
159 .map_err(WkcBuildResponseError::Other),
160 }
161 }
162}
163
164impl<H: Reporting + Handler> Reporting for WellKnownCore<H> {
172 type Record<'res>
173 = H::Record<'res>
174 where
175 H: 'res;
176 type Reporter<'res>
177 = H::Reporter<'res>
178 where
179 H: 'res;
180
181 fn report(&self) -> Self::Reporter<'_> {
182 self.0.report()
183 }
184}