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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
//! This crate contains demo applications for CoAP on Rust
//!
//! All demos use the ecosystem around the [coap-message] crate. They come in two variations:
//!
//! * "applications" contain code that would typically be the high-level code that executes
//!   business logic.
//!
//!   They are a mix of standalone resource implementations, collections thereof into a
//!   whole-server handler, and possibly client code.
//!
//!   They reside in the `src/` directory, and are available as library modules. This allows
//!   integrating them into other demo code, eg. into examples of a coap-message implementation.
//!
//! * "examples" are the stand-alone executable binaries using various backends.
//!
//!   They pick suitable applications, and wrap them with a CoAP implementation of choice into a
//!   program that can be run with `cargo run --example X`.
//!
//!   Currently, the examples in this crate show the use of:
//!
//!   * [coap-lite](https://crates.io/crates/coap-lite),
//!     a building block for CoAP-over-UDP libraries, running directly on a socket in the example.
//!
//!   * [the coap crate](https://crates.io/crates/coap),
//!     which provides a full implementation, and can interface with coap-message by virtue of
//!     using coap-lite as a backend.
//!
//!   * [embedded-nal-minimal-coapserver](https://crates.io/crates/embedded-nal-minimal-coapserver),
//!     which implements CoAP-over-UDP on the Embedded Network Abstraction Layer
//!     and processes messages through the [coap_handler] types.
//!     For the example, it uses a std implementation of embedded-nal.
//!
//!   Examples that need larger ecosystem support and can not simply be launched natively by `cargo
//!   run --example` are not included here, but show (maybe even better) what the coap-message
//!   ecosystem is capable of providing:
//!
//!   * [verdigris](https://crates.io/crates/verdigris)
//!     is an implementation of CoAP that runs in the web browser and uses CoAP-over-WebSockets.
//!     It includes the demo applications in its color server sub-application, where they can be
//!     accessed through a proxying Resource Directory.
//!
//!   * [RIOT](https://riot-os.org/) is an embedded operating system for the Internet of Things.
//!     In the [examples of its Rust bindings](https://gitlab.com/etonomy/riot-examples/),
//!     the `coap_through_embeddednal` application runs the no_std part of the demo applications
//!     using the same embedded-nal-minimal-coapserver crate as the local example,
//!     but using RIOT's sockets instead of POSIX sockets.
//!
//! Usage
//! -----
//!
//! The examples are all configured to run a selection of the applications; which they are depends
//! on the selected features.
//!
//! For minimal operation, run the examples as
//!
//! ```sh
//! $ cargo +nightly run --example EXNAME --features example-EXNAME
//! ```
//!
//! where `EXNAME` is substituted with any of the examples -- currently `coaplite`, `coap_crate` or
//! `std_embedded_nal_minicoapserver`.
//!
//! To explore all features, just run with
//!
//! ```sh
//! $ cargo +nightly run --example EXNAME --all-features
//! ```
//!
//! which, for example, adds access to a system [::log].
//!
//! All the same can be accessed, for example, by using [aiocoap-client]:
//!
//! ```sh
//! $ aiocoap-client coap://localhost/.well-known/core
//! </>; ct="0"; title="Landing page",
//! </time>; ct="0"; title="Clock",
//! </cbor/1>; ct="60",
//! </cbor/2>; ct="60",
//! </cbor>; ct="60",
//! </message/warning>; title="POST warning texts here",
//! </message/info>; title="POST info texts here"
//!
//! $ aiocoap-client coap://localhost/cbor
//! {'hidden': False, 'number': 32, 'label': 'Hello', 'list': [1, 2, 3]}
//! ```
//!
//! [coap-message]: https://crates.io/crates/coap-message
//! [aiocoap-client]: https://aiocoap.readthedocs.io/en/latest/installation.html
#![no_std]
#![feature(type_alias_impl_trait)]

#[cfg(feature = "std")]
extern crate std;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "alloc")]
pub mod cbor;

pub mod helloworld;

#[cfg(feature = "with-log")]
pub mod log;
#[cfg(not(feature = "with-log"))]
pub mod log {
    /// A never-ish type that allows having a single full_application_tree function independent of
    /// whether things are built with-log or without.
    pub enum Log {}
}

/// Build a handler that contains all the demo applications
///
/// Note that no log::Log is created because that needs to be global, created-only-once and
/// available as early in the application start-up as possible as per the log crate's design; you'd
/// have to pass one in if you want to view the log through CoAP.
///
/// The resources /message/info and /message/warn for creating log messages will
/// be available independently thereof as long as the with-log feature is active.
pub fn full_application_tree(
    main_log: Option<&'static crate::log::Log>
    ) -> FullHandler {
    #[cfg(feature = "with-log")]
    use crate::log::*;
    #[cfg(feature = "alloc")]
    use cbor::*;
    use helloworld::*;

    #[cfg(feature = "std")]
    let shared_cbor: std::sync::Arc<std::sync::Mutex<MyCBOR>> = Default::default();

    use coap_handler_implementations::{new_dispatcher, HandlerBuilder, SimpleCBORWrapper};

    let handler = new_dispatcher()
        .at(
            &[".well-known", "core"],
            // TBD: Build this string from cfg to not advertise 4.04'ing resources
            coap_handler_implementations::TypedStaticResponse {
                payload: b"</>;ct=0;title=\"Landing page\",\
                    </time>;ct=0;title=\"Clock\",\
                    </poem>;sz=1339,\
                    </cbor/1>;ct=60,\
                    </cbor/2>;ct=60,\
                    </cbor>;ct=60,\
                    </message/warn>;title=\"POST warning texts here\",\
                    </message/info>;title=\"POST info texts here\"\
                    </log>;title=\"Most recent log messages\"\
                    ",
                contentformat: &[40],
            },
        )
        .at(&[], WELCOME)
        .at(&["time"], TIME)
        .at(&["poem"], POEM);
    #[cfg(feature = "std")]
    let handler = handler
        .at(
            &["cbor", "1"],
            SimpleCBORWrapper::new(TryingThroughMutex(shared_cbor.clone())),
        )
        .at(
            &["cbor", "2"],
            SimpleCBORWrapper::new(TryingThroughMutex(shared_cbor.clone())),
        );
    #[cfg(feature = "alloc")]
    let handler = handler.at(
        &["cbor"],
        SimpleCBORWrapper::<MyCBOR>::new(Default::default()),
    );

    #[cfg(feature = "with-log")]
    let handler = handler
        .at(&["message", "warn"], LogMessagePostHandler::new_warn())
        .at(&["message", "info"], LogMessagePostHandler::new_info())
        .at(
            &["log"],
            main_log.map(|m| coap_handler_implementations::SimpleRendered(&*m)),
        );
    #[cfg(not(feature = "with-log"))]
    let _ = main_log; // Discarding what's sure to be None (because Ok can never be)

    handler
}

pub type FullHandler = impl coap_handler::Handler;