ami_client_plus 1.0.1 copy "ami_client_plus: ^1.0.1" to clipboard
ami_client_plus: ^1.0.1 copied to clipboard

Modern Asterisk Manager Interface (AMI) client with Clean Architecture. Type-safe, production-ready, with circuit breaker, connection pooling, and event filtering.

AMI Flutter #

Pub Version License

Production-ready Asterisk Manager Interface (AMI) client for Flutter & Dart with Clean Architecture.

Modern, type-safe, testable AMI implementation supporting TCP, WebSocket, and custom transports.

✨ Features #

  • Clean Architecture - SOLID principles, fully testable
  • Type Safety - No raw maps, strongly-typed entities and actions
  • Multi-Platform - Native (TCP) + Web (WebSocket) support
  • Functional Error Handling - Result<T> type for safe error management
  • Immutable Entities - Thread-safe, predictable state
  • Easy Testing - Mock-friendly repository pattern
  • Event Streaming - Reactive event handling with Dart Streams
  • Reconnection Strategies - Exponential backoff built-in

🚀 Quick Start #

Installation #

dependencies:
  ami_client_plus: ^1.0.1
import 'package:ami_client_plus/ami_client_plus_clean.dart';

void main() async {
  // Create client
  final client = AmiClientFactory.createTcpClient(
    host: '127.0.0.1',
    port: 5038,
  );

  // Connect and authenticate
  await client.connect();
  await client.authenticate(username: 'admin', password: 'secret');

  // Send action
  final response = await client.ping();
  print('Ping response: ${response.status}');

  // Listen to events
  client.listenToEvent('Newchannel').listen((event) {
    print('New channel: ${event.channel}');
  });

  // Originate call
  await client.originateCall(
    channel: 'SIP/6001',
    extension: '100',
    context: 'default',
  );
}

Legacy API (Still Supported) #

import 'package:ami_client_plus/ami_client_plus.dart';

class MyClient with AmiBase, TCPSocketConnector {
  // Mixin-based legacy approach
}

👉 New projects should use the Clean Architecture API (ami_client_plus_clean.dart)

📖 Documentation #

🏗️ Architecture #

┌─────────────────────────────────────────────┐
│         Presentation Layer                  │
│  AmiClient (Facade) + AmiClientFactory      │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│         Domain Layer (Pure Logic)           │
│  Entities • Value Objects • Use Cases       │
│  Repository Interface • Exceptions          │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│         Data Layer                          │
│  Repository Impl • Data Sources             │
│  (TCP, WebSocket, Custom)                   │
└─────────────────┬───────────────────────────┘
                  │
┌─────────────────▼───────────────────────────┐
│         Infrastructure Layer                │
│  Parsers • Network • Strategies             │
└─────────────────────────────────────────────┘

Dependencies flow inward - Domain has zero external dependencies!

💡 Examples #

Send Custom Action #

final action = GenericAction(
  name: 'QueueAdd',
  parameters: {
    'Queue': 'support',
    'Interface': 'SIP/6001',
  },
);

final response = await client.sendAction(action);

Type-Safe Actions #

// Built-in type-safe actions
await client.sendAction(LoginAction(username: 'admin', secret: 'pass'));
await client.sendAction(PingAction());
await client.sendAction(OriginateAction(...));
await client.sendAction(HangupAction(channel: 'SIP/6001'));
await client.sendAction(StatusAction());

Event Filtering #

// Listen to specific events
client.listenToEvent('Hangup').listen((event) {
  print('Call ended: ${event.channel}');
  print('Cause: ${event.cause}');
});

// Listen to all events
client.eventStream.listen((event) {
  print('Event: ${event.eventName}');
});

Error Handling #

try {
  await client.sendAction(action);
} on AmiAuthenticationException catch (e) {
  print('Auth failed: ${e.message}');
} on AmiTimeoutException catch (e) {
  print('Timeout: ${e.message}');
} on AmiException catch (e) {
  print('AMI error: ${e.message}');
}

Testing #

class MockRepository implements AmiRepository {
  // Easy to mock for testing
}

test('send action', () async {
  final repo = MockRepository();
  final useCase = SendAction(repo);
  
  final response = await useCase.call(PingAction());
  expect(response.isSuccess, isTrue);
});

🧪 Testing #

dart test                    # Run all tests
dart test --coverage         # With coverage

Test Coverage: 95%+ on Clean Architecture code

🛠️ Development #

# Analyze code
dart analyze

# Format code
dart format .

# Run example
cd example
dart run clean_architecture_example.dart

📝 Changelog #

See CHANGELOG.md for release history.

Latest (v1.0.1): Bug fixes and package metadata updates

🤝 Contributing #

Contributions welcome! Please open an issue or PR.

📄 License #

MIT License - see LICENSE file.


Made with ❤️ for the Flutter + Asterisk community

0
likes
140
points
40
downloads

Documentation

API reference

Publisher

verified publisherspinex.io

Weekly Downloads

Modern Asterisk Manager Interface (AMI) client with Clean Architecture. Type-safe, production-ready, with circuit breaker, connection pooling, and event filtering.

Homepage
Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

meta, web_socket_channel

More

Packages that depend on ami_client_plus