view release on metacpan or search on metacpan
0.2.4 - Due to a bug introduced in 0.2.3 get_event would return a reference to the current Asterisk::AMI object instead of the event.
0.2.3 - The Carp module is now required.
- Switched certain warnings to now use carp where appropriate.
- We now honor the 'use warnings' pragma and only present warnings when it is enabled. To disable all warnings
specific to this module you can use 'no warnings qw(Asterisk::AMI)'.
- Deprecated the use of the CALLBACK and TIMEOUT keys for setting timeouts and callbacks for actions sent with
send_action. A warning is emitted if they are used. Please use the new syntax introduced in version version 0.2.0.
This was done to minimize potential hash key collisions with actual manager command options.
- Allow passing of a perl variable to an action callback via a new argument for the send_action() method.
This can be used to pass along additional information to the callback. See the documentation for more details.
- Internal changes to how the constructor works, mostly pertaining to better option validation and making it
more flexible. Obvious errors should now be caught earlier (e.g. not using a subroutine refernce for an error
or event handler).
- General refactoring for a some internal methods for the sake of maintainability
- Updated cmd_server.pl to use new syntax and variable passing
0.2.2 - Added a call to AE::now_update in blocking methods to force the time for the event loop to update. Fixes an
issue where if sleep was called for a period before a blocking call after connecting that the resulting
blocking call would return a timeout (rt #61148).
0.2.1 - Fixed some errors in the documentation
- Fixed a bug where we would leave an empty value in callbacks on a get_response if the response was already in the
buffer. Only error message for this happend once the Asterisk::AMI object went away and attempted to flush all
pending callbacks.
- Require AnyEvent 5.2 or newer, as a feature we rely on was introduced in that release. Note, I have only tested
as far back as version 5.26.
0.2.0 - Added new syntax for using callbacks with the send_action method. Old syntax still works.
Check documentation for this method for more details.
- Changed method of parsing from a regex to a simple split. This was possible due to previous
changes in the order that we parsed input. Results are more accurate parsing and better performance.
- Removed the need for the 'DATA' key due to above parsing improvements. All input now creates a key
in the appropriate hash.
- Manager lines with empty values ( e.g. 'Account: ' in an event) are no longer placed
in 'DATA' and are instead parsed properly and contain the null string as a value ( test for '' ).
0.1.8 - Added support for 'MD5' challenge authenticaiton
- Added SSL support
- Internal changes to how we keep track of active actions
- Fixed some bad grammar/spelling/typos in documentation,
most likely added a few more as well
0.1.7 - Removed Asterisk::AMI::completed(). Seemed pointless with callbacks.
- Added TCP_Keepalive option, enables socket level TCP keepalive for detecting dead connections.
- Fixed possible undefined value for timeout when sending a keepalive.
- We were being a bit overzealous when we encounted an error on the socket (during connect or otherwise).
We now callback any outstanding actions (as if they had timed out) before we issue the on_error callbacks
and do internal cleanup. This bug was causing the hang during login if a socket connection could not
be made.
- Fixed a bug with older version of ExtUtils::MakeMaker
- Fix to properly us \v when perl >=5.10, we were only doing it when perl >5.10. This only affects performance.
- 'Keepalive' was not being set if Blocking was set to 1. Now 'Keepalive' is always set if configured,
it just may not be helpful if you are not running an event loop.
- Removed number of 'useless' functions. You should check the documentation.
- Fixed a memory 'leak' (total consumtion was still capped by our ring buffer) that could happen when many responses were timeing out.
Essentially we were still buffering the subsequent packets even if they action had already timed out. Now we properly discard them.
- AMI::get_action is now AMI::get_response. Behavior is the same, only the name has changed.
- Re-wrote event_proxy.pl example to utilize the new integration with AnyEvent.
- New example server called 'cmd_server.pl' which allows for a few basic commands. It demonstrates the use of callbacks.
0.1.3 - Changed version requirements from 5.10 to 5.8. Those running 5.8 may need to install the 'version' and 'parent'
pragmas. (install version and install parent in cpan).
- Now using "\015\012" as the end of line delimiter, more portable and better practice than "\r\n"
- AMI::Common::channels() was not accepting timeouts
- Changed AMI::Common::channels() to use the status command, which has changed the information it returns (more is better).
- New key {'GOOD'} added to the Response Obj. It is 1 when an object is complete and had no errors and 0 if it
had an error or never finished. Should make it very easy to check if a response is usuable.
- AMI::check_response() now also removes the action from the buffer
- We were not properly returning undef on error for several AMI::Common functions. These should now properly
return undef if the action failed.
- Added Callbacks on for Actions to core AMI, read the documentation for more information.
- New code example 'cmd_server.pl', a simple server, gives examples on how to use callbacks.
- New Module AMI::Common:Dev contains additional functions for working with Asterisk 1.6+
0.1.2 - All AMI Objects can now also be used a normal IO Handles. It is not recommended
that you read and write directly to them. This was added so you can add the AMI
object to something like IO::Select for single threaded server applications
- New module AMI::Common::Dev, which is currently empty. This will be where new functions
specific to Asterisk 1.6+ will go. When the next LTS of Asterisk is released these will then
be merged back into AMI::Common and new functions will be added here.
lib/Asterisk/AMI.pm view on Meta::CPAN
=head2 Warning - Mixing Event-loops and blocking actions
For an intro to Event-Based programming please check out the documentation in AnyEvent::Intro.
If you are running an event loop and use blocking methods (e.g. get_response, check_response, action,
simple_action, connected, or a blocking connect) the outcome is unspecified. It may work, it may lock everything up, the action may
work but break something else. I have tested it and behavior seems unpredictable at best and is very
circumstantial.
If you are running an event-loop use non-blocking callbacks! It is why they are there!
However if you do play with blocking methods inside of your loops let me know how it goes.
=head2 Actions
=head3 ActionIDs
This module handles ActionIDs internally and if you supply one in an action it will simply be ignored and overwritten.
=head3 Construction
lib/Asterisk/AMI.pm view on Meta::CPAN
my $response2 = $astman->action({ Action => 'Command',
Command => 'sip show peers'
});
my $response3 = $astman->action({ Action => 'Command',
Command => 'sip show peers'
});
=head3 Originate Examples
These don't include non-blocking examples, please read the section on 'Callbacks' below for information
on using non-blocking callbacks and events.
NOTE: Please read about the 'OriginateHack' option for the constructor above if you plan on using the 'Async'
option in your Originate command, as it may be required to properly retrieve the response.
In these examples we are dialing extension '12345' at a sip peer named 'peer' and when the call connects
we drop the channel into 'some_context' at priority 1 for extension 100.
Example 1 - A simple non-ASYNC Originate
my $response = $astman->action({Action => 'Originate',
lib/Asterisk/AMI.pm view on Meta::CPAN
Or
$astman->send_action({ Action => 'Ping' }, sub { return }, 7);
=head3 Callback Caveats
Callbacks only work if we are processing packets, therefore you must be running an event loop. Alternatively, we run
mini-event loops for our blocking calls (e.g. action(), get_action()), so in theory if you set callbacks and then
issue a blocking call those callbacks should also get triggered. However this is an unsupported scenario.
Timeouts are done using timers and they are set as soon as you send the object. Therefore if you send an action with a
timeout and then monkey around for a long time before getting back to your event loop (to process input) you can time
out before ever even attempting to receive the response.
A very contrived example:
$astman->send_action({ Action => 'Ping' }, \&somemethod, 3);
sleep(4);
lib/Asterisk/AMI.pm view on Meta::CPAN
waiting for a response.
Returns 1 if the connection is good, 0 if it is not.
error ()
Returns 1 if there are currently errors on the socket, 0 if everything is ok.
destroy ()
Destroys the contents of all buffers and removes any current callbacks that are set.
Mostly used internally. Useful if you want to ensure that our IO handle watcher gets removed.
Gets called automatically when our object goes out of scope.
loop ()
Starts an event loop via AnyEvent.
break ()
Breaks/exits the current event loop. The program will continue from where the event loop was invoked.
lib/Asterisk/AMI.pm view on Meta::CPAN
}
#Handles connection failures (includes login failure);
sub _on_connect_err {
my ($self, $message) = @_;
warnings::warnif('Asterisk::AMI', "Failed to connect to asterisk - $self->{CONFIG}->{PEERADDR}:$self->{CONFIG}->{PEERPORT}");
warnings::warnif('Asterisk::AMI', "Error Message: $message");
#Dispatch all callbacks as if they timed out
$self->_clear_cbs();
if (exists $self->{CONFIG}->{ON_CONNECT_ERR}) {
$self->{CONFIG}->{ON_CONNECT_ERR}->($self, $message);
} elsif (exists $self->{CONFIG}->{ON_ERROR}) {
$self->{CONFIG}->{ON_ERROR}->($self, $message);
}
$self->{SOCKERR} = 1;
lib/Asterisk/AMI.pm view on Meta::CPAN
}
#Handles the remote end disconnecting
sub _on_disconnect {
my ($self) = @_;
my $message = "Remote end disconnected - $self->{CONFIG}->{PEERADDR}:$self->{CONFIG}->{PEERPORT}";
warnings::warnif('Asterisk::AMI', "Remote Asterisk Server ended connection - $self->{CONFIG}->{PEERADDR}:$self->{CONFIG}->{PEERPORT}");
#Call all callbacks as if they had timed out
_
$self->_clear_cbs();
if (exists $self->{CONFIG}->{ON_DISCONNECT}) {
$self->{CONFIG}->{ON_DISCONNECT}->($self, $message);
} elsif (exists $self->{CONFIG}->{ON_ERROR}) {
$self->{CONFIG}->{ON_ERROR}->($self, $message);
}
$self->{SOCKERR} = 1;
lib/Asterisk/AMI.pm view on Meta::CPAN
$self->_handle_action(\%parsed);
} elsif (exists $parsed{'Event'}) {
$self->_handle_event(\%parsed);
}
}
return 1;
}
#Used once and action completes
#Determines goodness and performs any oustanding callbacks
sub _action_complete {
my ($self, $actionid) = @_;
#Determine 'Goodness'
if (defined $self->{RESPONSEBUFFER}->{$actionid}->{'Response'}
&& $self->{RESPONSEBUFFER}->{$actionid}->{'Response'} =~ /^(?:Success|Follows|Goodbye|Events Off|Pong)$/ox) {
$self->{RESPONSEBUFFER}->{$actionid}->{'GOOD'} = 1;
}
#Do callback and cleanup if callback exists
lib/Asterisk/AMI.pm view on Meta::CPAN
#Delete Originate Async bullshit
delete $response->{'ASYNC'};
$callback->($self, $response, $store);
}
return 1;
}
#Handles proccessing and callbacks for action responses
sub _handle_action {
my ($self, $packet) = @_;
#Snag our actionid
my $actionid = $packet->{'ActionID'};
#Discard Unknown ActionIDs
return unless ($self->{EXPECTED}->{$actionid});
#Event responses
lib/Asterisk/AMI.pm view on Meta::CPAN
#This aciton is finished do not accept any more packets for it
delete $self->{EXPECTED}->{$actionid};
#Determine goodness, do callback
$self->_action_complete($actionid);
}
return 1;
}
#Handles proccessing and callbacks for 'Event' packets
sub _handle_event {
my ($self, $event) = @_;
#If handlers were configured just dispatch, don't buffer
if ($self->{CONFIG}->{HANDLERS}) {
if (exists $self->{CONFIG}->{HANDLERS}->{$event->{'Event'}}) {
$self->{CONFIG}->{HANDLERS}->{$event->{'Event'}}->($self, $event);
} elsif (exists $self->{CONFIG}->{HANDLERS}->{'default'}) {
$self->{CONFIG}->{HANDLERS}->{'default'}->($self, $event);
}
lib/Asterisk/AMI.pm view on Meta::CPAN
delete $self->{CALLBACKS}->{'EVENT'};
#Save for later
} else {
push(@{$self->{EVENTBUFFER}}, $event);
}
}
return 1;
}
#This is used to provide blocking behavior for calls It installs callbacks for an action if it is not in the buffer
#and waits for the response before returning it.
sub _wait_response {
my ($self, $id, $timeout) = @_;
#Already got it?
if ($self->{RESPONSEBUFFER}->{$id}->{'COMPLETED'}) {
my $resp = $self->{RESPONSEBUFFER}->{$id};
delete $self->{RESPONSEBUFFER}->{$id};
delete $self->{CALLBACKS}->{$id};
delete $self->{EXPECTED}->{$id};
lib/Asterisk/AMI.pm view on Meta::CPAN
my ($self, $action, $challenge, $timeout) = @_;
#Weaken ref for use in anonsub
weaken($self);
#Callback for login action
my $login_cb = sub { $self->_logged_in($_[1]) };
#Do a md5 challenge
if (%{$challenge}) {
#Create callbacks for the challenge
my $challenge_cb = sub {
if ($_[1]->{'GOOD'}) {
my $md5 = Digest::MD5->new();
$md5->add($_[1]->{'PARSED'}->{'Challenge'});
$md5->add($self->{CONFIG}->{SECRET});
$md5 = $md5->hexdigest;
$action->{'Key'} = $md5;
lib/Asterisk/AMI.pm view on Meta::CPAN
unless ($_[1]->{'GOOD'}) {
$self->_on_timeout("Asterisk failed to respond to keepalive - $self->{CONFIG}->{PEERADDR}:$self->{CONFIG}->{PEERPORT}");
};
};
my $timeout = $self->{CONFIG}->{TIMEOUT} || 5;
return $self->send_action({ Action => 'Ping' }, $cb, $timeout);
}
#Calls all callbacks as if they had timed out Used when an error has occured on the socket
sub _clear_cbs {
my ($self) = @_;
foreach my $id (keys %{$self->{CALLBACKS}}) {
my $response = $self->{RESPONSEBUFFER}->{$id};
my $callback = $self->{CALLBACKS}->{$id}->{'cb'};
my $store = $self->{CALLBACKS}->{$id}->{'store'};
delete $self->{RESPONSEBUFFER}->{$id};
delete $self->{CALLBACKS}->{$id};
delete $self->{EXPECTED}->{$id};