Asterisk Manager (asterisk-manager)
A modern, asynchronous, strongly-typed, and stream-based library for interacting with the Asterisk Manager Interface (AMI) in Rust.
This crate simplifies communication with AMI by handling connection, authentication, sending actions, and consuming events in an idiomatic Rust way, using Tokio and a type system that helps prevent errors at compile time. For production applications, it includes an optional resilient module with heartbeat monitoring, automatic reconnection, and fault-tolerant event streaming.
Table of Contents
- ✨ Features
- 🚀 Getting Started
- 📖 Core Concepts
- 📝 API Documentation with Utoipa
- 🔌 Resilient Connections
- 🔌 Reconnection Strategy
- 🤝 Contributing
- 📜 License
✨ Features
- Strongly-Typed AMI Messages: Actions, Events, and Responses are modeled as Rust
enums andstructs, improving type safety and enabling editor autocompletion. - Intelligent Action Handling: The
send_actionmethod automatically detects actions that return lists of events (e.g.,PJSIPShowEndpoints). It transparently collects all related events and bundles them into a single, aggregatedAmiResponse. - Robust Concurrency: The internal architecture uses dedicated I/O tasks (Reader, Writer, and Dispatcher) to prevent deadlocks, ensuring high performance even when receiving a flood of events while sending actions.
- Stream-Based API: Consume AMI events reactively and efficiently using the
Streamabstraction fromtokio_stream. - Resilient Connections: Optional resilient module with heartbeat monitoring, automatic reconnection, infinite event streams, and configurable buffer sizes for production environments.
- Optional OpenAPI/Swagger Support: Includes a
docsfeature flag to enableutoipa::ToSchemaimplementations on all public types, allowing for automatic and accurate API documentation generation. - Detailed Error Handling: A comprehensive
AmiErrorenum allows robust handling of different failure scenarios.
🚀 Getting Started
1. Installation
Add asterisk-manager to your Cargo.toml.
[]
= "2.1.0" # Or the latest version
= { = "1", = ["full"] }
= "0.1"
To enable automatic API documentation support for frameworks like Actix-web or Axum, enable the docs feature:
[]
= { = "2.1.0", = ["docs"] }
2. Usage Example
This example connects to AMI, sends a simple action (Ping), and then sends a list-based action (PJSIPShowEndpoints), demonstrating how send_action handles both transparently.
use ;
use StreamExt;
use HashMap;
async
📖 Core Concepts
The Manager
The Manager struct is the main entry point. You first create an empty Manager with Manager::new() and then establish a connection with manager.connect_and_login(options).await. This method starts the internal, non-blocking I/O tasks. Manager is Clone, Send, and Sync, allowing it to be safely shared between multiple tasks.
Sending Actions
Use the manager.send_action() method. It intelligently handles different types of responses:
- For simple actions like
Ping, it returns the direct response immediately. - For actions that return a list (e.g.,
PJSIPShowEndpoints), it automatically collects all related events, bundles them into aCollectedEventsfield in the finalAmiResponse, and returns after the list is complete.
Consuming Events
The library uses a broadcast channel to fan-out events. To consume them, obtain a stream with manager.all_events_stream().await. This allows multiple parts of your application to independently listen to the same AMI events.
let mut stream = manager.all_events_stream.await;
while let Some = stream.next.await
📝 API Documentation with Utoipa
This library provides optional support for utoipa to automatically generate OpenAPI (Swagger) schemas for your web application.
This feature is available starting from version 2.0.0.
To enable it, add the docs feature in your Cargo.toml:
= { = "2.1.0", = ["docs"] }
With this feature enabled, all public types like AmiResponse and AmiEvent will derive utoipa::ToSchema. You can then reference them directly in your Actix-web or Axum controller documentation.
// In your application's controller
use AmiResponse;
use OpenApi;
;
🔌 Resilient Connections
For production applications that require high availability and fault tolerance, the library provides a resilient module with automatic reconnection, heartbeat monitoring, and infinite event streams.
Features
- Automatic Reconnection: Automatically reconnects when the connection is lost
- Heartbeat Monitoring: Configurable ping intervals to detect connection issues
- Infinite Event Streams: Never-ending event streams that handle reconnection transparently
- Configurable Buffer Sizes: Optimize memory usage for high-throughput applications
- Watchdog Functionality: Monitors authentication status and triggers reconnection
Configuration notes:
heartbeat_interval(seconds): controls how often a heartbeatPingis sent when using theresilientmodule. Lower values mean faster failure detection but more AMI traffic.max_retries: number of immediate reconnection attempts before adding 5-second delays in cycles. The logic works in cycles: firstmax_retriesattempts are immediate, then one attempt with a 5-second delay, then the cycle repeats. Tune this depending on how aggressive you want reconnection attempts to be.metrics: optionalResilientMetricsinstance for collecting reconnection statistics (attempts, successes, failures, timing). Set toSome(ResilientMetrics::new())to enable metrics collection.
Example Usage
use ;
use ManagerOptions;
use StreamExt;
async
🔌 Reconnection Strategy
Traditional Approach
The core library does not include built-in automatic reconnection logic by design. The philosophy is to provide robust building blocks so you can implement the reconnection strategy that best fits your application (e.g., fixed delays, exponential backoff, fixed number of attempts, etc.).
When the connection is lost, methods like send_action will return an AmiError::ConnectionClosed, and the event stream will end. Your application should handle these signals by creating a new Manager instance and calling connect_and_login again.
Resilient Approach
For applications that need automatic reconnection without manual implementation, use the resilient module described in the previous section. This provides production-ready reconnection logic with heartbeat monitoring and automatic retry mechanisms.
For complete examples of both approaches, see:
- Traditional:
examples/actix_web_example.rs- Manual reconnection handling - Resilient:
examples/actix_web_resilient_example.rs- Automatic reconnection
🤝 Contributing
Contributions are very welcome! If you find a bug, have a suggestion for improvement, or want to add support for more actions and events, feel free to open an Issue or a Pull Request.
📜 License
This project is licensed under the MIT License.
⭐ Acknowledgements
This work was inspired by the simplicity and effectiveness of the following libraries:
- NodeJS-AsteriskManager
- node-asterisk
- Thanks to all contributors and the Rust community.