forked from Mirrors/freeswitch
Initial checkin of the POE::Filter::FSSocket module and fsconsole.pl which is a curses, multi-window console for freeswitch mod_event_socket. See http://search.cpan.org/~ptinsley/POE-Filter-FSSocket-0.04/lib/POE/Filter/FSSocket.pm for more info on the perl module.
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3116 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
3a32d9e53c
commit
bb5b51dfbe
50
scripts/POE-Filter-FSSocket/CHANGES
Normal file
50
scripts/POE-Filter-FSSocket/CHANGES
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
=========================
|
||||||
|
2006-10-14 00:08:00 v0_05
|
||||||
|
=========================
|
||||||
|
|
||||||
|
2006-10-14 00:08:00 (r5) by ptinsley
|
||||||
|
|
||||||
|
Added some "bullet proofing" in the module to handle bad/unknown input
|
||||||
|
Updated the curses example (fsconsole.pl)
|
||||||
|
Added debug and strict parsing as part of the bullet proofing
|
||||||
|
to enable debug add debug => 1 in your new() and if you want the module
|
||||||
|
to croak when it doesn't properly parse something use strict => 1 in the
|
||||||
|
new(). Example Poe::Filter::FSSocket->new(debug => 1, strict => 1)
|
||||||
|
The default for debug and strict is 0
|
||||||
|
|
||||||
|
=========================
|
||||||
|
2006-10-14 00:08:00 v0_04
|
||||||
|
=========================
|
||||||
|
|
||||||
|
2006-10-14 00:08:00 (r4) by ptinsley
|
||||||
|
|
||||||
|
Fixed support for log/data
|
||||||
|
Added an example that is a quick curses console for freeswitch
|
||||||
|
|
||||||
|
=========================
|
||||||
|
2006-09-18 21:08:00 v0_03
|
||||||
|
=========================
|
||||||
|
|
||||||
|
2006-09-18 21:08:00 (r3) by ptinsley
|
||||||
|
|
||||||
|
Added support for log/data
|
||||||
|
|
||||||
|
=========================
|
||||||
|
2006-09-17 23:57:00 v0_02
|
||||||
|
=========================
|
||||||
|
|
||||||
|
2006-09-17 23:57:00 (r2) by ptinsley
|
||||||
|
|
||||||
|
Added support for api/response type, data ends up in api-response variable.
|
||||||
|
|
||||||
|
=========================
|
||||||
|
2006-09-17 22:19:20 v0_01
|
||||||
|
=========================
|
||||||
|
|
||||||
|
2006-09-17 22:19:20 (r1) by ptinsley
|
||||||
|
|
||||||
|
Initial package of the module.
|
||||||
|
|
||||||
|
==============
|
||||||
|
End of Excerpt
|
||||||
|
==============
|
4
scripts/POE-Filter-FSSocket/INSTALL
Normal file
4
scripts/POE-Filter-FSSocket/INSTALL
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
perl Makefile.PL
|
||||||
|
make
|
||||||
|
make test
|
||||||
|
make install
|
18
scripts/POE-Filter-FSSocket/LICENSE
Normal file
18
scripts/POE-Filter-FSSocket/LICENSE
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
The contents of this file are subject to the Mozilla Public License
|
||||||
|
Version 1.1 (the "License"); you may not use this file except in
|
||||||
|
compliance with the License. You may obtain a copy of the License at
|
||||||
|
http://www.mozilla.org/MPL/
|
||||||
|
|
||||||
|
Software distributed under the License is distributed on an "AS IS"
|
||||||
|
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing rights and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
The Original Code is POE::Filter::FSSocket.
|
||||||
|
|
||||||
|
The Initial Developer of the Original Code is Paul Tinsley <pdt@jackhammer.org>.
|
||||||
|
Portions created by the Initial Developer are Copyright (C) 2006
|
||||||
|
the Initial Developer. All Rights Reserved.
|
||||||
|
|
||||||
|
Contributor(s):
|
||||||
|
Paul Tinsley <pdt@jackhammer.org>
|
22
scripts/POE-Filter-FSSocket/Makefile.PL
Normal file
22
scripts/POE-Filter-FSSocket/Makefile.PL
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use ExtUtils::MakeMaker;
|
||||||
|
|
||||||
|
WriteMakefile(
|
||||||
|
NAME => 'POE::Filter::FSSocket',
|
||||||
|
AUTHOR => 'Paul Tinsley <pdt@jackhammer.org>',
|
||||||
|
ABSTRACT => 'POE filter for getting events out of FreeSWITCH',
|
||||||
|
VERSION_FROM => 'lib/POE/Filter/FSSocket.pm',
|
||||||
|
|
||||||
|
PM => { 'lib/POE/Filter/FSSocket.pm' => '$(INST_LIBDIR)/FSSocket.pm' },
|
||||||
|
PREREQ_PM => {
|
||||||
|
POE => 0.3101,
|
||||||
|
Test::More => 0,
|
||||||
|
POE::Component::Client::TCP => 0,
|
||||||
|
POE::Filter::Line => 0,
|
||||||
|
},
|
||||||
|
dist => {
|
||||||
|
COMPRESS => 'gzip -9f',
|
||||||
|
SUFFIX => 'gz',
|
||||||
|
},
|
||||||
|
);
|
3
scripts/POE-Filter-FSSocket/README
Normal file
3
scripts/POE-Filter-FSSocket/README
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
A POE filter for FreeSWITCH (http://www.freeswitch.org) that parses event/log/etc... messages for you. You must ask for events in plain mode.
|
||||||
|
|
||||||
|
perldoc POE::Filter::FSSocket for more info and an example.
|
5
scripts/POE-Filter-FSSocket/TODO
Normal file
5
scripts/POE-Filter-FSSocket/TODO
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
- Support bgapi output
|
||||||
|
- more example scripts
|
||||||
|
- more documentation
|
||||||
|
- sister component that uses this filter
|
||||||
|
- reconnect handling
|
361
scripts/POE-Filter-FSSocket/examples/fsconsole.pl
Normal file
361
scripts/POE-Filter-FSSocket/examples/fsconsole.pl
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
sub POE::Kernel::ASSERT_DEFAULT () { 1 };
|
||||||
|
sub Term::Visual::DEBUG () { 1 }
|
||||||
|
sub Term::Visual::DEBUG_FILE () { 'test.log' }
|
||||||
|
use IO::Socket;
|
||||||
|
use POE qw/Filter::FSSocket Component::Client::TCP/;
|
||||||
|
use Data::Dumper;
|
||||||
|
use Term::Visual;
|
||||||
|
|
||||||
|
|
||||||
|
local *D;
|
||||||
|
if (Term::Visual::DEBUG) {
|
||||||
|
*D = *Term::Visual::ERRS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local *ERROR = *STDERR;
|
||||||
|
|
||||||
|
|
||||||
|
$SIG{__DIE__} = sub {
|
||||||
|
if (Term::Visual::DEBUG) {
|
||||||
|
print Term::Visual::ERRS "Died: @_\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## BEGIN Globals ##############################################################
|
||||||
|
###############################################################################
|
||||||
|
our $server_address = "127.0.0.1";
|
||||||
|
our $server_port = "8021";
|
||||||
|
our $server_secret = "ClueCon";
|
||||||
|
|
||||||
|
#this is where you can customize the color scheme
|
||||||
|
our %Pallet = (
|
||||||
|
'warn_bullet' => 'bold yellow',
|
||||||
|
'err_bullet' => 'bold red',
|
||||||
|
'out_bullet' => 'bold green',
|
||||||
|
'access' => 'bright red on blue',
|
||||||
|
'current' => 'bright yellow on blue',
|
||||||
|
);
|
||||||
|
|
||||||
|
our $terminal;
|
||||||
|
my %sockets;
|
||||||
|
my %windows;
|
||||||
|
my %unread_count;
|
||||||
|
my %commands = (
|
||||||
|
'window' => 1,
|
||||||
|
'w' => 1,
|
||||||
|
'win' => 1,
|
||||||
|
);
|
||||||
|
###############################################################################
|
||||||
|
## END Globals ##############################################################
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
#setup our session
|
||||||
|
POE::Session->create(
|
||||||
|
'inline_states' => {
|
||||||
|
'_start' => \&handle_start, #session start
|
||||||
|
'_stop' => \&handle_stop, #session stop
|
||||||
|
'curses_input' => \&handle_curses_input, #input from the keyboard
|
||||||
|
'update_time' => \&handle_update_time, #update the status line clock
|
||||||
|
'quit' => \&handle_quit, #handler to do any cleanup
|
||||||
|
'server_input' => \&handle_server_input,
|
||||||
|
'_default' => \&handle_default,
|
||||||
|
},
|
||||||
|
'heap' => {
|
||||||
|
'terminal' => undef,
|
||||||
|
'freeswitch' => undef,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
#start the kernel a chugging along
|
||||||
|
$poe_kernel->run;
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## BEGIN Handlers #############################################################
|
||||||
|
###############################################################################
|
||||||
|
#handles any startup functions for our session
|
||||||
|
sub handle_default {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_start {
|
||||||
|
my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
|
||||||
|
|
||||||
|
#setup our terminal
|
||||||
|
$heap->{'terminal'} = Term::Visual->new(
|
||||||
|
'Alias' => 'terminal', #poe alias for this
|
||||||
|
'History_Size' => 300, #number of things to keep in history
|
||||||
|
'Common_Input' => 1, #all windows share input and history
|
||||||
|
'Tab_Complete' => \&tab_complete,
|
||||||
|
);
|
||||||
|
|
||||||
|
$terminal = $heap->{'terminal'};
|
||||||
|
|
||||||
|
#setup the color palette
|
||||||
|
$terminal->set_palette(%Pallet);
|
||||||
|
|
||||||
|
#create a base window
|
||||||
|
my $window_id = $terminal->create_window(
|
||||||
|
'Window_Name' => 'console',
|
||||||
|
'Buffer_Size' => 3000,
|
||||||
|
'Title' => 'FreeSWITCH Console',
|
||||||
|
'Status' => {
|
||||||
|
'0' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['time'],
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['window_status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$windows{'console'} = $window_id;
|
||||||
|
|
||||||
|
$window_id = $terminal->create_window(
|
||||||
|
'Window_Name' => 'log',
|
||||||
|
'Buffer_Size' => 3000,
|
||||||
|
'Title' => 'FreeSWITCH Logs',
|
||||||
|
'Status' => {
|
||||||
|
'0' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['time'],
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['window_status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$windows{'log'} = $window_id;
|
||||||
|
|
||||||
|
$window_id = $terminal->create_window(
|
||||||
|
'Window_Name' => 'event',
|
||||||
|
'Buffer_Size' => 3000,
|
||||||
|
'Title' => 'FreeSWITCH Event',
|
||||||
|
'Status' => {
|
||||||
|
'0' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['time'],
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['window_status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$windows{'event'} = $window_id;
|
||||||
|
|
||||||
|
#tell the terminal what to call when there is input from the keyboard
|
||||||
|
$kernel->post('terminal' => 'send_me_input' => 'curses_input');
|
||||||
|
|
||||||
|
$terminal->change_window(0);
|
||||||
|
$kernel->delay_set('update_time' => 1);
|
||||||
|
$terminal->set_status_field(0, 'time' => scalar(localtime));
|
||||||
|
new_message('destination_window' => 0, 'message' => "
|
||||||
|
Welcome to the FreeSWITCH POE Curses Console!
|
||||||
|
The console is split into three windows:
|
||||||
|
- 'console' for api response messages
|
||||||
|
- 'log' for freeswitch log output (simply send the log level you want
|
||||||
|
to start seeing events eg: 'log all')
|
||||||
|
- 'event' for freeswitch event output (must subscribe in plain format
|
||||||
|
eg: 'event plain all')
|
||||||
|
|
||||||
|
To switch between windows type 'w <windowname' so 'w log' for example.
|
||||||
|
|
||||||
|
Coming soon:
|
||||||
|
- Tab completion
|
||||||
|
- command history
|
||||||
|
- window status in the bar (messages added since last view, etc...)
|
||||||
|
|
||||||
|
Send any bug reports or comments to jackhammer\@gmail.com
|
||||||
|
|
||||||
|
Thanks,
|
||||||
|
Paul\n");
|
||||||
|
|
||||||
|
$terminal->set_status_field($terminal->current_window, 'window_status' => format_window_status());
|
||||||
|
|
||||||
|
#connect to freeswitch
|
||||||
|
$heap->{'freeswitch'} = POE::Component::Client::TCP->new(
|
||||||
|
'RemoteAddress' => $server_address,
|
||||||
|
'RemotePort' => $server_port,
|
||||||
|
'ServerInput' => \&handle_server_input,
|
||||||
|
'Connected' => \&handle_fs_connected,
|
||||||
|
'ServerError' => \&handle_server_error,
|
||||||
|
'Disconnected' => \&handle_server_disconnect,
|
||||||
|
'Domain' => AF_INET,
|
||||||
|
'Filter' => POE::Filter::FSSocket->new(),
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#called when users enter commands in a window
|
||||||
|
sub handle_curses_input {
|
||||||
|
my ($kernel, $heap, $input, $context) = @_[KERNEL, HEAP, ARG0, ARG1];
|
||||||
|
|
||||||
|
#get the id of the window that is responsible for the input
|
||||||
|
my $window = $heap->{'terminal'}->current_window;
|
||||||
|
|
||||||
|
open(ERROR, ">>error.log");
|
||||||
|
|
||||||
|
if($input eq "quit") {
|
||||||
|
$kernel->yield('quit');
|
||||||
|
} elsif ($input =~ /^w\ (.*)$/) {
|
||||||
|
#get the id of the requested window
|
||||||
|
eval {
|
||||||
|
my $window_id = $windows{$1};
|
||||||
|
|
||||||
|
#see if it's real
|
||||||
|
if(defined($window_id)) {
|
||||||
|
$unread_count{$window_id} = 0;
|
||||||
|
$terminal->change_window($window_id);
|
||||||
|
$terminal->set_status_field($window_id, 'window_status' => &format_window_status());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if($@) {
|
||||||
|
print ERROR "put error: $@\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#see if we got connected at some point
|
||||||
|
if(defined($sockets{'localhost'})) {
|
||||||
|
#send the command
|
||||||
|
$sockets{'localhost'}->put($input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_fs_connected {
|
||||||
|
my ($kernel, $heap) = @_[KERNEL, HEAP];
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$sockets{'localhost'} = $heap->{'server'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#this is responsible for doing any cleanup and returning the terminal to the previous
|
||||||
|
#state before we mucked with it
|
||||||
|
sub handle_quit {
|
||||||
|
my ($kernel, $heap) = @_[KERNEL, HEAP];
|
||||||
|
|
||||||
|
#tell curses to clean up it's crap
|
||||||
|
$kernel->post('terminal' => 'shutdown');
|
||||||
|
|
||||||
|
#there is probably a more elegant way, but this works for now
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#data from freeswitch
|
||||||
|
sub handle_server_input {
|
||||||
|
my ($kernel,$heap,$input) = @_[KERNEL,HEAP,ARG0];
|
||||||
|
|
||||||
|
eval {
|
||||||
|
#terminal HATES null
|
||||||
|
if(defined($input->{'__DATA__'})) {
|
||||||
|
$input->{'__DATA__'} =~ s/[\x00]//g;
|
||||||
|
}
|
||||||
|
|
||||||
|
#handle the login
|
||||||
|
if($input->{'Content-Type'} eq "auth/request") {
|
||||||
|
$heap->{'server'}->put("auth $server_secret");
|
||||||
|
} elsif ($input->{'Content-Type'} eq "api/response") {
|
||||||
|
new_message('destination_window' => 0, 'message' => 'Response: ');
|
||||||
|
new_message('destination_window' => 0, 'message' => $input->{'__DATA__'});
|
||||||
|
} elsif ($input->{'Content-Type'} eq "log/data") {
|
||||||
|
new_message('destination_window' => 1, 'message' => $input->{'__DATA__'});
|
||||||
|
} elsif ($input->{'Content-Type'} eq "text/event-plain") {
|
||||||
|
new_message('destination_window' => 2, 'message' => Dumper $input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if($@) {
|
||||||
|
open(ERROR, ">>error.log");
|
||||||
|
print ERROR "died: $@\n";
|
||||||
|
print ERROR Dumper $heap;
|
||||||
|
close(ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_server_error {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_server_disconnect {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub tab_complete {
|
||||||
|
my $left = shift;
|
||||||
|
|
||||||
|
my @return;
|
||||||
|
|
||||||
|
if(defined($commands{$left})) {
|
||||||
|
return [$left . " "];
|
||||||
|
#} elsif () {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_update_time {
|
||||||
|
my ($kernel, $heap) = @_[KERNEL, HEAP];
|
||||||
|
$terminal->set_status_field($terminal->current_window, 'time' => scalar(localtime));
|
||||||
|
$kernel->delay_set('update_time' => 1);
|
||||||
|
}
|
||||||
|
###############################################################################
|
||||||
|
## END Handlers #############################################################
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
sub new_message {
|
||||||
|
my %args = @_;
|
||||||
|
|
||||||
|
my $message = $args{'message'};
|
||||||
|
my $destination_window = $args{'destination_window'};
|
||||||
|
|
||||||
|
my $status_field;
|
||||||
|
|
||||||
|
#see if we are on the window being updated
|
||||||
|
if($terminal->current_window != $destination_window) {
|
||||||
|
#increment the unread count for the window
|
||||||
|
#FIXME, should we count messages or lines?
|
||||||
|
$unread_count{$destination_window}++;
|
||||||
|
|
||||||
|
|
||||||
|
#update the status bar
|
||||||
|
eval {
|
||||||
|
$terminal->set_status_field($terminal->current_window, 'window_status' => &format_window_status());
|
||||||
|
};
|
||||||
|
|
||||||
|
if($@) {
|
||||||
|
print $@;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#deliver the message
|
||||||
|
$terminal->print($destination_window, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub format_window_status {
|
||||||
|
my $status_field;
|
||||||
|
|
||||||
|
#put all the windows in the bar with their current unread count
|
||||||
|
foreach my $window (sort {$windows{$a} <=> $windows{$b}} keys %windows) {
|
||||||
|
#see if we are printing the current window
|
||||||
|
if($terminal->current_window == $windows{$window}) {
|
||||||
|
$status_field .= "[\0(current)$window\0(st_frames)";
|
||||||
|
} else {
|
||||||
|
$status_field .= "[$window";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($unread_count{$windows{$window}}) {
|
||||||
|
$status_field .= " (" . $unread_count{$windows{$window}} . ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
$status_field .= "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status_field;
|
||||||
|
}
|
42
scripts/POE-Filter-FSSocket/examples/poetest.pl
Normal file
42
scripts/POE-Filter-FSSocket/examples/poetest.pl
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use POE qw(Component::Client::TCP Filter::FSSocket);
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
my $auth_sent = 0;
|
||||||
|
my $password = "ClueCon";
|
||||||
|
|
||||||
|
POE::Component::Client::TCP->new(
|
||||||
|
'RemoteAddress' => '127.0.0.1',
|
||||||
|
'RemotePort' => '8021',
|
||||||
|
'ServerInput' => \&handle_server_input,
|
||||||
|
'Filter' => POE::Filter::FSSocket->new(),
|
||||||
|
);
|
||||||
|
|
||||||
|
POE::Kernel->run();
|
||||||
|
exit;
|
||||||
|
|
||||||
|
|
||||||
|
sub handle_server_input {
|
||||||
|
my ($heap,$input) = @_[HEAP,ARG0];
|
||||||
|
|
||||||
|
print Dumper $input;
|
||||||
|
|
||||||
|
|
||||||
|
if($input->{'Content-Type'} eq "auth/request") {
|
||||||
|
$auth_sent = 1;
|
||||||
|
$heap->{'server'}->put("auth $password");
|
||||||
|
} elsif ($input->{'Content-Type'} eq "command/reply") {
|
||||||
|
if($auth_sent == 1) {
|
||||||
|
$auth_sent = -1;
|
||||||
|
|
||||||
|
#do post auth stuff
|
||||||
|
$heap->{'server'}->put("events plain all");
|
||||||
|
$heap->{'server'}->put("log");
|
||||||
|
$heap->{'server'}->put("api show channels");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
343
scripts/POE-Filter-FSSocket/lib/POE/Filter/FSSocket.pm
Executable file
343
scripts/POE-Filter-FSSocket/lib/POE/Filter/FSSocket.pm
Executable file
@ -0,0 +1,343 @@
|
|||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
POE::Filter::FSSocket - a POE filter that parses FreeSWITCH events into hashes
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use POE qw(Component::Client::TCP Filter::FSSocket);
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
my $auth_sent = 0;
|
||||||
|
my $password = "ClueCon";
|
||||||
|
|
||||||
|
POE::Component::Client::TCP->new(
|
||||||
|
'RemoteAddress' => '127.0.0.1',
|
||||||
|
'RemotePort' => '8021',
|
||||||
|
'ServerInput' => \&handle_server_input,
|
||||||
|
'Filter' => 'POE::Filter::FSSocket',
|
||||||
|
);
|
||||||
|
|
||||||
|
POE::Kernel->run();
|
||||||
|
exit;
|
||||||
|
|
||||||
|
sub handle_server_input {
|
||||||
|
my ($heap,$input) = @_[HEAP,ARG0];
|
||||||
|
|
||||||
|
print Dumper $input;
|
||||||
|
|
||||||
|
|
||||||
|
if($input->{'Content-Type'} eq "auth/request") {
|
||||||
|
$auth_sent = 1;
|
||||||
|
$heap->{'server'}->put("auth $password");
|
||||||
|
} elsif ($input->{'Content-Type'} eq "command/reply") {
|
||||||
|
if($auth_sent == 1) {
|
||||||
|
$auth_sent = -1;
|
||||||
|
|
||||||
|
#do post auth stuff
|
||||||
|
$heap->{'server'}->put("events plain all");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
See examples in the examples directory of the distribution.
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
POE::Filter::FSSocket parses output from FreeSWITCH into hashes. FreeSWITCH
|
||||||
|
events have a very wide range of keys, the only consistant one being
|
||||||
|
Content-Type. The keys are dependant on the type of events. You must use the
|
||||||
|
plain event type as that is what the filter knows how to parse. You can ask for
|
||||||
|
as many event types as you like or all for everything. You specify a list of
|
||||||
|
event types by putting spaces between them ex: "events plain api log talk"
|
||||||
|
|
||||||
|
Currently known event types (Event-Name):
|
||||||
|
|
||||||
|
CUSTOM
|
||||||
|
CHANNEL_CREATE
|
||||||
|
CHANNEL_DESTROY
|
||||||
|
CHANNEL_STATE
|
||||||
|
CHANNEL_ANSWER
|
||||||
|
CHANNEL_HANGUP
|
||||||
|
CHANNEL_EXECUTE
|
||||||
|
CHANNEL_BRIDGE
|
||||||
|
CHANNEL_UNBRIDGE
|
||||||
|
CHANNEL_PROGRESS
|
||||||
|
CHANNEL_OUTGOING
|
||||||
|
CHANNEL_PARK
|
||||||
|
CHANNEL_UNPARK
|
||||||
|
API
|
||||||
|
LOG
|
||||||
|
INBOUND_CHAN
|
||||||
|
OUTBOUND_CHAN
|
||||||
|
STARTUP
|
||||||
|
SHUTDOWN
|
||||||
|
PUBLISH
|
||||||
|
UNPUBLISH
|
||||||
|
TALK
|
||||||
|
NOTALK
|
||||||
|
SESSION_CRASH
|
||||||
|
MODULE_LOAD
|
||||||
|
DTMF
|
||||||
|
MESSAGE
|
||||||
|
CODEC
|
||||||
|
BACKGROUND_JOB
|
||||||
|
ALL
|
||||||
|
|
||||||
|
Currently handled FreeSWITCH messages (Content-Type):
|
||||||
|
|
||||||
|
auth/request
|
||||||
|
command/response
|
||||||
|
text/event-plain
|
||||||
|
api/response (data in __DATA__ variable)
|
||||||
|
log/data (data in __DATA__ variable)
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
|
||||||
|
package POE::Filter::FSSocket;
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use Carp qw(carp croak);
|
||||||
|
use vars qw($VERSION);
|
||||||
|
use base qw(POE::Filter);
|
||||||
|
|
||||||
|
$VERSION = '0.05';
|
||||||
|
|
||||||
|
use POE::Filter::Line;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
#self array
|
||||||
|
sub LINE_FILTER() {1}
|
||||||
|
sub PARSER_STATE() {2}
|
||||||
|
sub PARSER_STATENEXT() {3}
|
||||||
|
sub PARSED_RECORD() {4}
|
||||||
|
sub CURRENT_LENGTH() {5}
|
||||||
|
sub STRICT_PARSE() {6}
|
||||||
|
sub DEBUG_LEVEL() {7}
|
||||||
|
|
||||||
|
#states of the parser
|
||||||
|
sub STATE_WAITING() {1} #looking for new input
|
||||||
|
sub STATE_CLEANUP() {2} #wipe out record separators
|
||||||
|
sub STATE_GETDATA() {3} #have header, get data
|
||||||
|
sub STATE_FLUSH() {4} #puts us back in wait state and tells us to kill the parsed_record
|
||||||
|
sub STATE_TEXTRESPONSE() {5} #used for api output
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my %args = @_;
|
||||||
|
|
||||||
|
my $strict = 0;
|
||||||
|
my $debug = 0;
|
||||||
|
|
||||||
|
if(defined($args{'debug'})) {
|
||||||
|
$debug = $args{'debug'};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(defined($args{'strict'}) && $args{'strict'} == 1) {
|
||||||
|
$strict = $args{'strict'};
|
||||||
|
}
|
||||||
|
|
||||||
|
#our filter is line based, don't reinvent the wheel
|
||||||
|
my $line_filter = POE::Filter::Line->new();
|
||||||
|
|
||||||
|
my $self = bless [
|
||||||
|
"", #not used by me but the baseclass clone wants it here
|
||||||
|
$line_filter, #LINE_FILTER
|
||||||
|
STATE_WAITING, #PARSER_STATE
|
||||||
|
undef, #PARSER_STATE
|
||||||
|
{}, #PARSED_RECORD
|
||||||
|
0, #length tracking (for Content-Length when needed)
|
||||||
|
$strict, #whether we should bail on a bad parse or try and save the session
|
||||||
|
$debug, #debug level
|
||||||
|
], $class;
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub get_one_start {
|
||||||
|
my ($self, $stream) = @_;
|
||||||
|
$self->[LINE_FILTER]->get_one_start($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_one {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
#grab a line from the filter
|
||||||
|
my $line = $self->[LINE_FILTER]->get_one();
|
||||||
|
|
||||||
|
#quit if we can't get any lines
|
||||||
|
return [] unless @$line;
|
||||||
|
|
||||||
|
#get the actual line
|
||||||
|
$line = $line->[0];
|
||||||
|
|
||||||
|
if(($self->[PARSER_STATE] == STATE_WAITING) || ($self->[PARSER_STATE] == STATE_FLUSH)) {
|
||||||
|
#see if we need to wipe out the parsed_record info
|
||||||
|
if($self->[PARSER_STATE] == STATE_FLUSH) {
|
||||||
|
delete $self->[PARSED_RECORD];
|
||||||
|
$self->[CURRENT_LENGTH] = 0;
|
||||||
|
|
||||||
|
$self->[PARSER_STATE] = STATE_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($line =~ /Content-Length:\ (\d+)$/) {
|
||||||
|
#store the length
|
||||||
|
$self->[PARSED_RECORD]{'Content-Length'} = $1;
|
||||||
|
|
||||||
|
#see if we had a place to go from here (we should)
|
||||||
|
if(defined($self->[PARSER_STATENEXT])) {
|
||||||
|
$self->[PARSER_STATE] = $self->[PARSER_STATENEXT];
|
||||||
|
$self->[PARSER_STATENEXT] = undef;
|
||||||
|
}
|
||||||
|
} elsif($line =~ /Content-Type:\ (.*)$/) {
|
||||||
|
#store the type of request
|
||||||
|
$self->[PARSED_RECORD]{'Content-Type'} = $1;
|
||||||
|
|
||||||
|
if($1 eq "auth/request") {
|
||||||
|
$self->[PARSER_STATE] = STATE_CLEANUP;
|
||||||
|
$self->[PARSER_STATENEXT] = STATE_FLUSH;
|
||||||
|
return [ $self->[PARSED_RECORD] ];
|
||||||
|
} elsif ($1 eq "command/reply") { #do something with this later
|
||||||
|
$self->[PARSER_STATE] = STATE_GETDATA;
|
||||||
|
} elsif ($1 eq "text/event-plain") {
|
||||||
|
$self->[PARSER_STATE] = STATE_CLEANUP;
|
||||||
|
$self->[PARSER_STATENEXT] = STATE_GETDATA;
|
||||||
|
} elsif ($1 eq "api/response") {
|
||||||
|
$self->[PARSER_STATENEXT] = STATE_TEXTRESPONSE;
|
||||||
|
} elsif ($1 eq "log/data") {
|
||||||
|
$self->[PARSER_STATENEXT] = STATE_TEXTRESPONSE;
|
||||||
|
} else { #unexpected input
|
||||||
|
croak ref($self) . " unknown input [" . $self->[PARSER_STATE] . "] (" . $line . ")";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#already in wait state, if we are not in strict, keep going
|
||||||
|
if($self->[STRICT_PARSE]) {
|
||||||
|
croak ref($self) . " unknown input [STATE_WAITING] (" . $line . ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($self->[PARSER_STATE] == STATE_CLEANUP) {
|
||||||
|
if($line eq "") {
|
||||||
|
if(defined($self->[PARSER_STATENEXT])) {
|
||||||
|
$self->[PARSER_STATE] = $self->[PARSER_STATENEXT];
|
||||||
|
$self->[PARSER_STATENEXT] = undef;
|
||||||
|
} else {
|
||||||
|
$self->[PARSER_STATE] = STATE_WAITING;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#see if we should bail
|
||||||
|
if($self->[STRICT_PARSE]) {
|
||||||
|
croak ref($self) . " unknown input [STATE_CLEANUP] (" . $line . ")";
|
||||||
|
} else {
|
||||||
|
#we are not supposed to bail so try and save our session...
|
||||||
|
#since we are think we should be cleaning up, flush it all away
|
||||||
|
$self->[PARSER_STATE] = STATE_FLUSH;
|
||||||
|
|
||||||
|
#parser fail should be considered critical, if any debug at all, print dump
|
||||||
|
if($self->[DEBUG_LEVEL]) {
|
||||||
|
print STDERR "Parse failed on ($line) in STATE_CLEANUP:\n";
|
||||||
|
print STDERR Dumper $self->[PARSED_RECORD];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($self->[PARSER_STATE] == STATE_GETDATA) {
|
||||||
|
if($line =~ /^([^:]+):\ (.*)$/) {
|
||||||
|
$self->[PARSED_RECORD]{$1} = $2;
|
||||||
|
} elsif ($line eq "") { #end of event
|
||||||
|
$self->[PARSER_STATE] = STATE_FLUSH;
|
||||||
|
|
||||||
|
return [ $self->[PARSED_RECORD] ];
|
||||||
|
} else {
|
||||||
|
if($self->[STRICT_PARSE]) {
|
||||||
|
croak ref($self) . " unknown input [STATE_GETDATA] (" . $line . ")";
|
||||||
|
} else {
|
||||||
|
#flush and run
|
||||||
|
$self->[PARSER_STATE] = STATE_FLUSH;
|
||||||
|
|
||||||
|
#parser fail should be considered critical, if any debug at all, print dump
|
||||||
|
if($self->[DEBUG_LEVEL]) {
|
||||||
|
print STDERR "Parse failed on ($line) in STATE_GETDATA:\n";
|
||||||
|
print STDERR Dumper $self->[PARSED_RECORD];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($self->[PARSER_STATE] == STATE_TEXTRESPONSE) {
|
||||||
|
if($self->[CURRENT_LENGTH] == -1) {
|
||||||
|
$self->[CURRENT_LENGTH] = 0;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->[CURRENT_LENGTH] += (length($line) + 1);
|
||||||
|
|
||||||
|
if(($self->[CURRENT_LENGTH] - 1) == $self->[PARSED_RECORD]{'Content-Length'}) {
|
||||||
|
$self->[PARSER_STATE] = STATE_FLUSH;
|
||||||
|
$self->[PARSED_RECORD]{'__DATA__'} .= $line;
|
||||||
|
|
||||||
|
return [$self->[PARSED_RECORD]];
|
||||||
|
} else {
|
||||||
|
$self->[PARSED_RECORD]{'__DATA__'} .= $line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub put {
|
||||||
|
my ($self, $lines) = @_;
|
||||||
|
|
||||||
|
my @row;
|
||||||
|
foreach my $line (@$lines) {
|
||||||
|
push @row, $line . "\n\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return \@row;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_pending {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->[LINE_FILTER]->get_pending();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get {
|
||||||
|
my ($self, $stream) = @_;
|
||||||
|
my @return;
|
||||||
|
|
||||||
|
$self->get_one_start($stream);
|
||||||
|
while(1) {
|
||||||
|
my $next = $self->get_one();
|
||||||
|
last unless @$next;
|
||||||
|
push @return, @$next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return \@return;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
FreeSWITCH - http://www.freeswitch.org/
|
||||||
|
|
||||||
|
=head1 AUTHORS
|
||||||
|
|
||||||
|
POE::Filter::FSSocket is written by Paul Tinsley. You can reach him by e-mail
|
||||||
|
at pdt@jackhammer.org.
|
||||||
|
|
||||||
|
=head1 COPYRIGHT
|
||||||
|
|
||||||
|
Copyright 2006, Paul Tinsley. All rights are reserved.
|
||||||
|
|
||||||
|
POE::Filter::FSSocket is free software; it is currently licensed under the MPL
|
||||||
|
license version 1.1.
|
||||||
|
|
||||||
|
=cut
|
10
scripts/POE-Filter-FSSocket/t/01_basic.t
Normal file
10
scripts/POE-Filter-FSSocket/t/01_basic.t
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use Test::More tests => 1;
|
||||||
|
|
||||||
|
use_ok("POE::Filter::FSSocket");
|
||||||
|
|
||||||
|
exit;
|
361
scripts/socket/fsconsole.pl
Normal file
361
scripts/socket/fsconsole.pl
Normal file
@ -0,0 +1,361 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
sub POE::Kernel::ASSERT_DEFAULT () { 1 };
|
||||||
|
sub Term::Visual::DEBUG () { 1 }
|
||||||
|
sub Term::Visual::DEBUG_FILE () { 'test.log' }
|
||||||
|
use IO::Socket;
|
||||||
|
use POE qw/Filter::FSSocket Component::Client::TCP/;
|
||||||
|
use Data::Dumper;
|
||||||
|
use Term::Visual;
|
||||||
|
|
||||||
|
|
||||||
|
local *D;
|
||||||
|
if (Term::Visual::DEBUG) {
|
||||||
|
*D = *Term::Visual::ERRS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#local *ERROR = *STDERR;
|
||||||
|
|
||||||
|
|
||||||
|
$SIG{__DIE__} = sub {
|
||||||
|
if (Term::Visual::DEBUG) {
|
||||||
|
print Term::Visual::ERRS "Died: @_\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## BEGIN Globals ##############################################################
|
||||||
|
###############################################################################
|
||||||
|
our $server_address = "127.0.0.1";
|
||||||
|
our $server_port = "8021";
|
||||||
|
our $server_secret = "ClueCon";
|
||||||
|
|
||||||
|
#this is where you can customize the color scheme
|
||||||
|
our %Pallet = (
|
||||||
|
'warn_bullet' => 'bold yellow',
|
||||||
|
'err_bullet' => 'bold red',
|
||||||
|
'out_bullet' => 'bold green',
|
||||||
|
'access' => 'bright red on blue',
|
||||||
|
'current' => 'bright yellow on blue',
|
||||||
|
);
|
||||||
|
|
||||||
|
our $terminal;
|
||||||
|
my %sockets;
|
||||||
|
my %windows;
|
||||||
|
my %unread_count;
|
||||||
|
my %commands = (
|
||||||
|
'window' => 1,
|
||||||
|
'w' => 1,
|
||||||
|
'win' => 1,
|
||||||
|
);
|
||||||
|
###############################################################################
|
||||||
|
## END Globals ##############################################################
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
#setup our session
|
||||||
|
POE::Session->create(
|
||||||
|
'inline_states' => {
|
||||||
|
'_start' => \&handle_start, #session start
|
||||||
|
'_stop' => \&handle_stop, #session stop
|
||||||
|
'curses_input' => \&handle_curses_input, #input from the keyboard
|
||||||
|
'update_time' => \&handle_update_time, #update the status line clock
|
||||||
|
'quit' => \&handle_quit, #handler to do any cleanup
|
||||||
|
'server_input' => \&handle_server_input,
|
||||||
|
'_default' => \&handle_default,
|
||||||
|
},
|
||||||
|
'heap' => {
|
||||||
|
'terminal' => undef,
|
||||||
|
'freeswitch' => undef,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
#start the kernel a chugging along
|
||||||
|
$poe_kernel->run;
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
## BEGIN Handlers #############################################################
|
||||||
|
###############################################################################
|
||||||
|
#handles any startup functions for our session
|
||||||
|
sub handle_default {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_start {
|
||||||
|
my ($kernel, $session, $heap) = @_[KERNEL, SESSION, HEAP];
|
||||||
|
|
||||||
|
#setup our terminal
|
||||||
|
$heap->{'terminal'} = Term::Visual->new(
|
||||||
|
'Alias' => 'terminal', #poe alias for this
|
||||||
|
'History_Size' => 300, #number of things to keep in history
|
||||||
|
'Common_Input' => 1, #all windows share input and history
|
||||||
|
'Tab_Complete' => \&tab_complete,
|
||||||
|
);
|
||||||
|
|
||||||
|
$terminal = $heap->{'terminal'};
|
||||||
|
|
||||||
|
#setup the color palette
|
||||||
|
$terminal->set_palette(%Pallet);
|
||||||
|
|
||||||
|
#create a base window
|
||||||
|
my $window_id = $terminal->create_window(
|
||||||
|
'Window_Name' => 'console',
|
||||||
|
'Buffer_Size' => 3000,
|
||||||
|
'Title' => 'FreeSWITCH Console',
|
||||||
|
'Status' => {
|
||||||
|
'0' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['time'],
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['window_status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$windows{'console'} = $window_id;
|
||||||
|
|
||||||
|
$window_id = $terminal->create_window(
|
||||||
|
'Window_Name' => 'log',
|
||||||
|
'Buffer_Size' => 3000,
|
||||||
|
'Title' => 'FreeSWITCH Logs',
|
||||||
|
'Status' => {
|
||||||
|
'0' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['time'],
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['window_status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$windows{'log'} = $window_id;
|
||||||
|
|
||||||
|
$window_id = $terminal->create_window(
|
||||||
|
'Window_Name' => 'event',
|
||||||
|
'Buffer_Size' => 3000,
|
||||||
|
'Title' => 'FreeSWITCH Event',
|
||||||
|
'Status' => {
|
||||||
|
'0' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['time'],
|
||||||
|
},
|
||||||
|
'1' => {
|
||||||
|
'format' => '%s',
|
||||||
|
'fields' => ['window_status'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
$windows{'event'} = $window_id;
|
||||||
|
|
||||||
|
#tell the terminal what to call when there is input from the keyboard
|
||||||
|
$kernel->post('terminal' => 'send_me_input' => 'curses_input');
|
||||||
|
|
||||||
|
$terminal->change_window(0);
|
||||||
|
$kernel->delay_set('update_time' => 1);
|
||||||
|
$terminal->set_status_field(0, 'time' => scalar(localtime));
|
||||||
|
new_message('destination_window' => 0, 'message' => "
|
||||||
|
Welcome to the FreeSWITCH POE Curses Console!
|
||||||
|
The console is split into three windows:
|
||||||
|
- 'console' for api response messages
|
||||||
|
- 'log' for freeswitch log output (simply send the log level you want
|
||||||
|
to start seeing events eg: 'log all')
|
||||||
|
- 'event' for freeswitch event output (must subscribe in plain format
|
||||||
|
eg: 'event plain all')
|
||||||
|
|
||||||
|
To switch between windows type 'w <windowname' so 'w log' for example.
|
||||||
|
|
||||||
|
Coming soon:
|
||||||
|
- Tab completion
|
||||||
|
- command history
|
||||||
|
- window status in the bar (messages added since last view, etc...)
|
||||||
|
|
||||||
|
Send any bug reports or comments to jackhammer\@gmail.com
|
||||||
|
|
||||||
|
Thanks,
|
||||||
|
Paul\n");
|
||||||
|
|
||||||
|
$terminal->set_status_field($terminal->current_window, 'window_status' => format_window_status());
|
||||||
|
|
||||||
|
#connect to freeswitch
|
||||||
|
$heap->{'freeswitch'} = POE::Component::Client::TCP->new(
|
||||||
|
'RemoteAddress' => $server_address,
|
||||||
|
'RemotePort' => $server_port,
|
||||||
|
'ServerInput' => \&handle_server_input,
|
||||||
|
'Connected' => \&handle_fs_connected,
|
||||||
|
'ServerError' => \&handle_server_error,
|
||||||
|
'Disconnected' => \&handle_server_disconnect,
|
||||||
|
'Domain' => AF_INET,
|
||||||
|
'Filter' => POE::Filter::FSSocket->new(),
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#called when users enter commands in a window
|
||||||
|
sub handle_curses_input {
|
||||||
|
my ($kernel, $heap, $input, $context) = @_[KERNEL, HEAP, ARG0, ARG1];
|
||||||
|
|
||||||
|
#get the id of the window that is responsible for the input
|
||||||
|
my $window = $heap->{'terminal'}->current_window;
|
||||||
|
|
||||||
|
open(ERROR, ">>error.log");
|
||||||
|
|
||||||
|
if($input eq "quit") {
|
||||||
|
$kernel->yield('quit');
|
||||||
|
} elsif ($input =~ /^w\ (.*)$/) {
|
||||||
|
#get the id of the requested window
|
||||||
|
eval {
|
||||||
|
my $window_id = $windows{$1};
|
||||||
|
|
||||||
|
#see if it's real
|
||||||
|
if(defined($window_id)) {
|
||||||
|
$unread_count{$window_id} = 0;
|
||||||
|
$terminal->change_window($window_id);
|
||||||
|
$terminal->set_status_field($window_id, 'window_status' => &format_window_status());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if($@) {
|
||||||
|
print ERROR "put error: $@\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#see if we got connected at some point
|
||||||
|
if(defined($sockets{'localhost'})) {
|
||||||
|
#send the command
|
||||||
|
$sockets{'localhost'}->put($input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_fs_connected {
|
||||||
|
my ($kernel, $heap) = @_[KERNEL, HEAP];
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$sockets{'localhost'} = $heap->{'server'};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#this is responsible for doing any cleanup and returning the terminal to the previous
|
||||||
|
#state before we mucked with it
|
||||||
|
sub handle_quit {
|
||||||
|
my ($kernel, $heap) = @_[KERNEL, HEAP];
|
||||||
|
|
||||||
|
#tell curses to clean up it's crap
|
||||||
|
$kernel->post('terminal' => 'shutdown');
|
||||||
|
|
||||||
|
#there is probably a more elegant way, but this works for now
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
#data from freeswitch
|
||||||
|
sub handle_server_input {
|
||||||
|
my ($kernel,$heap,$input) = @_[KERNEL,HEAP,ARG0];
|
||||||
|
|
||||||
|
eval {
|
||||||
|
#terminal HATES null
|
||||||
|
if(defined($input->{'__DATA__'})) {
|
||||||
|
$input->{'__DATA__'} =~ s/[\x00]//g;
|
||||||
|
}
|
||||||
|
|
||||||
|
#handle the login
|
||||||
|
if($input->{'Content-Type'} eq "auth/request") {
|
||||||
|
$heap->{'server'}->put("auth $server_secret");
|
||||||
|
} elsif ($input->{'Content-Type'} eq "api/response") {
|
||||||
|
new_message('destination_window' => 0, 'message' => 'Response: ');
|
||||||
|
new_message('destination_window' => 0, 'message' => $input->{'__DATA__'});
|
||||||
|
} elsif ($input->{'Content-Type'} eq "log/data") {
|
||||||
|
new_message('destination_window' => 1, 'message' => $input->{'__DATA__'});
|
||||||
|
} elsif ($input->{'Content-Type'} eq "text/event-plain") {
|
||||||
|
new_message('destination_window' => 2, 'message' => Dumper $input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if($@) {
|
||||||
|
open(ERROR, ">>error.log");
|
||||||
|
print ERROR "died: $@\n";
|
||||||
|
print ERROR Dumper $heap;
|
||||||
|
close(ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_server_error {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_server_disconnect {
|
||||||
|
}
|
||||||
|
|
||||||
|
sub tab_complete {
|
||||||
|
my $left = shift;
|
||||||
|
|
||||||
|
my @return;
|
||||||
|
|
||||||
|
if(defined($commands{$left})) {
|
||||||
|
return [$left . " "];
|
||||||
|
#} elsif () {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub handle_update_time {
|
||||||
|
my ($kernel, $heap) = @_[KERNEL, HEAP];
|
||||||
|
$terminal->set_status_field($terminal->current_window, 'time' => scalar(localtime));
|
||||||
|
$kernel->delay_set('update_time' => 1);
|
||||||
|
}
|
||||||
|
###############################################################################
|
||||||
|
## END Handlers #############################################################
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
sub new_message {
|
||||||
|
my %args = @_;
|
||||||
|
|
||||||
|
my $message = $args{'message'};
|
||||||
|
my $destination_window = $args{'destination_window'};
|
||||||
|
|
||||||
|
my $status_field;
|
||||||
|
|
||||||
|
#see if we are on the window being updated
|
||||||
|
if($terminal->current_window != $destination_window) {
|
||||||
|
#increment the unread count for the window
|
||||||
|
#FIXME, should we count messages or lines?
|
||||||
|
$unread_count{$destination_window}++;
|
||||||
|
|
||||||
|
|
||||||
|
#update the status bar
|
||||||
|
eval {
|
||||||
|
$terminal->set_status_field($terminal->current_window, 'window_status' => &format_window_status());
|
||||||
|
};
|
||||||
|
|
||||||
|
if($@) {
|
||||||
|
print $@;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#deliver the message
|
||||||
|
$terminal->print($destination_window, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub format_window_status {
|
||||||
|
my $status_field;
|
||||||
|
|
||||||
|
#put all the windows in the bar with their current unread count
|
||||||
|
foreach my $window (sort {$windows{$a} <=> $windows{$b}} keys %windows) {
|
||||||
|
#see if we are printing the current window
|
||||||
|
if($terminal->current_window == $windows{$window}) {
|
||||||
|
$status_field .= "[\0(current)$window\0(st_frames)";
|
||||||
|
} else {
|
||||||
|
$status_field .= "[$window";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($unread_count{$windows{$window}}) {
|
||||||
|
$status_field .= " (" . $unread_count{$windows{$window}} . ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
$status_field .= "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $status_field;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user