coap-server 0.1.1

Robust async CoAP server
Documentation
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::sync::Arc;

use async_trait::async_trait;
use coap_lite::{ContentFormat, ResponseType};

use crate::app::error::CoapError;
use crate::app::request_handler::RequestHandler;
use crate::app::resource_builder::DiscoverableResource;
use crate::app::{coap_utils, Request, ResourceBuilder, Response};

#[derive(Clone)]
pub struct CoreRequestHandler {
    resources: Arc<Vec<DiscoverableResource>>,
}

impl CoreRequestHandler {
    pub(crate) fn new_resource_builder<
        Endpoint: Debug + Clone + Ord + Eq + Hash + Send + 'static,
    >(
        resources: Vec<DiscoverableResource>,
    ) -> ResourceBuilder<Endpoint> {
        let me = Self {
            resources: Arc::new(resources),
        };
        ResourceBuilder::new("/.well-known/core").get(me)
    }
}

#[async_trait]
impl<Endpoint: Send + 'static> RequestHandler<Endpoint> for CoreRequestHandler {
    async fn handle(&self, request: Request<Endpoint>) -> Result<Response, CoapError> {
        let queries = coap_utils::request_get_queries(&request.original);

        let mut response = request.new_response();
        response.message.payload = self
            .resources
            .iter()
            .filter(|&r| filter_by_query(r, &queries))
            .map(|k| k.link_str.as_str())
            .collect::<Vec<_>>()
            .join("\n")
            .into_bytes();
        response.set_status(ResponseType::Content);
        response
            .message
            .set_content_format(ContentFormat::ApplicationLinkFormat);
        Ok(response)
    }
}

fn filter_by_query(resource: &DiscoverableResource, queries: &HashMap<String, String>) -> bool {
    for (key, value) in queries {
        if Some(value) != resource.attributes_as_string.get(key.as_str()) {
            return false;
        }
    }
    true
}