use crate::helpers::{block2_write_with_cf, codeconvert, Block2RequestData, Renderable};
use crate::option_processing::{BadOption, OptionsExt};
use crate::Code;
use coap_handler::Handler;
use coap_message::{MessageOption, MutableWritableMessage, ReadableMessage};
use coap_numbers::{code, option};
use core::marker::PhantomData;
use serde::Serialize;
pub trait TypeRenderable {
type Get;
type Post;
type Put;
fn get(&mut self) -> Result<Self::Get, u8> {
Err(code::METHOD_NOT_ALLOWED)
}
fn post(&mut self, _representation: &Self::Post) -> u8 {
code::METHOD_NOT_ALLOWED
}
fn put(&mut self, _representation: &Self::Put) -> u8 {
code::METHOD_NOT_ALLOWED
}
fn delete(&mut self) -> u8 {
code::METHOD_NOT_ALLOWED
}
}
mod sealed {
pub trait TypeSerializer {
const CF: Option<u16>;
}
pub struct SerdeCBORSerialization;
pub struct MiniCBORSerialization;
}
use sealed::*;
impl TypeSerializer for SerdeCBORSerialization {
const CF: Option<u16> = coap_numbers::content_format::from_str("application/cbor");
}
impl TypeSerializer for MiniCBORSerialization {
const CF: Option<u16> = coap_numbers::content_format::from_str("application/cbor");
}
pub struct TypeHandler<H, S: TypeSerializer = SerdeCBORSerialization>
where
H: TypeRenderable,
{
handler: H,
_phantom: PhantomData<S>,
}
impl<H, S> TypeHandler<H, S>
where
H: TypeRenderable,
S: TypeSerializer,
{
fn check_get_options(
request: &impl ReadableMessage,
) -> Result<Block2RequestData, TypeRequestData> {
let mut block2 = None;
request
.options()
.take_block2(&mut block2)
.filter(|o| {
if o.number() == option::ACCEPT {
if let Some(cf) = S::CF {
o.value_uint() != Some(cf)
} else {
true
}
} else {
true
}
})
.ignore_elective_others()
.map_err(|o| TypeRequestData(TypeRequestDataE::BadOption(o)))?;
Ok(block2.unwrap_or_default())
}
fn check_delete_options(request: &impl ReadableMessage) -> Result<(), TypeRequestData> {
request
.options()
.ignore_elective_others()
.map_err(|o| TypeRequestData(TypeRequestDataE::BadOption(o)))
}
fn check_postput_options(request: &impl ReadableMessage) -> Result<(), TypeRequestData> {
let mut cf = Ok(());
request
.options()
.filter(|o| {
if o.number() == option::CONTENT_FORMAT
&& (S::CF.is_none() || o.value_uint() != S::CF)
{
cf = Err(TypeRequestData(Done(Code(
coap_numbers::code::UNSUPPORTED_CONTENT_FORMAT,
))));
}
true
})
.ignore_elective_others()
.map_err(|o| TypeRequestData(TypeRequestDataE::BadOption(o)))?;
cf
}
}
impl<H> TypeHandler<H, SerdeCBORSerialization>
where
H: TypeRenderable,
H::Get: for<'de> serde::Serialize,
H::Post: for<'de> serde::Deserialize<'de>,
H::Put: for<'de> serde::Deserialize<'de>,
{
pub fn new(handler: H) -> Self {
TypeHandler {
handler,
_phantom: PhantomData,
}
}
}
impl<H> TypeHandler<H, MiniCBORSerialization>
where
H: TypeRenderable,
H::Get: for<'de> minicbor::Encode<()>,
H::Post: for<'de> minicbor::Decode<'de, ()>,
H::Put: for<'de> minicbor::Decode<'de, ()>,
{
pub fn new_minicbor(handler: H) -> Self {
TypeHandler {
handler,
_phantom: PhantomData,
}
}
}
pub struct TypeRequestData(TypeRequestDataE);
enum TypeRequestDataE {
Get(Block2RequestData), Done(Code), BadOption(BadOption),
}
use self::TypeRequestDataE::{Done, Get};
impl<H> Handler for TypeHandler<H, SerdeCBORSerialization>
where
H: TypeRenderable,
H::Get: for<'de> serde::Serialize,
H::Post: for<'de> serde::Deserialize<'de>,
H::Put: for<'de> serde::Deserialize<'de>,
{
type RequestData = TypeRequestData;
fn extract_request_data(&mut self, request: &impl ReadableMessage) -> Self::RequestData {
TypeRequestData(match request.code().into() {
code::DELETE => match Self::check_delete_options(request) {
Err(e) => return e,
Ok(()) => Done(Code(self.handler.delete())),
},
code::GET => match Self::check_get_options(request) {
Err(e) => return e,
Ok(block) => Get(block),
},
code::POST => {
if let Err(e) = Self::check_postput_options(request) {
return e;
}
let parsed: Result<H::Post, _> =
serde_cbor::de::from_slice_with_scratch(request.payload(), &mut []);
match parsed {
Ok(p) => Done(Code(self.handler.post(&p))),
Err(_) => Done(Code(code::BAD_REQUEST)),
}
}
code::PUT => {
if let Err(e) = Self::check_postput_options(request) {
return e;
}
let parsed: Result<H::Put, _> =
serde_cbor::de::from_slice_with_scratch(request.payload(), &mut []);
match parsed {
Ok(p) => Done(Code(self.handler.put(&p))),
Err(_) => Done(Code(code::BAD_REQUEST)),
}
}
_ => Done(Code(code::METHOD_NOT_ALLOWED)),
})
}
fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
match &request.0 {
Done(_) => 4,
TypeRequestDataE::BadOption(_) => 20, Get(block) => (block.size() + 25).into(), }
}
fn build_response(
&mut self,
response: &mut impl MutableWritableMessage,
request: Self::RequestData,
) {
match request.0 {
Done(r) => r.render(response),
TypeRequestDataE::BadOption(cor) => cor.render(response),
Get(block2) => {
let repr = self.handler.get();
match repr {
Err(e) => {
Code(e).render(response);
}
Ok(repr) => {
response.set_code(codeconvert(code::CONTENT));
match block2_write_with_cf(
block2,
response,
|win| repr.serialize(&mut serde_cbor::ser::Serializer::new(win)),
SerdeCBORSerialization::CF,
) {
Ok(()) => (),
Err(_) => {
response.set_code(codeconvert(code::INTERNAL_SERVER_ERROR));
}
}
}
}
}
}
}
}
impl<H> Handler for TypeHandler<H, MiniCBORSerialization>
where
H: TypeRenderable,
H::Get: for<'de> minicbor::Encode<()>,
H::Post: for<'de> minicbor::Decode<'de, ()>,
H::Put: for<'de> minicbor::Decode<'de, ()>,
{
type RequestData = TypeRequestData;
fn extract_request_data(&mut self, request: &impl ReadableMessage) -> Self::RequestData {
TypeRequestData(match request.code().into() {
code::DELETE => match Self::check_delete_options(request) {
Err(e) => return e,
Ok(()) => Done(Code(self.handler.delete())),
},
code::GET => match Self::check_get_options(request) {
Err(e) => return e,
Ok(block) => Get(block),
},
code::POST => {
if let Err(e) = Self::check_postput_options(request) {
return e;
}
let parsed: Result<H::Post, _> = minicbor::decode(request.payload());
match parsed {
Ok(p) => Done(Code(self.handler.post(&p))),
Err(_) => Done(Code(code::BAD_REQUEST)),
}
}
code::PUT => {
if let Err(e) = Self::check_postput_options(request) {
return e;
}
let parsed: Result<H::Put, _> = minicbor::decode(request.payload());
match parsed {
Ok(p) => Done(Code(self.handler.put(&p))),
Err(_) => Done(Code(code::BAD_REQUEST)),
}
}
_ => Done(Code(code::METHOD_NOT_ALLOWED)),
})
}
fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
match &request.0 {
Done(_) => 4,
TypeRequestDataE::BadOption(_) => 20, Get(block) => (block.size() + 25).into(), }
}
fn build_response(
&mut self,
response: &mut impl MutableWritableMessage,
request: Self::RequestData,
) {
match request.0 {
Done(r) => r.render(response),
TypeRequestDataE::BadOption(cor) => cor.render(response),
Get(block2) => {
let repr = self.handler.get();
match repr {
Err(e) => {
Code(e).render(response);
}
Ok(repr) => {
response.set_code(codeconvert(code::CONTENT));
match block2_write_with_cf(
block2,
response,
|win| minicbor::encode(&repr, win),
MiniCBORSerialization::CF,
) {
Ok(()) => (),
Err(_) => {
response.set_code(codeconvert(code::INTERNAL_SERVER_ERROR));
}
}
}
}
}
}
}
}