//! This example will create a container and attach an interactive session to it //! passing through input and output into the tty running inside the container use bollard_next::container::{ AttachContainerOptions, AttachContainerResults, Config, RemoveContainerOptions, }; use bollard_next::Docker; 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::async_stdin; #[cfg(not(windows))] use termion::raw::IntoRawMode; use tokio::io::AsyncWriteExt; use tokio::task::spawn; use tokio::time::sleep; const IMAGE: &str = "alpine:3"; #[tokio::main] async fn main() -> Result<(), Box> { let docker = Docker::connect_with_socket_defaults().unwrap(); docker .create_image( Some(CreateImageOptions { from_image: IMAGE, ..Default::default() }), None, None, ) .try_collect::>() .await?; let alpine_config = Config { image: Some(IMAGE.to_owned()), tty: Some(true), attach_stdin: Some(true), attach_stdout: Some(true), attach_stderr: Some(true), open_stdin: Some(true), ..Default::default() }; let id = docker .create_container::<&str>(None, alpine_config) .await? .id; docker.start_container::(&id, None).await?; #[cfg(not(windows))] { let AttachContainerResults { mut output, mut input, } = docker .attach_container( &id, Some(AttachContainerOptions:: { stdout: Some(true), stderr: Some(true), stdin: Some(true), stream: Some(true), ..Default::default() }), ) .await?; // pipe stdin into the docker attach stream input 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; } } }); // set stdout in raw mode so we can do tty stuff let stdout = stdout(); let mut stdout = stdout.lock().into_raw_mode()?; // pipe docker attach output into stdout 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(()) }