coap-server 0.1.1

Robust async CoAP server
Documentation
use std::collections::HashMap;

use coap_lite::error::IncompatibleOptionValueFormat;
use coap_lite::option_value::OptionValueType;
use coap_lite::{CoapOption, CoapRequest, MessageClass, MessageType, Packet};

use crate::app::CoapError;

pub fn new_pong_message(ping: &Packet) -> Packet {
    let mut pong = Packet::new();

    pong.header.set_type(MessageType::Reset);
    pong.header.code = MessageClass::Empty;
    pong.header.message_id = ping.header.message_id;
    pong
}

pub fn request_get_queries<Endpoint>(request: &CoapRequest<Endpoint>) -> HashMap<String, String> {
    request
        .message
        .get_options_as::<OptionValueQuery>(CoapOption::UriQuery)
        .map_or_else(
            || HashMap::new(),
            |options| {
                options
                    .into_iter()
                    .filter_map(Result::ok)
                    .map(|query| (query.key, query.value))
                    .collect::<HashMap<_, _>>()
            },
        )
}

pub struct OptionValueQuery {
    key: String,
    value: String,
}

impl From<OptionValueQuery> for Vec<u8> {
    fn from(option_value: OptionValueQuery) -> Self {
        format!("{}={}", option_value.key, option_value.value).into_bytes()
    }
}

impl TryFrom<Vec<u8>> for OptionValueQuery {
    type Error = IncompatibleOptionValueFormat;

    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
        Self::do_try_from(value).map_err(|e| IncompatibleOptionValueFormat {
            message: e.to_string(),
        })
    }
}

impl OptionValueType for OptionValueQuery {}

impl OptionValueQuery {
    fn do_try_from(value: Vec<u8>) -> Result<Self, CoapError> {
        let mut key_value_iter = value.split(|&c| c == b'=');
        let key_vec = key_value_iter.next().unwrap().to_vec();
        let value_vec = key_value_iter
            .next()
            .ok_or_else(|| CoapError::bad_request("Missing '=', not a valid query string"))?
            .to_vec();
        let key = String::from_utf8(key_vec)
            .map_err(|e| CoapError::bad_request(format!("Key is not UTF-8: {e}")))?;
        let value = String::from_utf8(value_vec)
            .map_err(|e| CoapError::bad_request(format!("Value is not UTF-8: {e}")))?;

        Ok(OptionValueQuery { key, value })
    }
}