Skip to content

Commit 929070b

Browse files
authored
Merge pull request #59 from cgwalters/add-example-client
Add an example client
2 parents a9aae43 + ebec044 commit 929070b

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ tracing = "0.1"
2424
# We support both versions
2525
cap-std-ext = ">= 2.0, <= 3.0"
2626

27+
[dev-dependencies]
28+
bytes = "1.5"
29+
clap = { version = "4.4", features = ["derive"] }
30+
2731
[lib]
2832
path = "src/imageproxy.rs"
2933

examples/client.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use std::io::Write;
2+
3+
use anyhow::Result;
4+
use clap::Parser;
5+
use oci_spec::image::ImageManifest;
6+
use tokio::io::AsyncReadExt;
7+
8+
#[derive(clap::Parser, Debug)]
9+
struct GetMetadataOpts {
10+
/// The skopeo-style transport:image reference
11+
reference: String,
12+
}
13+
14+
#[derive(clap::Parser, Debug)]
15+
struct GetBlobOpts {
16+
/// The skopeo-style transport:image reference
17+
reference: String,
18+
19+
/// The digest of the target blob to fetch
20+
digest: String,
21+
22+
/// The size of the blob to fetch
23+
size: u64,
24+
}
25+
26+
/// Simple program to greet a person
27+
#[derive(clap::Parser, Debug)]
28+
#[command(version, about, long_about = None)]
29+
enum Opt {
30+
GetMetadata(GetMetadataOpts),
31+
GetBlob(GetBlobOpts),
32+
}
33+
34+
#[derive(serde::Serialize, Debug)]
35+
struct Metadata {
36+
digest: String,
37+
manifest: ImageManifest,
38+
}
39+
40+
async fn get_metadata(o: GetMetadataOpts) -> Result<()> {
41+
let proxy = containers_image_proxy::ImageProxy::new().await?;
42+
let img = proxy.open_image(&o.reference).await?;
43+
let (digest, manifest) = proxy.fetch_manifest(&img).await?;
44+
let metadata = Metadata { digest, manifest };
45+
serde_json::to_writer_pretty(&mut std::io::stdout().lock(), &metadata)?;
46+
Ok(())
47+
}
48+
49+
async fn get_blob(o: GetBlobOpts) -> Result<()> {
50+
let proxy = containers_image_proxy::ImageProxy::new().await?;
51+
let img = proxy.open_image(&o.reference).await?;
52+
let (mut blob, driver) = proxy.get_blob(&img, &o.digest, o.size).await?;
53+
54+
let mut stdout = std::io::stdout().lock();
55+
let reader = async move {
56+
let mut buffer = [0u8; 8192];
57+
loop {
58+
let n = blob.read(&mut buffer).await?;
59+
if n == 0 {
60+
return anyhow::Ok(());
61+
}
62+
stdout.write_all(&buffer[..n])?;
63+
}
64+
};
65+
66+
let (a, b) = tokio::join!(reader, driver);
67+
a?;
68+
b?;
69+
Ok(())
70+
}
71+
72+
async fn run() -> Result<()> {
73+
match Opt::parse() {
74+
Opt::GetMetadata(o) => get_metadata(o).await,
75+
Opt::GetBlob(o) => get_blob(o).await,
76+
}
77+
}
78+
79+
#[tokio::main(flavor = "current_thread")]
80+
async fn main() {
81+
if let Err(e) = run().await {
82+
eprintln!("{:#}", e);
83+
}
84+
}

0 commit comments

Comments
 (0)