robotrt-action-core 0.1.0-beta.2

RobotRT modular robotics runtime and middleware components.
Documentation
use core_types::Timestamp;

/// Immediate acknowledgement returned to the client after a goal is sent.
///
/// One of the key differences between Action and Service: before a goal is
/// actually accepted for execution, the server first returns a `GoalAck`
/// indicating whether it is willing to handle the goal.
/// A rejected goal never enters execution and produces no feedback or result.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GoalAck {
    /// Whether the server accepted this goal.
    pub accepted: bool,
    /// Optional rejection reason or additional message.
    pub reason: Option<String>,
}

/// Current execution status of a goal (polled by the client, updated by the server).
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GoalStatus {
    /// Accepted by the server; not yet executing.
    Accepted,
    /// Currently executing.
    Executing,
    /// Cancel requested; server is processing the cancellation.
    Canceling,
    /// Execution completed successfully.
    Succeeded,
    /// Execution failed.
    Failed,
    /// Execution was canceled.
    Canceled,
    /// Goal was rejected by the server before execution began.
    Rejected,
}

impl GoalStatus {
    /// Returns `true` if this status is a terminal state (no further transitions possible).
    pub fn is_terminal(self) -> bool {
        matches!(
            self,
            GoalStatus::Succeeded
                | GoalStatus::Failed
                | GoalStatus::Canceled
                | GoalStatus::Rejected
        )
    }
}

/// Intermediate progress published by the server during goal execution.
///
/// Feedback is keyed by `ActionGoalId` so the client can distinguish updates
/// from concurrent goals. Delivery is best-effort; the client must not assume
/// every item is received. Only the final `ActionResult` is delivered exactly once.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ActionFeedback<F> {
    /// Timestamp when this feedback was produced.
    pub timestamp: Timestamp,
    /// Application-defined feedback payload.
    pub value: F,
}

/// Terminal result returned when a goal finishes (Succeeded / Failed / Canceled).
///
/// Regardless of the outcome, `ActionResult` is delivered exactly once.
/// After the client receives it, the goal's lifecycle is complete.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ActionResult<R> {
    /// Terminal status of the goal.
    pub status: GoalStatus,
    /// Result payload; `None` when canceled or rejected.
    pub value: Option<R>,
    /// Failure reason; present when `status == GoalStatus::Failed`.
    pub error: Option<String>,
}

/// Liveness classification for an action goal session.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ActionLiveness {
    /// The goal is progressing and heartbeat is within timeout budget.
    Active,
    /// The goal is not timed out yet but heartbeat age exceeds the stalled threshold.
    Stalled,
    /// The goal exceeded heartbeat timeout budget.
    TimedOut,
    /// Terminal goals are considered completed.
    Completed,
    /// Insufficient data to classify liveness.
    Unknown,
}

/// Health snapshot for a specific action goal.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ActionSessionHealth {
    pub goal_id: core_types::ActionGoalId,
    pub status: GoalStatus,
    pub liveness: ActionLiveness,
    pub heartbeat_timeout_nanos: Option<u128>,
    pub stalled_threshold_nanos: Option<u128>,
    pub last_heartbeat_at_unix_nanos: Option<u128>,
    pub last_feedback_at_unix_nanos: Option<u128>,
    pub last_result_at_unix_nanos: Option<u128>,
}

/// Schema descriptor for an action, covering the goal, feedback, and result message types.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ActionSchema {
    pub goal: data_model::SchemaDescriptor,
    pub feedback: data_model::SchemaDescriptor,
    pub result: data_model::SchemaDescriptor,
}