riot_coap_handler_demos/
stdio.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
//! Handlers for interacting with RIOT's stdio system
//!
//! (Really just putting things on the console, and reading from the console with terribly locking
//! properties)

use riot_wrappers::stdio::{println, Stdio};

use coap_message::{Code, MinimalWritableMessage, MutableWritableMessage, ReadableMessage};
use coap_message_utils::{Error, OptionsExt};

struct Write;

impl coap_handler::Handler for Write {
    type RequestData = ();

    type ExtractRequestError = Error;
    type BuildResponseError<M: MinimalWritableMessage> = M::UnionError;

    fn extract_request_data<M: ReadableMessage>(
        &mut self,
        request: &M,
    ) -> Result<Self::RequestData, Error> {
        if request.code().into() != coap_numbers::code::POST {
            return Err(Error::method_not_allowed());
        }
        request.options().ignore_elective_others()?;

        let payload = core::str::from_utf8(request.payload())
            .map_err(|ue| Error::bad_request_with_rbep(ue.valid_up_to()))?;

        println!("{}", payload);
        Ok(())
    }

    fn estimate_length(&mut self, _request: &Self::RequestData) -> usize {
        1
    }

    fn build_response<M: MutableWritableMessage>(
        &mut self,
        response: &mut M,
        _request: (),
    ) -> Result<(), M::UnionError> {
        response.set_code(Code::new(coap_numbers::code::CHANGED)?);
        Ok(())
    }
}

struct Read;

impl coap_handler::Handler for Read {
    type RequestData = ();

    type ExtractRequestError = Error;
    type BuildResponseError<M: MinimalWritableMessage> = M::UnionError;

    fn extract_request_data<M: ReadableMessage>(&mut self, request: &M) -> Result<(), Error> {
        if request.code().into() != coap_numbers::code::POST {
            return Err(Error::method_not_allowed());
        }
        // FIXME: We could Just Allow block-wise as long as the client behaves as we expect
        request.options().ignore_elective_others()?;
        Ok(())
    }

    fn estimate_length(&mut self, _request: &Self::RequestData) -> usize {
        1025
    }

    fn build_response<M: MutableWritableMessage>(
        &mut self,
        response: &mut M,
        _request: (),
    ) -> Result<(), M::UnionError> {
        response.set_code(Code::new(coap_numbers::code::CHANGED)?);
        let payload = response.payload_mut_with_len(1024)?;
        println!("Mapped {} bytes", payload.len());
        let filled = (Stdio {}).read_raw(payload).unwrap().len();
        response.truncate(filled)?;
        Ok(())
    }
}

/// A resource that, when POSTed to, renders any payload to standard out
///
/// This is an unusual implementation of Handler in that it requires request deduplication from the
/// underlying implementation. (Failing that, messages may be printed twice).
pub fn write() -> impl coap_handler::Handler {
    Write
}

/// A resource that, when POSTed to, reads up to whichever internally decided buffer length from
/// stdin
///
/// ## Warning
///
/// This is not only an unusual implementation of Handler (as is [write()]; here, lack of the
/// retranmission buffering associated with deduplication leads to lost input), but also a bad
/// implementation of Handler as it blocks arbitrarily (making it even more likely that
/// retransmissions occur).
pub fn read() -> impl coap_handler::Handler {
    Read
}