cobble-core 1.2.0

Library for managing, installing and launching Minecraft instances and more.
Documentation
use crate::error::CobbleResult;
use async_zip::read::seek::ZipFileReader;
use std::path::{Path, PathBuf};
use time::OffsetDateTime;
use tokio::fs::{remove_file, File};

/// Represents a single log file.
/// On each launch the game creates a new log file and compresses the old one.
#[cfg_attr(doc_cfg, doc(cfg(feature = "log-files")))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug)]
pub struct LogFile {
    /// Filename
    pub name: String,
    /// Filepath
    pub path: PathBuf,
    /// Type
    pub _type: LogFileType,
    /// Modified timestamp on filesystem
    #[cfg_attr(feature = "serde", serde(with = "time::serde::rfc3339::option"))]
    pub modified: Option<OffsetDateTime>,
}

impl LogFile {
    /// Removes the log file from disk.
    ///
    /// **Warning**: This will permanently delete the file!
    #[instrument(
        name = "remove_log_file",
        level = "trace",
        skip_all,
        fields(
            path = %self.path.to_string_lossy(),
        )
    )]
    pub async fn remove(self) -> CobbleResult<()> {
        remove_file(&self.path).await?;
        Ok(())
    }

    /// Unpacks the log file if it is compressed.
    /// If the file is **not** compressed, it copies the file to the target path.
    #[instrument(
        name = "extract_log_file",
        level = "trace",
        skip_all,
        fields(
            source = %self.path.to_string_lossy(),
            target = %target.as_ref().to_string_lossy(),
        )
    )]
    pub async fn unpack(&self, target: impl AsRef<Path> + Send) -> CobbleResult<()> {
        match self._type {
            LogFileType::Plain => {
                trace!("Copying file to target location");
                tokio::fs::copy(&self.path, target).await?;
            }
            LogFileType::GzipCompressed => {
                trace!("Extracting log file to target location");
                let mut file = File::open(&self.path).await?;
                let mut archive = ZipFileReader::new(&mut file).await?;

                let entry_reader = archive.entry_reader(0).await?;

                let mut out_file = File::create(target).await?;
                entry_reader.copy_to_end_crc(&mut out_file, 64000).await?;
            }
        }

        Ok(())
    }
}

/// Whether the file is compressed or in plain text.
#[cfg_attr(doc_cfg, doc(cfg(feature = "log-files")))]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug)]
pub enum LogFileType {
    /// Plain text
    Plain,
    /// GZip compressed text
    GzipCompressed,
}