yao 0.1.4

a fast, tiny, extensiable workflow engine
Documentation
use crate::{
    debug,
    sch::{ActId, ActState, TaskState},
    Act, ActTask, Branch, Context, Job, Step, Workflow,
};
use async_trait::async_trait;

#[derive(Clone)]
pub enum Task {
    Workflow(String, Workflow),
    Job(String, Job),
    Branch(String, Branch),
    Step(String, Step),
    Act(String, Act),
}

impl Task {
    pub fn check_pass(&self, ctx: &Context) -> bool {
        let pass = match self {
            Task::Workflow(_, workflow) => workflow.check_pass(ctx),
            Task::Job(_, job) => job.check_pass(ctx),
            Task::Branch(_, branch) => branch.check_pass(ctx),
            Task::Step(_, step) => step.check_pass(ctx),
            Task::Act(_, act) => act.check_pass(ctx),
        };
        debug!("check_pass: {}", pass);

        pass
    }

    pub fn start_time(&self) -> i64 {
        match self {
            Task::Workflow(_, workflow) => workflow.start_time(),
            Task::Job(_, job) => job.start_time(),
            Task::Branch(_, branch) => branch.start_time(),
            Task::Step(_, step) => step.start_time(),
            Task::Act(_, act) => act.start_time(),
        }
    }

    pub fn set_start_time(&self, time: i64) {
        match self {
            Task::Workflow(_, workflow) => workflow.set_start_time(time),
            Task::Job(_, job) => job.set_start_time(time),
            Task::Branch(_, branch) => branch.set_start_time(time),
            Task::Step(_, step) => step.set_start_time(time),
            Task::Act(_, act) => act.set_start_time(time),
        }
    }

    pub fn set_end_time(&self, time: i64) {
        match self {
            Task::Workflow(_, workflow) => workflow.set_end_time(time),
            Task::Job(_, job) => job.set_end_time(time),
            Task::Branch(_, branch) => branch.set_end_time(time),
            Task::Step(_, step) => step.set_end_time(time),
            Task::Act(_, act) => act.set_end_time(time),
        }
    }

    pub fn set_user(&self, user: &str) {
        match self {
            Task::Act(_, act) => act.set_user(user),
            _ => {}
        }
    }

    pub fn end_time(&self) -> i64 {
        match self {
            Task::Workflow(_, workflow) => workflow.end_time(),
            Task::Job(_, job) => job.end_time(),
            Task::Branch(_, branch) => branch.end_time(),
            Task::Step(_, step) => step.end_time(),
            Task::Act(_, act) => act.end_time(),
        }
    }

    pub fn user(&self) -> String {
        match self {
            Task::Workflow(_, _) => "".to_string(),
            Task::Job(_, _) => "".to_string(),
            Task::Branch(_, _) => "".to_string(),
            Task::Step(_, _) => "".to_string(),
            Task::Act(_, act) => {
                let user = act.user();
                match user {
                    Some(u) => u.clone(),
                    None => "".to_string(),
                }
            }
        }
    }

    pub fn needs(&self) -> Vec<String> {
        match self {
            Task::Workflow(_, _workflow) => vec![],
            Task::Job(_, job) => job.needs.clone(),
            Task::Branch(_, _branch) => vec![],
            Task::Step(_, _step) => vec![],
            Task::Act(_, _act) => vec![],
        }
    }

    pub fn as_job(&self) -> Option<&Job> {
        match self {
            Task::Job(_, job) => Some(job),
            _ => None,
        }
    }

    pub fn next(&self, ctx: &Context) {
        let next_ = |ctx: &Context| {
            if let Some(node) = ctx.proc.tree.node(&self.tid()) {
                ctx.proc.next(&node, ctx)
            }
        };
        match self {
            Task::Workflow(_, _) => {
                next_(ctx);
            }
            Task::Job(_, _) | Task::Branch(_, _) => {
                next_(ctx);
            }
            Task::Step(_, _) => {
                next_(ctx);
            }
            Task::Act(_, act) => {
                if let Some(step) = act.parent(ctx) {
                    if step.state().is_completed() {
                        return;
                    }
                    let ret = step.check_pass(ctx);
                    if ret {
                        step.set_state(&TaskState::Success);
                        next_(ctx);
                    }
                }
            }
        }
    }
}

impl ActId for Task {
    fn tid(&self) -> String {
        match self {
            Task::Workflow(tid, _) => tid.clone(),
            Task::Job(tid, _) => tid.clone(),
            Task::Branch(tid, _) => tid.clone(),
            Task::Step(tid, _) => tid.clone(),
            Task::Act(tid, _) => tid.clone(),
        }
    }
}
impl ActState for Task {
    fn state(&self) -> TaskState {
        match self {
            Task::Workflow(_, workflow) => workflow.state(),
            Task::Job(_, job) => job.state(),
            Task::Branch(_, branch) => branch.state(),
            Task::Step(_, step) => step.state(),
            Task::Act(_, act) => act.state(),
        }
    }

    fn set_state(&self, state: &TaskState) {
        match self {
            Task::Workflow(_, workflow) => workflow.set_state(state),
            Task::Job(_, job) => job.set_state(state),
            Task::Branch(_, branch) => branch.set_state(state),
            Task::Step(_, step) => step.set_state(state),
            Task::Act(_, act) => act.set_state(state),
        }
    }
}

#[async_trait]
impl ActTask for Task {
    fn prepare(&self, ctx: &Context) {
        debug!("prepare:{}", self.tid());
        if self.state().is_completed() {
            return;
        }
        ctx.prepare(self);
        match self {
            Task::Workflow(_, workflow) => {
                workflow.prepare(ctx);
            }
            Task::Job(_, job) => {
                job.prepare(ctx);
            }
            Task::Branch(_, branch) => branch.prepare(ctx),
            Task::Step(_, step) => {
                step.prepare(ctx);
            }
            Task::Act(_, act) => act.prepare(ctx),
        }
    }

    fn run(&self, ctx: &Context) {
        if self.state().is_completed() {
            return;
        }
        debug!("run:{} {:?}", self.tid(), self.state());
        match self {
            Task::Workflow(_, workflow) => workflow.run(ctx),
            Task::Job(_, job) => job.run(ctx),
            Task::Branch(_, branch) => branch.run(ctx),
            Task::Step(_, step) => step.run(ctx),
            Task::Act(_, act) => {
                act.run(ctx);
            }
        }
    }

    fn post(&self, ctx: &Context) {
        match self {
            Task::Workflow(_, workflow) => workflow.post(ctx),
            Task::Job(_, job) => job.post(ctx),
            Task::Branch(_, branch) => branch.post(ctx),
            Task::Step(_, step) => step.post(ctx),
            Task::Act(_, act) => act.post(ctx),
        }
        ctx.post(self);
        debug!("post:{} {:?}", self.tid(), self.state());
    }
}

impl std::fmt::Display for Task {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Task::Workflow(id, workflow) => write!(f, "({} {})", id, workflow.name),
            Task::Job(id, job) => write!(f, "({} {})", id, job.name),
            Task::Branch(id, branch) => write!(f, "({} {})", id, branch.name),
            Task::Step(id, step) => write!(f, "({} {})", id, step.name),
            Task::Act(id, act) => write!(f, "({} {})", id, act.owner),
        }
    }
}