maelstrom-worker 0.14.0

The Maelstrom worker. This process executes jobs as directed by the broker.
use anyhow::Result;
use futures::StreamExt as _;
use maelstrom_base::{manifest::UnixTimestamp, ArtifactType, Sha256Digest};
use maelstrom_layer_fs::{BlobDir, BottomLayerBuilder, LayerFs, UpperLayerBuilder};
use maelstrom_util::{
    async_fs::Fs,
    cache::{
        fs::{
            std::{Fs as StdFs, TempDir as StdTempDir},
            TempDir as _,
        },
        TempFileFactory,
    },
    root::Root,
};
use slog::Logger;
use std::path::{Path, PathBuf};
use tokio::io::BufReader;

async fn dir_size(fs: &Fs, path: &Path) -> Result<u64> {
    let mut total = 0;
    let mut entries = fs.read_dir(path).await?;
    while let Some(e) = entries.next().await {
        let e = e?;
        total += e.metadata().await?.len();
    }
    Ok(total)
}

pub async fn build_bottom_layer(
    log: Logger,
    temp_file_factory: TempFileFactory<StdFs>,
    blob_dir: &Root<BlobDir>,
    artifact_digest: Sha256Digest,
    artifact_type: ArtifactType,
    artifact_path: PathBuf,
) -> Result<(StdTempDir, u64)> {
    let layer_temp_dir = temp_file_factory.temp_dir()?;
    let layer_path = layer_temp_dir.path();
    let fs = Fs::new();
    let mut builder =
        BottomLayerBuilder::new(log, &fs, layer_path, blob_dir, UnixTimestamp::EPOCH).await?;
    let artifact_file = BufReader::new(fs.open_file(artifact_path).await?);
    match artifact_type {
        ArtifactType::Tar => builder.add_from_tar(artifact_digest, artifact_file).await?,
        ArtifactType::Manifest => builder.add_from_manifest(artifact_file).await?,
    }
    builder.finish().await?;

    let size = dir_size(&fs, layer_path).await?;
    Ok((layer_temp_dir, size))
}

pub async fn build_upper_layer(
    log: Logger,
    temp_file_factory: TempFileFactory<StdFs>,
    blob_dir: &Root<BlobDir>,
    lower_layer_path: PathBuf,
    upper_layer_path: PathBuf,
) -> Result<(StdTempDir, u64)> {
    let layer_temp_dir = temp_file_factory.temp_dir()?;
    let layer_path = layer_temp_dir.path();
    let fs = Fs::new();
    let lower = LayerFs::from_path(&lower_layer_path, blob_dir)?;
    let upper = LayerFs::from_path(&upper_layer_path, blob_dir)?;
    let mut builder = UpperLayerBuilder::new(log, layer_path, blob_dir, &lower).await?;
    builder.fill_from_bottom_layer(&upper).await?;
    builder.fill_from_bottom_layer(&upper).await?;
    builder.finish().await?;

    let size = dir_size(&fs, layer_path).await?;
    Ok((layer_temp_dir, size))
}