view release on metacpan or search on metacpan
- 0.08
- Added search_rates method to generic storage module
- Tweaked the 'bin' script so that 'locale' is optional in the Dialer section
- Added countries list in /contrib directory
- Added ITSP-centric features such as rates generation & management
- 0.07 (2006-01-24)
- Done lots of refactoring on the ./bin scripts
- Wrote an abstract persistence storage database layer
- Wrote Asterisk::LCR::Importer::DiskStatic (slow)
- Wrote Asterisk::LCR::Importer::DiskBlock (faster but non granular)
- Added RichMedium importer
- Updated documentation
lib/Asterisk/LCR/Route.pm
lib/Asterisk/LCR/Storage.pm
lib/Asterisk/LCR/Storage/DiskBlob.pm
lib/Asterisk/LCR/Storage/DiskStatic.pm
lib/Asterisk/LCR/Storage/MyRoutes.pm
LICENSE
Makefile.PL
MANIFEST This list of files
META.yml
README
t/001_locale.t
bin/asterisk-lcr-dialplan view on Meta::CPAN
$SIG{__WARN__} = sub { $_[0] !~ /Can't locate AGI\/Fake\.pm/ and warn @_ };
@ARGV || die "Usage: $0 <config_file>";
Config::Mini::parse_file (shift);
$Asterisk::LCR::Storage::MyRoutes::FILE = shift || "__NO_FILE__";
our $STORE = Config::Mini::instantiate ("storage") || die "no storage configured";
our $DIALER = Config::Mini::instantiate ("dialer") || die "no dialer configured";
our $LOCALE = $DIALER->locale();
# ----------------------------------------------------------------------------
print STDERR "Reading all possible prefixes from all_rates.csv\n";
our %Prefixes = ();
open FP, "<all_rates.csv" or die "Cannot open-read all_rates.csv";
my $head = <FP>;
while (<FP>)
{
bin/asterisk-lcr-myroutes view on Meta::CPAN
Config::Mini::parse_file (shift @ARGV);
@ARGV || die "Usage: $0 <config_file> <country_prefixes> <rules_file>";
my $country_pfx = shift (@ARGV);
@ARGV || die "Usage: $0 <config_file> <country_prefixes> <rules_file>";
my $rategen = Routegen->new (file => shift @ARGV);
our $STORE = Config::Mini::instantiate ("storage") || die "no storage configured";
our $DIAL = Config::Mini::instantiate ("dialer") || die "no dialer configured";
our $LOCALE = $DIAL->locale();
my %pfx2label = ();
my %pfx2rate = ();
print STDERR "Importing supported prefixes\n";
open FP, "<$country_pfx" or die "Cannot read-open $country_pfx!";
while (<FP>)
{
chomp();
my ($key, $val) = split /\s*,\s*/, $_, 2;
lib/Asterisk/LCR.pm view on Meta::CPAN
# example.
[comparer]
package = Asterisk::LCR::Comparer::XERAND
currency = eur
# Asterisk::LCR supports pluggable dialing strategies. Currently there is
# 'MinCost' which tries the absolutely cheapest route, and 'MinTime' which
# tries the $n cheapest providers simultaneously.
[dialer]
package = Asterisk::LCR::Dialer::MinCost
locale = fr
# Finally, you need to define which providers rates you want to import.
[import:voipjet]
package = Asterisk::LCR::Importer::VoIPJet
dial = us IAX2/login@voipjet/REPLACEME
[import:nufone]
package = Asterisk::LCR::Importer::NuFone
dial = us IAX2/login@NuFone/REPLACEME
lib/Asterisk/LCR.pm view on Meta::CPAN
You can choose between two strategies:
=head3 dialer - Asterisk::LCR::Dialer::MinCost
This strategy minimizes cost by trying from cheapest to most expensive provider
for any given route, in the limit of 3 providers.
[dialer]
package = Asterisk::LCR::Dialer::MinCost
locale = fr
limit = 3
=head3 dialer - Asterisk::LCR::Dialer::MinTime
This strategy minimizes PDD (Post-Dialing-Delay) by trying dialing out the 3
cheapest providers at the same time.
[dialer]
package = Asterisk::LCR::Dialer::MinCost
locale = fr
limit = 3
=head2 import modules
ATTENTION: ALL import sections must be named [import:<something>] and ALL of
them must have a unique name.
These modules are used to import / download rates from various providers. The
following modules are available.
lib/Asterisk/LCR/Dialer.pm view on Meta::CPAN
use base qw /Asterisk::LCR::Object/;
use Asterisk::LCR::Locale;
use Config::Mini;
use warnings;
use strict;
our $STORE = undef;
=head2 $self->locale();
Returns the 'locale' attribute.
=cut
sub locale
{
my $self = shift;
my $loc = $self->{locale};
return $loc ? Asterisk::LCR::Locale->new ($loc) : undef;
}
=head2 $self->set_locale ($locale);
Sets the 'locale' attribute to $locale.
=cut
sub set_locale
{
my $self = shift;
$self->{locale} = shift;
}
=head2 $self->limit();
Returns the optional 'limit' attribute.
Returns 100000 if it's not defined (quasi-infinity)
=cut
lib/Asterisk/LCR/Dialer.pm view on Meta::CPAN
sub set_opts
{
my $self = shift;
$self->{opts} = shift;
}
=head2 $self->process ($number);
Turns $number into a canonical, global number if $number
if $self->locale() returns an Asterisk::LCR::Locale object.
Then calls $self->_process ($number). This method must
be defined in subclasses.
=cut
sub process
{
my $self = shift;
my $num = shift;
my $loc = $self->locale();
$loc and do { $num = $loc->local_to_global ($num) };
$self->_process ($num);
}
sub _process
{
die "Asterisk::LCR::Dialer::process() is a virtual method";
}
lib/Asterisk/LCR/Dialer.pm view on Meta::CPAN
within Dial()
Extract a string dial template from the asterisk config file.
For example, say $rate->{provider} = 'voipjet'. This method will look for
an asterisk variable called 'ASTERISK_LCR_TMPL_VOIPJET'. The grammar to be used
for this syntax is:
VARIABLE: [LOCALE] DIAL_STRING
LOCALE: (scalar string, i.e. 'us' or 'fr' or even /var/mylocale.txt)
DIAL_STRING: <whateverwhatever>REPLACEME<whateverwhatever>
Where REPLACEME will be replaced by the phone number to dial.
If LOCALE is defined and an Asterisk::LCR::Locale object can be created,
then $num is assumed to be given as a canonical, international
number.
For example, if LOCALE is 'fr' and the number is 33575874745, then
lib/Asterisk/LCR/Dialer.pm view on Meta::CPAN
sub dial_string
{
my $self = shift;
my $num = shift || return;
my $rate = shift || return;
my $provider = $rate->provider();
my $provider_o = Config::Mini::instantiate ("import:$provider");
my $value = $provider_o->{dial};
my ($locale, $dialtmpl) = ($value =~ /\s/) ? ( split /\s+/, $value, 2 ) : (undef, $value);
for ($locale)
{
$locale || next;
$locale = Asterisk::LCR::Locale->new ($locale) || next;
$num = $locale->global_to_local ($num);
}
$dialtmpl || return;
$dialtmpl =~ s/REPLACEME/$num/;
return ($dialtmpl);
}
=head2 $self->rates ($number);
lib/Asterisk/LCR/Dialer/MinCost.pm view on Meta::CPAN
use strict;
sub _process
{
my $self = shift;
my $prefix = shift || return;
my @rates = $self->rates ($prefix);
@rates || return [];
my $local_prefix = $self->locale() ? $self->locale()->global_to_local ($prefix) : $prefix;
my $exten_remove = length ($local_prefix);
$prefix = "$prefix\${EXTEN:$exten_remove}";
my $res ||= [];
foreach my $rate (@rates)
{
my $str = $self->dial_string ($prefix, $rate) || next;
push @{$res}, $str;
}
lib/Asterisk/LCR/Importer.pm view on Meta::CPAN
package MyOwnImporter;
use base qw /Asterisk::LCR::Importer/;
use warnings;
use strict;
sub new
{
my $class = shift;
my $self = $class->SUPER::new (@_);
$self->{prefix_locale} = 'us'
$self->{prefix_position} = '0'
$self->{label_position} = '1'
$self->{rate_position} = '4'
$self->{first_increment_position} = '2'
$self->{increment_position} = '3'
$self->{connection_fee} = '0'
$self->{currency} = 'USD'
$self->{uri} = 'http://www.plainvoip.com/ratedump.php'
$self->{separator} = '(?:,|(?<=\d)\/(?=\d))'
return $self;
lib/Asterisk/LCR/Importer.pm view on Meta::CPAN
=head2 $self->prefix ($rec);
Extracts and returns the prefix from $rec.
=cut
sub prefix
{
my $self = shift;
my $rec = shift;
my $pos = $self->prefix_pos();
my $loc = $self->prefix_locale();
my $res = $rec->[$pos];
if ($loc)
{
$res = $loc->local_to_global ($res);
$res = $loc->normalize ($res);
}
return $res;
}
lib/Asterisk/LCR/Importer.pm view on Meta::CPAN
=head2 $self->prefix_pos();
Returns the position of the field which contains the prefix in the CSV data.
By default, returns 0.
If $self->{prefix_position} is defined, returns it instead.
=cut
sub prefix_pos { my $self = shift; return defined $self->{prefix_position} ? $self->{prefix_position} : 0 }
=head2 $self->prefix_locale();
Returns the locale which should be used for normalizing / translating the prefix.
Returns undef unless $self->{prefix_locale} is defined.
See L<Asterisk::LCR::Locale> for more details.
=cut
sub prefix_locale
{
my $self = shift;
$self->{prefix_locale} || return;
$self->{prefix_locale_obj} ||= Asterisk::LCR::Locale->new ( $self->{prefix_locale} );
return $self->{prefix_locale_obj};
}
=head2 $self->label ($rec);
Extracts and returns the label from $rec.
=cut
sub label
{
lib/Asterisk/LCR/Importer.pm view on Meta::CPAN
=cut
sub rates
{
my $self = shift;
$self->{rates} and return $self->{rates};
my $data = $self->get_data();
my $filter = $self->filter();
my $comma = $self->separator();
my $locale = Config::Mini::get ("dialer", "locale");
my $loc = $locale ? Asterisk::LCR::Locale->new ($locale) : undef;
my $res = {};
for (@{$data})
{
/$filter/ or do {
print "IGNORED: $_ (doesn't match /$filter/)\n";
next;
};
my $rec = [ split /\s*$comma\s*/, $_ ];
my $pfx = $self->prefix ($rec);
lib/Asterisk/LCR/Importer/CanonicalCSV.pm view on Meta::CPAN
##
# $self->rates();
# ---------------
# Returns a { <international_code> => <rate> } hash reference
##
sub rates
{
my $self = shift;
my $locale = Asterisk::LCR::Locale->new ("fix_intl");
$self->{rates} ||= do {
my $data = $self->get_data();
my $res = {};
for (@{$data})
{
my ($prefix, $label, $provider, $currency, $rate, $connection_fee, $first_increment, $increment) = split /\s*,\s*/, $_;
$prefix = $locale->local_to_global ($prefix);
$res->{$prefix} = Asterisk::LCR::Route->new (
connection_fee => $connection_fee,
first_increment => $first_increment,
increment => $increment,
currency => $currency,
rate => $rate,
provider => $provider,
label => $label,
prefix => $prefix,
);
lib/Asterisk/LCR/Importer/MutualPhone.pm view on Meta::CPAN
package Asterisk::LCR::Importer::PlainVoip;
use base qw /Asterisk::LCR::Importer/;
use warnings;
use strict;
sub new
{
my $class = shift;
my $self = $class->SUPER::new (@_);
$self->{prefix_locale} = 'us';
$self->{prefix_position} = '0';
$self->{label_position} = '1';
$self->{rate_position} = '2';
$self->{first_increment} = '1';
$self->{increment} = '1';
$self->{connection_fee} = '0';
$self->{currency} = 'USD';
$self->{uri} = 'http://mutualphone.com/mutualphone-a-z.csv';
return $self;
}
lib/Asterisk/LCR/Importer/NuFone.pm view on Meta::CPAN
use base qw /Asterisk::LCR::Importer/;
use warnings;
use strict;
sub new
{
my $class = shift;
my $self = $class->SUPER::new (@_);
$self->{prefix_position} ||= 1;
$self->{prefix_locale} ||= 'us';
$self->{label_position} ||= 0;
$self->{rate_position} ||= 2;
$self->{currency} ||= 'USD';
$self->{connection_fee} ||= 0;
$self->{first_increment} ||= 15;
$self->{increment} ||= 15;
$self->{uri} ||= 'https://www.nufone.net/rates.csv';
$self->{filter} ||= '^.*,\d+,';
return $self;
}
lib/Asterisk/LCR/Importer/PlainVoip.pm view on Meta::CPAN
package Asterisk::LCR::Importer::PlainVoip;
use base qw /Asterisk::LCR::Importer/;
use warnings;
use strict;
sub new
{
my $class = shift;
my $self = $class->SUPER::new (@_);
$self->{prefix_locale} = 'us';
$self->{prefix_position} = '0';
$self->{label_position} = '1';
$self->{rate_position} = '4';
$self->{first_increment_position} = '2';
$self->{increment_position} = '3';
$self->{connection_fee} = '0';
$self->{currency} = 'USD';
$self->{uri} = 'http://www.plainvoip.com/ratedump.php';
$self->{separator} = '(?:,|(?<=\d)\/(?=\d))';
return $self;
lib/Asterisk/LCR/Importer/RichMedium.pm view on Meta::CPAN
use warnings;
use strict;
sub new
{
my $class = shift;
my $self = $class->SUPER::new (@_);
$self->{uri} ||= "http://www.richmedium.com/wholesale-termination.csv";
$self->{prefix_position} ||= 0;
$self->{prefix_locale} ||= 'us';
$self->{label_position} ||= 4;
$self->{rate_position} ||= 1;
$self->{first_increment_position} ||= 2;
$self->{increment_position} ||= 3;
$self->{connection_fee} ||= 0;
$self->{currency} ||= 'USD';
return $self;
}
lib/Asterisk/LCR/Importer/VoIPJet.pm view on Meta::CPAN
use base qw /Asterisk::LCR::Importer/;
use warnings;
use strict;
sub new
{
my $class = shift;
my $self = $class->SUPER::new (@_);
$self->{prefix_position} ||= 1;
$self->{prefix_locale} ||= 'us';
$self->{label_position} ||= 0;
$self->{rate_position} ||= 2;
$self->{first_increment_position} ||= 3;
$self->{increment} ||= 6;
$self->{connection_fee} ||= 0;
$self->{currency} ||= 'USD';
$self->{uri} ||= 'http://voipjet.com/ratescsv.php';
$self->{filter} ||= '^.*(?<!dialing),\d+,';
return $self;
}
lib/Asterisk/LCR/Locale.pm view on Meta::CPAN
};
return $self->{local_to_global_cache}->{$num};
}
sub validate
{
my $self = shift;
my $id = $self->id() or do {
die "asterisk/lcr/locale/id/undefined";
return 0;
};
$self->path() or do {
die "asterisk/lcr/locale/id/no_path : $id";
return 0;
};
return 1;
}
sub id
{
my $self = shift;
t/001_locale.t view on Meta::CPAN
#!/usr/bin/perl
use Test::More 'no_plan';
use lib qw (../lib lib);
use warnings;
use strict;
use Asterisk::LCR::Locale;
my $locale = Asterisk::LCR::Locale->new ('fr');
is ($locale->global_to_local ("33262"), "0262");
is ($locale->local_to_global ("0262"), "262262");
# 262,Reunion,phonext,EUR,0.099,0,30,1
# 33262,Reunion,phonext,EUR,0.349,0,30,1
# 33262692,Reunion - Mobile,phonext,EUR,0.349,0,30,1
# 33692,Reunion - Mobile,phonext,EUR,0.349,0,30,1
# 262692,Reunion - Mobile,phonext,EUR,0.199,0,30,1
#Â 262,reunion island proper,voipjet,USD,0.0620,0,30,6
#Â 262692,reunion island cellular,voipjet,USD,0.2682,0,30,6
#Â 262,Reunion,ykoz,EUR,0.05,0,1,1
#Â 262692,Reunion Mobile,ykoz,EUR,0.20,0,1,1
is ($locale->local_to_global ($locale->global_to_local ("262")) => "262262");
is ($locale->local_to_global ($locale->global_to_local ("33262")) => "262262");
is ($locale->local_to_global ($locale->global_to_local ("33692")) => "262692");
is ($locale->local_to_global ($locale->global_to_local ("262692")) => "262692");
is ($locale->global_to_local ("33262692") => "0692");
is ($locale->local_to_global ($locale->global_to_local ("33262692")) => "262692");