taskflow-rs 0.1.1

A high-performance, async-first task orchestration framework for Rust
Documentation
use async_trait::async_trait;
use std::collections::HashMap;

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

pub struct ShellTaskHandler;

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

#[async_trait]
impl TaskHandler for ShellTaskHandler {
    async fn execute(&self, task: &Task) -> Result<TaskResult> {
        let start_time = std::time::Instant::now();

        let command = task
            .definition
            .payload
            .get("command")
            .and_then(|v| v.as_str())
            .ok_or_else(|| {
                TaskFlowError::InvalidConfiguration("Missing 'command' in payload".to_string())
            })?;

        let args: Vec<&str> = task
            .definition
            .payload
            .get("args")
            .and_then(|v| v.as_array())
            .map(|arr| arr.iter().filter_map(|v| v.as_str()).collect())
            .unwrap_or_default();

        let output = tokio::process::Command::new(command)
            .args(&args)
            .output()
            .await
            .map_err(|e| TaskFlowError::ExecutionError(e.to_string()))?;

        let execution_time = start_time.elapsed().as_millis() as u64;
        let success = output.status.success();

        let stdout = String::from_utf8_lossy(&output.stdout).to_string();
        let stderr = String::from_utf8_lossy(&output.stderr).to_string();

        let mut metadata = HashMap::new();
        metadata.insert(
            "exit_code".to_string(),
            output.status.code().unwrap_or(-1).to_string(),
        );

        Ok(TaskResult {
            success,
            output: Some(stdout),
            error: if success { None } else { Some(stderr) },
            execution_time_ms: execution_time,
            metadata,
        })
    }

    fn task_type(&self) -> &str {
        "shell_command"
    }
}