use bollard_next::container::{Config, RemoveContainerOptions};
use bollard_next::Docker;
use bollard_next::exec::{CreateExecOptions, ResizeExecOptions, StartExecResults};
use bollard_next::image::CreateImageOptions;
use futures_util::{StreamExt, TryStreamExt};
use std::io::{stdout, Read, Write};
use std::time::Duration;
#[cfg(not(windows))]
use termion::raw::IntoRawMode;
#[cfg(not(windows))]
use termion::{async_stdin, terminal_size};
use tokio::io::AsyncWriteExt;
use tokio::task::spawn;
use tokio::time::sleep;
const IMAGE: &str = "alpine:3";
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
let docker = Docker::connect_with_socket_defaults().unwrap();
#[cfg(not(windows))]
let tty_size = terminal_size()?;
docker
.create_image(
Some(CreateImageOptions {
from_image: IMAGE,
..Default::default()
}),
None,
None,
)
.try_collect::<Vec<_>>()
.await?;
let alpine_config = Config {
image: Some(IMAGE.to_owned()),
tty: Some(true),
..Default::default()
};
let id = docker
.create_container::<&str>(None, alpine_config)
.await?
.id;
docker.start_container::<String>(&id, None).await?;
let exec = docker
.create_exec(
&id,
CreateExecOptions {
attach_stdout: Some(true),
attach_stderr: Some(true),
attach_stdin: Some(true),
tty: Some(true),
cmd: Some(vec!["sh".into()]),
..Default::default()
},
)
.await?
.id;
#[cfg(not(windows))]
if let StartExecResults::Attached {
mut output,
mut input,
} = docker.start_exec(&exec, None).await?
{
spawn(async move {
let mut stdin = async_stdin().bytes();
loop {
if let Some(Ok(byte)) = stdin.next() {
input.write_all(&[byte]).await.ok();
} else {
sleep(Duration::from_nanos(10)).await;
}
}
});
docker
.resize_exec(
&exec,
ResizeExecOptions {
height: tty_size.1,
width: tty_size.0,
},
)
.await?;
let stdout = stdout();
let mut stdout = stdout.lock().into_raw_mode()?;
while let Some(Ok(output)) = output.next().await {
stdout.write_all(output.into_bytes().as_ref())?;
stdout.flush()?;
}
}
docker
.remove_container(
&id,
Some(RemoveContainerOptions {
force: true,
..Default::default()
}),
)
.await?;
Ok(())
}