taskflow-rs 0.1.1

A high-performance, async-first task orchestration framework for Rust
Documentation
use tokio::fs;
use tracing::info;

use crate::error::{Result, TaskFlowError};
use crate::task::{Task, TaskHandler, TaskResult};

pub struct FileTaskHandler;

impl FileTaskHandler {
    pub fn new() -> Self {
        Self
    }
}

#[async_trait::async_trait]
impl TaskHandler for FileTaskHandler {
    fn task_type(&self) -> &'static str {
        "file_operation"
    }

    async fn execute(&self, task: &Task) -> Result<TaskResult> {
        let operation = task
            .definition
            .payload
            .get("operation")
            .and_then(|v| v.as_str())
            .ok_or_else(|| {
                TaskFlowError::InvalidConfiguration("Missing operation type".to_string())
            })?;

        let path = task
            .definition
            .payload
            .get("path")
            .and_then(|v| v.as_str())
            .ok_or_else(|| TaskFlowError::InvalidConfiguration("Missing file path".to_string()))?;

        info!("Performing file operation {} on: {}", operation, path);

        match operation {
            "read" => self.read_file(path).await,
            "write" => self.write_file(task, path).await,
            "delete" => self.delete_file(path).await,
            "copy" => self.copy_file(task, path).await,
            "move" => self.move_file(task, path).await,
            op => Err(TaskFlowError::InvalidConfiguration(format!(
                "Unknown file operation: {}",
                op
            ))),
        }
    }
}

impl FileTaskHandler {
    async fn read_file(&self, path: &str) -> Result<TaskResult> {
        let content = fs::read_to_string(path)
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        Ok(TaskResult {
            success: true,
            output: Some(content),
            error: None,
            execution_time_ms: 0,
            metadata: Default::default(),
        })
    }

    async fn write_file(&self, task: &Task, path: &str) -> Result<TaskResult> {
        let content = task
            .definition
            .payload
            .get("content")
            .and_then(|v| v.as_str())
            .ok_or_else(|| TaskFlowError::InvalidConfiguration("Missing content".to_string()))?;

        fs::write(path, content)
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        Ok(TaskResult {
            success: true,
            output: Some(format!("File written successfully: {}", path)),
            error: None,
            execution_time_ms: 0,
            metadata: Default::default(),
        })
    }

    async fn delete_file(&self, path: &str) -> Result<TaskResult> {
        fs::remove_file(path)
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        Ok(TaskResult {
            success: true,
            output: Some(format!("File deleted: {}", path)),
            error: None,
            execution_time_ms: 0,
            metadata: Default::default(),
        })
    }

    async fn copy_file(&self, task: &Task, source_path: &str) -> Result<TaskResult> {
        let dest_path = task
            .definition
            .payload
            .get("destination")
            .and_then(|v| v.as_str())
            .ok_or_else(|| {
                TaskFlowError::InvalidConfiguration("Missing destination path".to_string())
            })?;

        fs::copy(source_path, dest_path)
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        Ok(TaskResult {
            success: true,
            output: Some(format!("File copied from {} to {}", source_path, dest_path)),
            error: None,
            execution_time_ms: 0,
            metadata: Default::default(),
        })
    }

    async fn move_file(&self, task: &Task, source_path: &str) -> Result<TaskResult> {
        let dest_path = task
            .definition
            .payload
            .get("destination")
            .and_then(|v| v.as_str())
            .ok_or_else(|| {
                TaskFlowError::InvalidConfiguration("Missing destination path".to_string())
            })?;

        fs::rename(source_path, dest_path)
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        Ok(TaskResult {
            success: true,
            output: Some(format!("File moved from {} to {}", source_path, dest_path)),
            error: None,
            execution_time_ms: 0,
            metadata: Default::default(),
        })
    }
}