Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Theater API Documentation

This page provides an overview of the Theater API. For detailed reference documentation, you can check out the auto-generated rustdoc API Reference.

Note: The rustdoc API Reference provides detailed information about all types, functions, and modules directly from the code annotations.

Core Concepts

Theater uses WebAssembly components to create isolated, deterministic actors that communicate through a message-passing interface. Each actor is a WebAssembly component that implements specific interfaces defined using the WebAssembly Interface Type (WIT) system.

Key API Components

Here are some key components in the API:

Core Actor Interface

Every Theater actor must implement the core actor interface:

// ntwk:theater/actor interface
package ntwk:theater

interface types {
    /// JSON-encoded data
    type json = list<u8>
    
    /// Event structure for actor messages
    record event {
        event-type: string,
        parent: option<u64>,
        data: json
    }
}

interface actor {
    use types.{json, event}

    /// Initialize actor state
    init: func() -> json

    /// Handle an incoming event, returning new state
    handle: func(evt: event, state: json) -> json
}

Implementation Example

Here's how to implement the core actor interface in Rust:

#![allow(unused)]
fn main() {
use bindings::exports::ntwk::theater::actor::Guest as ActorGuest;
use bindings::ntwk::theater::types::{Event, Json};
use serde::{Deserialize, Serialize};

// Define your actor's state
#[derive(Serialize, Deserialize)]
struct State {
    count: i32,
    last_updated: String,
}

struct Component;

impl ActorGuest for Component {
    // Initialize actor state
    fn init() -> Vec<u8> {
        let initial_state = State {
            count: 0,
            last_updated: chrono::Utc::now().to_string(),
        };
        
        serde_json::to_vec(&initial_state).unwrap()
    }

    // Handle incoming messages
    fn handle(evt: Event, state: Vec<u8>) -> Vec<u8> {
        let mut current_state: State = serde_json::from_slice(&state).unwrap();
        
        // Process the event
        if let Ok(message) = serde_json::from_slice(&evt.data) {
            // Update state based on message...
        }
        
        serde_json::to_vec(&current_state).unwrap()
    }
}

bindings::export!(Component with_types_in bindings);
}

Available Host Functions

Theater provides several host functions that actors can use. For complete details, see the host module documentation.

Runtime Interface

// ntwk:theater/runtime interface
interface runtime {
    /// Log a message to the host system
    log: func(msg: string)

    /// Spawn a new actor from a manifest
    spawn: func(manifest: string)

    /// Get the current event chain
    get-chain: func() -> chain
}

HTTP Server Interface

// ntwk:theater/http-server interface
interface http-server {
    record http-request {
        method: string,
        path: string,
        headers: list<tuple<string, string>>,
        body: option<list<u8>>
    }

    record http-response {
        status: u16,
        headers: list<tuple<string, string>>,
        body: option<list<u8>>
    }

    handle-request: func(req: http-request, state: json) -> tuple<http-response, json>
}

The HttpFramework provides the implementation of this interface.

WebSocket Server Interface

// ntwk:theater/websocket-server interface
interface websocket-server {
    use types.{json}

    /// Types of WebSocket messages
    enum message-type {
        text,
        binary,
        connect,
        close,
        ping,
        pong,
        other(string)
    }

    /// WebSocket message structure
    record websocket-message {
        ty: message-type,
        data: option<list<u8>>,
        text: option<string>
    }

    /// WebSocket response structure
    record websocket-response {
        messages: list<websocket-message>
    }

    /// Handle an incoming WebSocket message
    handle-message: func(msg: websocket-message, state: json) -> tuple<json, websocket-response>
}

Handler Implementation Examples

HTTP Server Handler

#![allow(unused)]
fn main() {
use bindings::exports::ntwk::theater::http_server::Guest as HttpGuest;
use bindings::ntwk::theater::types::Json;
use bindings::ntwk::theater::http_server::{HttpRequest, HttpResponse};

impl HttpGuest for Component {
    fn handle_request(req: HttpRequest, state: Json) -> (HttpResponse, Json) {
        match (req.method.as_str(), req.path.as_str()) {
            ("GET", "/count") => {
                let current_state: State = serde_json::from_slice(&state).unwrap();
                
                (HttpResponse {
                    status: 200,
                    headers: vec![
                        ("Content-Type".to_string(), "application/json".to_string())
                    ],
                    body: Some(serde_json::json!({
                        "count": current_state.count
                    }).to_string().into_bytes()),
                }, state)
            },
            _ => (HttpResponse {
                status: 404,
                headers: vec![],
                body: None,
            }, state)
        }
    }
}
}

For more details on HTTP handling, see the HTTP Client documentation.

WebSocket Server Handler

#![allow(unused)]
fn main() {
use bindings::exports::ntwk::theater::websocket_server::Guest as WebSocketGuest;
use bindings::ntwk::theater::types::Json;
use bindings::ntwk::theater::websocket_server::{
    WebSocketMessage,
    WebSocketResponse,
    MessageType
};

impl WebSocketGuest for Component {
    fn handle_message(msg: WebSocketMessage, state: Json) -> (Json, WebSocketResponse) {
        let mut current_state: State = serde_json::from_slice(&state).unwrap();
        
        let response = match msg.ty {
            MessageType::Text => {
                if let Some(text) = msg.text {
                    // Process text message...
                    WebSocketResponse {
                        messages: vec![WebSocketMessage {
                            ty: MessageType::Text,
                            text: Some("Message received".to_string()),
                            data: None,
                        }]
                    }
                } else {
                    WebSocketResponse { messages: vec![] }
                }
            },
            _ => WebSocketResponse { messages: vec![] }
        };
        
        (serde_json::to_vec(&current_state).unwrap(), response)
    }
}
}

Actor Configuration

Actors are configured using TOML manifests. See the ManifestConfig for details on the configuration options.

name = "example-actor"
component_path = "target/wasm32-wasi/release/example_actor.wasm"

[interface]
implements = "ntwk:theater/websocket-server"
requires = []

[[handlers]]
type = "websocket-server"
config = { port = 8080 }

[logging]
level = "debug"

Hash Chain Integration

Theater uses a hash chain to track state transitions. See the StateChain for more details.

Best Practices

  1. State Management

    • Use serde for state serialization
    • Keep state JSON-serializable
    • Include timestamps in state
    • Handle serialization errors
  2. Message Handling

    • Validate message format
    • Handle all message types
    • Return consistent responses
    • Preserve state on errors
  3. Handler Implementation

    • Implement appropriate interfaces
    • Handle all request types
    • Return proper responses
    • Maintain state consistency
  4. Error Handling

    • Log errors with context
    • Return unchanged state on error
    • Validate all inputs
    • Handle all error cases

Development Tips

  1. Use the chat-room example as a reference implementation
  2. Test with multiple handler types
  3. Monitor the hash chain during development
  4. Use logging for debugging
  5. Validate state transitions