Skip to content

Commit

Permalink
examples/*: streamline, refactor, and rewrite to use future chaining
Browse files Browse the repository at this point in the history
  • Loading branch information
steveej committed Oct 24, 2018
1 parent ca86157 commit 363baf3
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 217 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ strum = "0.11"
strum_macros = "0.11"
tar = "0.4"
tokio-core = "0.1"
dirs = "1.0"

[dev-dependencies]
env_logger = "0.5"
Expand Down
8 changes: 3 additions & 5 deletions examples/checkregistry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ extern crate tokio_core;
use std::{boxed, error};
use tokio_core::reactor::Core;

type Result<T> = std::result::Result<T, boxed::Box<error::Error>>;

fn main() {
let registry = match std::env::args().nth(1) {
Some(x) => x,
Expand All @@ -20,20 +18,20 @@ fn main() {
};
}

fn run(host: &str) -> Result<bool> {
fn run(host: &str) -> Result<bool, boxed::Box<error::Error>> {
let mut tcore = try!(Core::new());
let dclient = try!(
dkregistry::v2::Client::configure(&tcore.handle())
.registry(host)
.insecure_registry(false)
.build()
);
let futcheck = try!(dclient.is_v2_supported());
let futcheck = dclient.is_v2_supported();

let supported = try!(tcore.run(futcheck));
match supported {
false => println!("{} does NOT support v2", host),
true => println!("{} supports v2", host),
}
return Ok(supported);
Ok(supported)
}
42 changes: 42 additions & 0 deletions examples/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
extern crate dkregistry;
extern crate futures;

use futures::prelude::*;

pub fn authenticate_client<'a>(
client: &'a mut dkregistry::v2::Client,
login_scope: &'a str,
) -> impl futures::future::Future<Item = &'a dkregistry::v2::Client, Error = dkregistry::errors::Error>
{
futures::future::ok::<_, dkregistry::errors::Error>(client)
.and_then(|dclient| {
dclient.is_v2_supported().and_then(|v2_supported| {
if !v2_supported {
Err("API v2 not supported".into())
} else {
Ok(dclient)
}
})
}).and_then(|dclient| {
dclient.is_auth(None).and_then(|is_auth| {
if is_auth {
Err("no login performed, but already authenticated".into())
} else {
Ok(dclient)
}
})
}).and_then(move |dclient| {
dclient.login(&[&login_scope]).and_then(move |token| {
dclient
.is_auth(Some(token.token()))
.and_then(move |is_auth| {
if !is_auth {
Err("login failed".into())
} else {
println!("logged in!");
Ok(dclient.set_token(Some(token.token())))
}
})
})
})
}
161 changes: 83 additions & 78 deletions examples/image.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
extern crate dirs;
extern crate dkregistry;
extern crate futures;
extern crate serde_json;
extern crate tokio_core;

use dkregistry::{reference, render};
use futures::prelude::*;
use std::result::Result;
use std::str::FromStr;
use std::{boxed, env, error, fs, io};
use tokio_core::reactor::Core;

use std::str::FromStr;

type Result<T> = std::result::Result<T, boxed::Box<error::Error>>;
mod common;

fn main() {
let dkr_ref = match std::env::args().nth(1) {
Expand All @@ -22,7 +24,7 @@ fn main() {

let mut user = None;
let mut password = None;
let home = env::home_dir().unwrap_or("/root".into());
let home = dirs::home_dir().unwrap();
let cfg = fs::File::open(home.join(".docker/config.json"));
if let Ok(fp) = cfg {
let creds = dkregistry::get_credentials(io::BufReader::new(fp), &registry);
Expand Down Expand Up @@ -51,87 +53,90 @@ fn main() {
};
}

fn run(dkr_ref: &reference::Reference, user: Option<String>, passwd: Option<String>) -> Result<()> {
let image = dkr_ref.repository();
let version = dkr_ref.version();

fn run(
dkr_ref: &reference::Reference,
user: Option<String>,
passwd: Option<String>,
) -> Result<(), boxed::Box<error::Error>> {
let mut tcore = try!(Core::new());
let mut dclient = try!(
dkregistry::v2::Client::configure(&tcore.handle())
.registry(&dkr_ref.registry())
.insecure_registry(false)
.username(user)
.password(passwd)
.build()
);

let futcheck = try!(dclient.is_v2_supported());
let supported = try!(tcore.run(futcheck));
if !supported {
return Err("API v2 not supported".into());
}

let fut_token = try!(dclient.login(&[&format!("repository:{}:pull", image)]));
let token_auth = try!(tcore.run(fut_token));

let futauth = try!(dclient.is_auth(Some(token_auth.token())));
if !try!(tcore.run(futauth)) {
return Err("login failed".into());
}
let mut client = dkregistry::v2::Client::configure(&tcore.handle())
.registry(&dkr_ref.registry())
.insecure_registry(false)
.username(user)
.password(passwd)
.build()?;

dclient.set_token(Some(token_auth.token()));

let fut_hasmanif = dclient.has_manifest(&image, &version, None)?;
let manifest_kind = try!(tcore.run(fut_hasmanif)?.ok_or("no manifest found"));

let fut_manif = dclient.get_manifest(&image, &version)?;
let body = tcore.run(fut_manif)?;
let image = dkr_ref.repository();
let login_scope = format!("repository:{}:pull", image);
let version = dkr_ref.version();

let layers = match manifest_kind {
dkregistry::mediatypes::MediaTypes::ManifestV2S1Signed => {
let m: dkregistry::v2::manifest::ManifestSchema1Signed =
try!(serde_json::from_slice(body.as_slice()));
m.get_layers()
}
dkregistry::mediatypes::MediaTypes::ManifestV2S2 => {
let m: dkregistry::v2::manifest::ManifestSchema2 =
try!(serde_json::from_slice(body.as_slice()));
m.get_layers()
}
_ => return Err("unknown format".into()),
let futures = common::authenticate_client(&mut client, &login_scope)
.and_then(|dclient| {
dclient
.has_manifest(&image, &version, None)
.and_then(move |manifest_option| Ok((dclient, manifest_option)))
.and_then(|(dclient, manifest_option)| match manifest_option {
None => Err(format!("{}:{} doesn't have a manifest", &image, &version).into()),

Some(manifest_kind) => Ok((dclient, manifest_kind)),
})
}).and_then(|(dclient, manifest_kind)| {
let image = image.clone();
dclient.get_manifest(&image, &version).and_then(
move |manifest_body| match manifest_kind {
dkregistry::mediatypes::MediaTypes::ManifestV2S1Signed => {
let m: dkregistry::v2::manifest::ManifestSchema1Signed = match
serde_json::from_slice(manifest_body.as_slice()) {
Ok(json) => json,
Err(e) => return Err(e.into()),

};
Ok((dclient, m.get_layers()))
}
dkregistry::mediatypes::MediaTypes::ManifestV2S2 => {
let m: dkregistry::v2::manifest::ManifestSchema2 =
match serde_json::from_slice(manifest_body.as_slice()) {
Ok(json) => json,
Err(e) => return Err(e.into()),
};
Ok((dclient, m.get_layers()))
}
_ => Err("unknown format".into()),
},
)
}).and_then(|(dclient, layers)| {
let image = image.clone();

println!("{} -> got {} layer(s)", &image, layers.len(),);

futures::stream::iter_ok::<_, dkregistry::errors::Error>(layers)
.and_then(move |layer| {
let get_blob_future = dclient.get_blob(&image, &layer);
get_blob_future.inspect(move |blob| {
println!("Layer {}, got {} bytes.\n", layer, blob.len());
})
}).collect()
});

let blobs = match tcore.run(futures) {
Ok(blobs) => blobs,
Err(e) => return Err(Box::new(e)),
};

println!(
"{} -> got {} layer(s), saving to directory {:?}",
image,
layers.len(),
version
);
std::fs::create_dir(&version)?;
let mut blobs: Vec<Vec<u8>> = vec![];

for (i, digest) in layers.iter().enumerate() {
let fut_presence = dclient.has_blob(&image, &digest)?;
let has_blob = tcore.run(fut_presence)?;
if !has_blob {
return Err(format!("missing layer {}", digest).into());
}
println!("Downloaded {} layers", blobs.len());

println!("Downloading layer {}...", digest);
let fut_out = dclient.get_blob(&image, &digest)?;
let out = tcore.run(fut_out)?;
println!(
"Layer {}/{}, got {} bytes.\n",
i + 1,
layers.len(),
out.len()
);
blobs.push(out);
// FIXME: use async io
let path = &format!("{}:{}", &image, &version).replace("/", "_");
let path = std::path::Path::new(&path);
if path.exists() {
return Err(format!("path {:?} already exists, exiting", &path).into());
}
std::fs::create_dir(&path).unwrap();
let can_path = path.canonicalize().unwrap();

println!("Unpacking layers to {:?}", &can_path);
let r = render::unpack(&blobs, &can_path).unwrap();

let can_path = std::fs::canonicalize(&version)?;
let r = render::unpack(&blobs, &can_path);
println!("{:?}", r);
r?;
Ok(())
Ok(r)
}
68 changes: 28 additions & 40 deletions examples/login.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
extern crate dkregistry;
extern crate futures;
extern crate tokio_core;

mod common;

use futures::prelude::*;
use std::result::Result;
use std::{boxed, error};
use tokio_core::reactor::Core;

type Result<T> = std::result::Result<T, boxed::Box<error::Error>>;

fn main() {
let registry = match std::env::args().nth(1) {
Some(x) => x,
Expand All @@ -29,43 +32,28 @@ fn main() {
};
}

fn run(host: &str, user: Option<String>, passwd: Option<String>) -> Result<()> {
let mut tcore = try!(Core::new());
let dclient = try!(
dkregistry::v2::Client::configure(&tcore.handle())
.registry(host)
.insecure_registry(false)
.username(user)
.password(passwd)
.build()
);

let futcheck = try!(dclient.is_v2_supported());
let supported = try!(tcore.run(futcheck));
if !supported {
return Err("API v2 not supported".into());
fn run(
host: &str,
user: Option<String>,
passwd: Option<String>,
) -> Result<(), boxed::Box<error::Error>> {
let mut tcore = Core::new()?;

let mut client = dkregistry::v2::Client::configure(&tcore.handle())
.registry(host)
.insecure_registry(false)
.username(user)
.password(passwd)
.build()?;

let login_scope = "";

let futures = common::authenticate_client(&mut client, &login_scope)
.and_then(|dclient| dclient.is_v2_supported());

match tcore.run(futures) {
Ok(login_successful) if login_successful => Ok(()),
Err(e) => Err(Box::new(e)),
_ => Err("Login unsucessful".into()),
}

let futauth = try!(dclient.is_auth(None));
let logged_in = try!(tcore.run(futauth));
if logged_in {
return Err("no login performed, but already authenticated".into());
}

let fut_token = try!(dclient.login(&[]));
let token = try!(tcore.run(fut_token));

let futauth = try!(dclient.is_auth(Some(token.token())));
let done = try!(tcore.run(futauth));

match done {
false => return Err("login failed".into()),
true => println!("logged in!",),
}
let futcheck = try!(dclient.is_v2_supported());
if !try!(tcore.run(futcheck)) {
return Err("API check failed after login".into());
};

return Ok(());
}
Loading

0 comments on commit 363baf3

Please sign in to comment.