use hyper::client::connect::Connect;
use futures::Future;
use hyper::rt::Stream;
use errors::{Result, Error, ErrorKind};
use transport::status_code;
use transport::parse_to_trait;
use transport::parse_to_stream;
use communicate::util::AsSlice;
use std::env;
use build::{
EventsOptions,
};
use representation::rep::{
Info, Version, Event
};
use hyper::Uri;
use hyper::StatusCode;
use transport::interact::InteractApi;
use transport::interact::InteractApiExt;
use std::sync::Arc;
use std::borrow::Cow;
use super::tcp_docker::TcpDocker;
#[cfg(target_os = "linux")]
use super::unix_docker::UnixDocker;
#[cfg(feature = "ssl")]
use super::ssl_tcp_docker::TcpSSLDocker;
use std::marker::PhantomData;
use communicate::Container;
use communicate::image::Image;
use communicate::Images;
use communicate::containers::Containers;
use communicate::networks::Networks;
use communicate::Network;
pub trait DockerApi
{
fn version(&self) -> Box<Future<Item=Version, Error=Error> + Send>;
fn info(&self) -> Box<Future<Item=Info, Error=Error> + Send>;
fn ping(&self) -> Box<Future<Item=StatusCode, Error=Error> + Send>;
fn events(&self, opts: &EventsOptions) -> Box<Stream<Item=Result<Event>, Error=Error> + Send>;
fn container(&self, id: Cow<'static, str>) -> Container;
fn containers(&self) -> Containers;
fn image<'a>(&self, id: Cow<'a, str>) -> Image<'a>;
fn images(&self) -> Images;
fn network<'a>(&self, id: Cow<'a, str>) -> Network<'a>;
fn networks(&self) -> Networks;
}
pub(crate) struct Docker<C>
where C: Connect + 'static
{
interact: Arc<InteractApi>,
phantom: PhantomData<C>,
}
impl <C> Docker<C>
where C: Connect + 'static
{
pub(super) fn new_inner(interact: Arc<InteractApi>) -> Self
{
Self {
interact,
phantom: PhantomData
}
}
}
impl <C> DockerApi for Docker<C>
where C: Connect + 'static
{
fn version(&self) -> Box<Future<Item=Version, Error=Error> + Send> {
let arg = "/version";
Box::new(parse_to_trait::<Version>(self.interact.get(arg)))
}
fn info(&self) -> Box<Future<Item=Info, Error=Error> + Send> {
let arg = "/info";
Box::new(parse_to_trait::<Info>(self.interact.get(arg)))
}
fn ping(&self) -> Box<Future<Item=StatusCode, Error=Error> + Send> {
let arg = "/_ping";
Box::new(status_code(self.interact.get(arg)))
}
fn events(&self, opts: &EventsOptions) -> Box<Stream<Item=Result<Event>, Error=Error> + Send> {
let query = opts.serialize();
let arg = ("/events", query.as_slice());
Box::new(parse_to_stream::<Event>(self.interact.get(arg)))
}
fn container(&self, id: Cow<'static, str>) -> Container
{
let interact = self.interact.clone();
Container::new(interact, id)
}
fn containers(&self) -> Containers
{
let interact = self.interact.clone();
Containers::new(interact)
}
fn image<'a>(&self, id: Cow<'a, str>) -> Image<'a>
{
let interact = self.interact.clone();
Image::new(interact, id)
}
fn images(&self) -> Images
{
let interact = self.interact.clone();
Images::new(interact)
}
fn network<'a>(&self, id: Cow<'a, str>) -> Network<'a>
{
let interact = self.interact.clone();
Network::new(interact, id)
}
fn networks(&self) -> Networks
{
let interact = self.interact.clone();
Networks::new(interact)
}
}
fn default_uri(uri: Option<Uri>) -> Result<Uri> {
use communicate::util::{URI_ENV, DEFAULT_URI};
match uri {
None => match env::var(URI_ENV) {
Ok(var) => var.parse().map_err(Error::from),
Err(_) => DEFAULT_URI.parse().map_err(Error::from),
},
Some(x) => Ok(x)
}
}
pub fn new_docker(host: Option<Uri>) -> Result<Box<DockerApi>>
{
let host = default_uri(host)?;
let scheme = host.scheme_part().map(|a| a.as_str().to_string());
match scheme.as_slice() {
Some(scheme) => match scheme {
#[cfg(target_os = "linux")]
"unix" => UnixDocker::new(host),
#[cfg(feature = "ssl")]
"https" => TcpSSLDocker::new(host),
"http" => TcpDocker::new(host),
_ => Err(ErrorKind::InvalidScheme.into()),
}
None => Err(ErrorKind::EmptyScheme.into())
}
}