use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::time::Duration;
use r2d2;
use r2d2_redis::RedisConnectionManager;
use iron::Iron;
use router::Router;
use redis::{IntoConnectionInfo, ConnectionInfo};
use serde_json::Value;
use serde_json::map::Map;
mod handlers;
use ::api;
use ::sensors;
use ::modifiers;
use ::errors::SpaceapiServerError;
use ::types::RedisPool;
pub struct SpaceapiServerBuilder {
status: api::Status,
redis_connection_info: Result<ConnectionInfo, SpaceapiServerError>,
sensor_specs: Vec<sensors::SensorSpec>,
status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}
impl SpaceapiServerBuilder {
pub fn new(mut status: api::Status) -> SpaceapiServerBuilder {
let mut versions = Map::new();
versions.insert("spaceapi-rs".into(), api::get_version().into());
versions.insert("spaceapi-server-rs".into(), ::get_version().into());
status.extensions.insert("versions".into(), Value::Object(versions));
SpaceapiServerBuilder {
status: status,
redis_connection_info: Err("redis_connection_info missing".into()),
sensor_specs: vec![],
status_modifiers: vec![],
}
}
pub fn redis_connection_info<R: IntoConnectionInfo>(mut self, redis_connection_info: R) -> Self {
self.redis_connection_info = redis_connection_info.into_connection_info().map_err(|e| e.into());
self
}
pub fn add_status_modifier<M: modifiers::StatusModifier + 'static>(mut self, modifier: M) -> Self {
self.status_modifiers.push(Box::new(modifier));
self
}
pub fn add_sensor<T: api::SensorTemplate + 'static>(mut self, template: T, data_key: String) -> Self {
self.sensor_specs.push(
sensors::SensorSpec { template: Box::new(template), data_key: data_key}
);
self
}
pub fn build(self) -> Result<SpaceapiServer, SpaceapiServerError> {
debug!("Redis connection info: {:?}", &self.redis_connection_info);
let redis_config = r2d2::Config::builder()
.pool_size(6)
.min_idle(Some(2))
.initialization_fail_fast(false)
.connection_timeout(Duration::from_secs(1))
.error_handler(Box::new(r2d2::NopErrorHandler))
.build();
let redis_manager = try!(RedisConnectionManager::new(self.redis_connection_info?));
let pool = try!(r2d2::Pool::new(redis_config, redis_manager));
Ok(SpaceapiServer {
status: self.status,
redis_pool: pool,
sensor_specs: Arc::new(self.sensor_specs),
status_modifiers: self.status_modifiers,
})
}
}
pub struct SpaceapiServer {
status: api::Status,
redis_pool: RedisPool,
sensor_specs: sensors::SafeSensorSpecs,
status_modifiers: Vec<Box<modifiers::StatusModifier>>,
}
impl SpaceapiServer {
fn route(self) -> Router {
let mut router = Router::new();
router.get("/", handlers::ReadHandler::new(
self.status.clone(), self.redis_pool.clone(),
self.sensor_specs.clone(), self.status_modifiers), "root");
router.put("/sensors/:sensor/", handlers::UpdateHandler::new(
self.redis_pool.clone(), self.sensor_specs.clone()), "sensors");
router
}
pub fn serve<S: ToSocketAddrs>(self, socket_addr: S) -> ::HttpResult<::Listening> {
let router = self.route();
println!("Starting HTTP server on:");
for a in socket_addr.to_socket_addrs()? {
println!("\thttp://{}", a);
}
Iron::new(router).http(socket_addr)
}
}