Implement a Debugging Server

Sometimes it is desirable to embed a debugging server inside the application such that an external debugger interface can connect to the application’s running instance at runtime.

This way, when scripts are run within the application, it is easy for an external interface to debug those scripts as they run.

Such connections may take the form of any communication channel, for example a TCP/IP connection, a named pipe, or an MPSC channel.

Example

Server side

The following example assumes bi-direction, blocking messaging channels, such as a WebSocket connection, with a server that accepts connections and creates those channels.

use rhai::debugger::{ASTNode, DebuggerCommand};

let mut engine = Engine::new();

engine.register_debugger(
    // Use the initialization callback to set up the communications channel
    // and listen to it
    |engine, mut debugger| {
        // Create server that will listen to requests
        let mut server = MyCommServer::new();
        server.listen("localhost:8080");

        // Wrap it up in a shared locked cell so it can be 'Clone'
        let server = Rc::new(RefCell::new(server));

        // Store the channel in the debugger state
        debugger.set_state(Dynamic::from(server));
        debugger
    },
    // Trigger the server during each debugger stop point
    |context, event, node, source, pos| {
        // Get the state
        let mut state = context.tag_mut();

        // Get the server
        let mut server = state.write_lock::<MyCommServer>().unwrap();

        // Send the event to the server - blocking call
        server.send_message(...);

        // Receive command - blocking call
        match server.receive_message() {
            None => DebuggerCommand::StepOver,
            // Decode command
            Ok(...) => { ... }
            Ok(...) => { ... }
            Ok(...) => { ... }
            Ok(...) => { ... }
            Ok(...) => { ... }
                :
                :
        }
    }
);

Client side

The client can be any system that can work with WebSockets for messaging.

// Connect to the application's debugger
let webSocket = new WebSocket("wss://localhost:8080");

webSocket.on_message = (event) => {
    let msg = JSON.parse(event.data);

    switch msg.type {
        // handle debugging events from the application...
        case "step": {
                :
        }
                :
                :
    }
};

// Send command to the application
webSocket.send("step-over");