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

FastAGI Server

Binding

The server binds a TCP listener and dispatches each connection to your handler. Asterisk connects via the AGI() dialplan application:

exten => 100,1,AGI(agi://your-server:4573)

Handler Trait

pub trait AgiHandler: Send + Sync + 'static {
    fn handle(&self, request: AgiRequest, channel: AgiChannel)
        -> impl Future<Output = Result<()>> + Send;
}

The handler receives the AGI request (parsed environment variables from Asterisk) and a channel for sending commands back.

Request Environment

AgiRequest contains the agi_* variables sent by Asterisk at connection start: channel name, caller ID, called extension, context, language, etc.

Channel Commands

AgiChannel provides typed async methods for every AGI command: answer, hangup, stream_file, get_data, say_digits, record_file, database_get, speech_create, and more. See Reference.

Concurrency

Limit concurrent connections with max_connections:

let (server, _shutdown) = AgiServer::builder()
    .bind("0.0.0.0:4573")
    .handler(MyHandler)
    .max_connections(50)
    .build()
    .await?;

Graceful Shutdown

build() returns a ShutdownHandle that stops the accept loop:

let (server, shutdown) = AgiServer::builder()
    .bind("0.0.0.0:4573")
    .handler(MyHandler)
    .build()
    .await?;

// stop accepting after ctrl-c
tokio::spawn(async move {
    tokio::signal::ctrl_c().await.ok();
    shutdown.shutdown();
});

server.run().await?;