spaceapi_server/
lib.rs

1//! This crate enables you to create your own SpaceAPI server endpoint using
2//! Rust. In the end you'll get a single binary that you can run on your
3//! server.
4//!
5//!
6//! ## Requirements
7//!
8//! On the build machine:
9//!
10//! - Rust and Cargo ([https://rustup.rs/](https://rustup.rs/))
11//!
12//! On the server:
13//!
14//! - Redis
15//!
16//! The Redis instance will be used to store dynamic data like sensor values,
17//! as well as keys for dynamic data update authentication.
18//!
19//!
20//! ## Getting Started
21//!
22//! Create a new Rust project:
23//!
24//! ```text
25//! cargo new --bin mystatus
26//! ```
27//!
28//! Add the `spaceapi-server` dependency to `Cargo.toml`:
29//!
30//! ```toml
31//! [dependencies]
32//! spaceapi-server = "0.7"
33//! ```
34//!
35//! Create a `main.rs`:
36//!
37//! ```no_run
38//! use spaceapi_server::api::{Contact, Location, StatusBuilder};
39//! use spaceapi_server::SpaceapiServerBuilder;
40//!
41//! fn main() {
42//!     // Create new minimal v14 Status instance
43//!     let status = StatusBuilder::v14("coredump")
44//!         .logo("https://www.coredump.ch/logo.png")
45//!         .url("https://www.coredump.ch/")
46//!         .location(Location {
47//!             address: Some("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".into()),
48//!             lat: 47.22936,
49//!             lon: 8.82949,
50//!             timezone: None,
51//!         })
52//!         .contact(Contact {
53//!             irc: Some("irc://freenode.net/#coredump".into()),
54//!             twitter: Some("@coredump_ch".into()),
55//!             ..Default::default()
56//!         })
57//!         .build()
58//!         .expect("Creating status failed");
59//!
60//!     // Set up server
61//!     let server = SpaceapiServerBuilder::new(status)
62//!         .redis_connection_info("redis://127.0.0.1/")
63//!         .build()
64//!         .unwrap();
65//!
66//!     // Serve!
67//!     let _ = server.serve("127.0.0.1:8000");
68//! }
69//! ```
70//!
71//! Now you can build and run your binary with `cargo run`. Running this code
72//! starts a HTTP server instance on port 8000. You can also override the port
73//! by setting the `PORT` environment variable.
74//!
75//! See the
76//! [`examples/`](https://github.com/spaceapi-community/spaceapi-server-rs/tree/master/examples)
77//! directory for some other examples.
78//!
79//!
80//! ## Sensors
81//!
82//! ### Registering Sensors
83//!
84//! This crate supports updating and retrieving dynamic sensor values (e.g.
85//! temperature or people present). For this, first register a sensor with a
86//! sensor template:
87//!
88//! ```rust
89//! use spaceapi_server::SpaceapiServerBuilder;
90//! use spaceapi_server::api::sensors::{
91//!    PeopleNowPresentSensorTemplate, SensorMetadata, SensorMetadataWithLocation, TemperatureSensorTemplate,
92//! };
93//!
94//! # use spaceapi_server::api;
95//! # let status = api::StatusBuilder::v14("aa")
96//! #     .logo("https://example.com/logo.png")
97//! #     .url("https://example.com/")
98//! #     .location(api::Location {
99//! #         address: Some("addr".into()),
100//! #         lat: 47.0,
101//! #         lon: 8.0,
102//! #         timezone: None,
103//! #     })
104//! #     .contact(api::Contact {
105//! #         twitter: Some("@example".into()),
106//! #         ..Default::default()
107//! #     })
108//! #     .build()
109//! #     .expect("Creating status failed");
110//! #
111//! let server = SpaceapiServerBuilder::new(status)
112//!     .redis_connection_info("redis://127.0.0.1/")
113//!     .add_sensor(PeopleNowPresentSensorTemplate {
114//!         metadata: SensorMetadata {
115//!             location: Some("Hackerspace".into()),
116//!             ..Default::default()
117//!         },
118//!     }, "people_now_present".into())
119//!     .add_sensor(TemperatureSensorTemplate {
120//!         metadata: SensorMetadataWithLocation {
121//!             location: "Room 1".into(),
122//!             ..Default::default()
123//!         },
124//!         unit: "°C".into(),
125//!     }, "temp_room1".into())
126//!     .add_sensor(TemperatureSensorTemplate {
127//!         metadata: SensorMetadataWithLocation {
128//!             location: "Room 2".into(),
129//!             ..Default::default()
130//!         },
131//!         unit: "°C".into(),
132//!     }, "temp_room2".into())
133//!     .build()
134//! .expect("Could not initialize server");
135//! ```
136//!
137//! (You can find the full example at
138//! [`examples/with_sensors.rs`](https://github.com/spaceapi-community/spaceapi-server-rs/blob/master/examples/with_sensors.rs).)
139//!
140//! This will register three sensors: One "people now present" sensor and two
141//! "temperature" sensors.
142//!
143//! ### Updating Sensors via HTTP
144//!
145//! If you start the server like that, the JSON output will not yet contain any
146//! sensor data. To update a sensor value, send a HTTP POST request to the
147//! `/sensors/<sensor-id>/` endpoint with the `value` parameter:
148//!
149//! ```text
150//! curl -v -X PUT -d value=42 http://127.0.0.1:8000/sensors/people_now_present/
151//! curl -v -X PUT -d value=13.37 http://127.0.0.1:8000/sensors/temp_room1/
152//! ```
153//!
154//! Now the server response will contain the following key:
155//!
156//! ```json
157//! "sensors": {
158//!   "people_now_present": [
159//!     {
160//!       "location": "Hackerspace",
161//!       "value": 42
162//!     }
163//!   ],
164//!   "temperature": [
165//!     {
166//!       "unit": "°C",
167//!       "location": "Room 1",
168//!       "value": 13.37
169//!     }
170//!   ]
171//! },
172//! ```
173//!
174//! ### Updating Sensors via Redis
175//!
176//! Alternatively you can modify the values in Redis directly. You can access
177//! the database with the `redis-cli` tool:
178//!
179//! ```text
180//! % redis-cli
181//! 127.0.0.1:6379> SET people_now_present 1
182//! OK
183//! 127.0.0.1:6379> GET people_now_present
184//! "1"
185//! 127.0.0.1:6379> KEYS *
186//! 1) "people_now_present"
187//! 2) "temp_room1"
188//! ```
189//!
190//! The keys need to match the IDs you used when registering the sensor.
191
192#![deny(missing_docs)]
193#![doc(html_root_url = "https://docs.rs/spaceapi-server")]
194
195pub use spaceapi as api;
196
197pub use iron::error::HttpResult;
198pub use iron::Listening;
199
200mod errors;
201pub mod modifiers;
202mod sensors;
203mod server;
204mod types;
205
206pub use crate::errors::SpaceapiServerError;
207pub use crate::server::SpaceapiServer;
208pub use crate::server::SpaceapiServerBuilder;
209
210/// Return own crate version. Used in API responses.
211pub fn get_version() -> &'static str {
212    env!("CARGO_PKG_VERSION")
213}
214
215#[cfg(test)]
216mod test {
217    use super::get_version;
218
219    #[test]
220    fn test_get_version() {
221        let version = get_version();
222        assert_eq!(3, version.split('.').count());
223    }
224}