Files
AstrBot/openspec/changes/rust-core-runtime-migration/spec.md

6.3 KiB

AstrBot Core Runtime (Rust) Specification

Overview

AstrBot Core Runtime is a high-performance Rust implementation of the core orchestrator, protocol clients, and configuration management. It provides Python bindings via pyo3 for seamless integration with the existing AstrBot Python codebase.

Module Structure

Core Modules

1. orchestrator.rs - Runtime Orchestrator

Central coordinator managing protocol clients and star registry.

pub struct Orchestrator {
    running: RwLock<bool>,
    stars: RwLock<HashMap<String, String>>,
    stats: RuntimeStats,
    protocol_lsp: RwLock<ProtocolStatus>,
    protocol_mcp: RwLock<ProtocolStatus>,
    protocol_acp: RwLock<ProtocolStatus>,
    protocol_abp: RwLock<ProtocolStatus>,
}

impl Orchestrator {
    pub fn new() -> Self;
    pub fn start(&self) -> Result<(), AstrBotError>;
    pub fn stop(&self) -> Result<(), AstrBotError>;
    pub fn is_running(&self) -> bool;
    pub fn register_star(&self, name: &str, handler: &str) -> Result<(), AstrBotError>;
    pub fn unregister_star(&self, name: &str) -> Result<(), AstrBotError>;
    pub fn list_stars(&self) -> Vec<String>;
    pub fn record_activity(&self);
    pub fn stats(&self) -> RuntimeStats;
    pub fn get_protocol_status(&self, protocol: &str) -> Option<ProtocolStatus>;
    pub fn set_protocol_connected(&self, protocol: &str, connected: bool) -> Result<(), AstrBotError>;
}

2. protocol.rs - Protocol Client Trait

Unified interface for all protocol clients.

#[async_trait]
pub trait ProtocolClient: Send + Sync {
    async fn connect(&mut self) -> Result<(), AstrBotError>;
    async fn disconnect(&mut self) -> Result<(), AstrBotError>;
    fn is_connected(&self) -> bool;
    fn name(&self) -> &'static str;
}

Implementations:

  • LspClient - Language Server Protocol client
  • McpClient - Model Context Protocol client
  • AcpClient - AstrBot Communication Protocol client
  • AbpClient - AstrBot Protocol client

3. message.rs - Message Types

Message structures with serde serialization.

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
    pub id: String,
    pub content: String,
    pub sender: String,
    pub timestamp: f64,
    pub message_type: MessageType,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Default)]
pub enum MessageType {
    #[default]
    Text,
    Image,
    Audio,
    Video,
    File,
    System,
    Unknown,
}

4. stats.rs - Runtime Statistics

Thread-safe message counting and uptime tracking.

#[derive(Debug, Clone)]
pub struct RuntimeStats {
    message_count: AtomicU64,
    start_time: Instant,
    last_activity: Mutex<Option<Instant>>,
}

impl RuntimeStats {
    pub fn new() -> Self;
    pub fn record_message(&self);
    pub fn message_count(&self) -> u64;
    pub fn uptime_seconds(&self) -> f64;
    pub fn last_activity_time(&self) -> Option<f64>;
}

5. config.rs - Configuration Management

TOML-based configuration with serde.

pub struct Config {
    pub runtime: RuntimeConfig,
    pub protocols: ProtocolsConfig,
    pub logging: LoggingConfig,
}

impl Config {
    pub fn load(path: &PathBuf) -> anyhow::Result<Self>;
    pub fn save(&self, path: &PathBuf) -> anyhow::Result<()>;
}

6. error.rs - Error Types

Using thiserror for ergonomic error handling.

#[derive(Error, Debug)]
pub enum AstrBotError {
    #[error("Not connected: {0}")]
    NotConnected(String),
    #[error("Connection failed: {0}")]
    ConnectionFailed(String),
    #[error("Protocol error: {0}")]
    Protocol(String),
    #[error("Timeout: {0}")]
    Timeout(String),
    #[error("Invalid state: {0}")]
    InvalidState(String),
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),
}

7. python.rs - Python Bindings

pyo3 bindings for Python integration.

#[pyclass]
pub struct PythonOrchestrator {
    inner: Orchestrator,
}

#[pymethods]
impl PythonOrchestrator {
    #[new]
    pub fn new() -> Self;
    pub fn start(&self) -> PyResult<()>;
    pub fn stop(&self) -> PyResult<()>;
    pub fn is_running(&self) -> bool;
    pub fn register_star(&self, name: &str, handler: &str) -> PyResult<()>;
    pub fn unregister_star(&self, name: &str) -> PyResult<()>;
    pub fn list_stars(&self) -> Vec<String>;
    pub fn record_activity(&self);
    pub fn get_stats(&self) -> PyResult<Py<PyAny>>;
    pub fn set_protocol_connected(&self, protocol: &str, connected: bool) -> PyResult<()>;
    pub fn get_protocol_status(&self, protocol: &str) -> Option<Py<PyAny>>;
}

#[pyfunction]
pub fn get_orchestrator(py: Python<'_>) -> PyResult<&'static Py<PythonOrchestrator>>;

8. main.rs - CLI Binary

Command-line interface using clap.

#[derive(Parser, Debug)]
enum Command {
    Start,
    Stats,
    Health,
}

Commands:

  • start - Start the astrbot-core runtime
  • stats - Display runtime statistics
  • health - Check runtime health status

Rust Rules

  1. No unsafe code - All memory access is safe
  2. No .unwrap() - Use ? operator or expect() with descriptive messages
  3. Clippy pedantic compliance - Pass cargo clippy with no warnings
  4. Full error handling - All errors properly propagated

Python Integration

The module is importable as astrbot_core:

from astrbot_core import PythonOrchestrator, get_orchestrator

# Get singleton
orch = get_orchestrator()

# Use methods
orch.start()
orch.register_star("my-star", "handler-id")
stars = orch.list_stars()

Cargo Features

[features]
default = ["python"]
python = ["pyo3"]
  • python: Enable pyo3 bindings (default)
  • Without python: Pure Rust library without Python dependencies

Dependencies

  • serde + serde_json - Serialization
  • toml - Configuration file parsing
  • tokio - Async runtime
  • tracing + tracing-subscriber - Logging
  • anyhow - Error handling
  • thiserror - Error derive
  • async-trait - Async trait methods
  • clap - CLI argument parsing
  • pyo3 - Python bindings (optional)

Verification Criteria

  • cargo clippy passes with no warnings
  • cargo build compiles successfully
  • cargo test passes (if tests exist)
  • Python module imports successfully
  • CLI --help works correctly