Actix

To get a taste of Interact as applied to actual servers, you can try the Interact-enabled Actix chat demo (originally from here).

While the state of an Actix program is spread across a stack of Futures that may exist in multiple process thread, Interact has no difficulty in traversing it and presenting a whole picture of the server.

Summary of changes

To enable this example, there were two changes:

  • Changes in Actix core (Github link), that enable Interact for the Addr<T> Actor messaging proxy.
  • Changes to Actix chat app (Github link), which add #[derive(Interact)] for its types, and invocation of the Interact prompt.

Demo

git clone https://github.com/interact-rs/actix
cd actix/examples/chat
cargo run --bin server

Executing the server presents a prompt in a dedicated Interact thread, while the server functionality runs in the process's background:

Running chat server on 127.0.0.1:12345
Rust `interact`, type '?' for more information
>>>

You can examine the server state:

>>> server
ChatServer { sessions: HashMap {}, rooms: HashMap { "Main": HashSet {} } }

In parallel, run two clients using cargo run --bin client, and re-examine the server's state:

>>> server
[#1] ChatServer {
    sessions: HashMap {
        8426954607288880898: ChatSession { id: 8426954607288880898,
            addr: [#1], hb: 374.307146ms, room: "Main" },
        9536033526192464616: ChatSession { id: 9536033526192464616,
            addr: [#1], hb: 513.580812ms, room: "Main" }
    },
    rooms: HashMap { "Main": HashSet { 8426954607288880898, 9536033526192464616 } }
}

The reason for #[1] is the loop that is detected by traversal of ChatSession's addr, which loops back into ChatServer.

You can use Interact to print only field of rooms:

>>> server.rooms
HashMap { "Main": HashSet { 8426954607288880898, 9536033526192464616 } }

Or access one of the sessions:

>>> server.sessions[8426954607288880898]
[#1] ChatSession {
    id: 8426954607288880898,
    addr: [#2] ChatServer {
        sessions: HashMap {
            8426954607288880898: [#1],
            9536033526192464616: ChatSession { id: 9536033526192464616,
                 addr: [#2], hb: 759.986694ms, room: "Main" }
        },
        rooms: HashMap { "Main": HashSet { 8426954607288880898, 9536033526192464616 } }
    },
    hb: 632.849822ms,
    room: "Main"
}

See the 'hb' field get updated:

>>> server.sessions[8426954607288880898].hb
716.16972ms
>>> server.sessions[8426954607288880898].hb
10.398845ms

Modify the room's name:

>>> server.sessions[8426954607288880898].room = "Boo"

See that it was indeed modified:

>>> server.sessions[8426954607288880898]
[#1] ChatSession {
    id: 8426954607288880898,
    addr: [#2] ChatServer {
        sessions: HashMap {
            8426954607288880898: [#1],
            9536033526192464616: ChatSession { id: 9536033526192464616,
                addr: [#2], hb: 219.435076ms, room: "Main" }
        },
        rooms: HashMap { "Main": HashSet { 8426954607288880898, 9536033526192464616 } }
    },
    hb: 112.667608ms,
    room: "Boo"
}