Skip to content

Clock

The clock module manages frame timing for the forge runner. It provides types for controlling tick interval, pausing and resuming the clock, and querying clock state — all expressed as serializable request/response messages so they can be forwarded over HTTP, WebSocket, or any async channel.

ClockAction

pub enum ClockAction {
    Step,
    SetInterval { interval_ms: u64 },
    Pause,
    Resume,
    Status,
}
Action Effect
Step Advance exactly one frame, regardless of interval
SetInterval { interval_ms } Start or change the continuous tick interval. interval_ms = 0 means single-shot mode
Pause Suspend the clock; subsequent Step commands still work
Resume Restart a paused clock
Status Return current ClockStatus without mutating state

ClockRequest / ClockResponse

pub struct ClockRequest {
    pub action: ClockAction,
    pub session_id: String,
    pub request_id: Option<String>,
}

pub struct ClockResponse {
    pub success: bool,
    pub status: Option<ClockStatus>,
    pub error: Option<ClockError>,
    pub request_id: Option<String>,
}

Build a request:

let req = ClockRequest::new(ClockAction::Pause, "session-abc")
    .with_request_id("req-001");

The response echoes the request_id so callers can correlate async responses.

ClockState

ClockState is the mutable runtime state held by the clock task. It is not part of the public serialization contract; use ClockStatus for the observable view.

ClockStatus

pub struct ClockStatus {
    pub running: bool,
    pub paused: bool,
    pub interval_ms: u64,
    pub current_frame: i64,
    pub mode: String,   // "continuous" | "single_shot" | "paused"
}

Convenience predicates:

status.is_continuous()   // interval_ms > 0 and not paused
status.is_single_shot()  // interval_ms == 0
status.is_paused()       // paused flag set

ClockError

pub struct ClockError {
    pub code: String,
    pub message: String,
}

Standard codes: "invalid_action", "operation_failed".

handle_clock_request

pub async fn handle_clock_request(
    request: ClockRequest,
    state: &ClockState,
) -> ClockResponse;

The handler is async because some actions (e.g. SetInterval) may interact with the tokio task that drives frame advancement. It always returns a ClockResponse rather than propagating errors, so it is safe to call over an HTTP handler without additional error mapping.

Time Utilities

// Current wall-clock time as milliseconds since Unix epoch
pub fn current_time_ms() -> u64;

// Same, as SystemTime
pub fn now() -> std::time::SystemTime;

// Convert between u64 ms and SystemTime
pub fn ms_to_system_time(ms: u64) -> std::time::SystemTime;
pub fn system_time_to_ms(t: std::time::SystemTime) -> u64;

FrameTimestamp and FrameDuration are newtype wrappers over u64 (ms) for type-safe frame timing arithmetic.

ClockUtils is a utility struct grouping the above functions for use from non-async contexts where you cannot call current_time_ms() directly.