ngcp-panel/lib/NGCP/Panel/Utils/Interception.pm

148 lines
4.4 KiB

package NGCP::Panel::Utils::Interception;
use warnings;
use strict;
use Data::Dumper;
use LWP::UserAgent;
use TryCatch;
use JSON;
sub request {
my ($c, $method, $uuid, $data) = @_;
my $a = _init($c);
return unless($a);
return unless($method eq 'POST' || $method eq 'PUT' || $method eq 'DELETE');
my @agents = @{ $a->{ua} };
my @urls = @{ $a->{url} };
for(my $i = 0; $i < scalar(@agents); ++$i) {
my $ua = $agents[$i];
my $url = $urls[$i];
if($method eq 'PUT' or $method eq 'DELETE') {
return unless($uuid);
$url .= '/'.$uuid;
}
$c->log->debug("performing $method for interception at $url");
try {
_request($c, $ua, $url, $method, $data);
} catch($e) {
# skip errors
}
}
return 1;
}
sub _request {
my ($c, $ua, $url, $method, $data) = @_;
my $req = HTTP::Request->new($method => $url);
if($data) {
$req->content_type('application/json');
$req->content(encode_json($data));
}
my $res = $ua->request($req);
if($res->is_success) {
return 1;
} else {
$c->log->error("Failed to do $method on $url: " . $res->status_line);
return;
}
}
sub _init {
my ($c) = @_;
my @ua = ();
my @url = ();
my @cfgs = ();
if(ref $c->config->{intercept}->{agent} eq 'HASH') {
push @cfgs, $c->config->{intercept}->{agent};
} elsif(ref $c->config->{intercept}->{agent} eq 'ARRAY') {
@cfgs = @{ $c->config->{intercept}->{agent} };
}
unless(@cfgs) {
$c->log->error("No intercept agents configured in ngcp_panel.conf, rejecting request");
return;
}
foreach my $cfg(@cfgs) {
my $agent = LWP::UserAgent->new();
$agent->agent("Sipwise NGCP X1/0.2");
$agent->timeout(2);
if($cfg->{user} && $cfg->{pass}) {
$agent->credentials(
$cfg->{host}.":".$cfg->{port},
$cfg->{realm},
$cfg->{user},
$cfg->{pass}
);
}
push @ua, $agent;
push @url, $cfg->{schema}.'://'.$cfg->{host}.':'.$cfg->{port}.$cfg->{url};
}
return { ua => \@ua, url => \@url };
}
sub username_to_regexp_pattern {
my ($c,$voip_number,$username) = @_;
# $c is intended to use $c->config vars here.
# vsc.clir_code is not part of the panel conf, so
# the global conf would be required to load to get it.
# as this is not done elsewhere in panel code yet, we leave
# that as todo for now, and capture any vsc codes.
my $vsc_pattern = '(\*\d+\*)?';
#my $vsc_pattern = '(\*31\*)?';
my @pattern_elements = ();
# longest to shortest:
#1. the sip username itself:
push(@pattern_elements,$vsc_pattern . quotemeta($username));
#2. "international format": concat(concat('00',cc),ac,sn):
push(@pattern_elements,$vsc_pattern . '00' . $voip_number->cc . $voip_number->ac . $voip_number->sn);
#3. "e164 format": concat(cc,ac,sn):
push(@pattern_elements,$vsc_pattern . $voip_number->cc . $voip_number->ac . $voip_number->sn);
#4. "local format": concat(concat('0',ac),sn):
push(@pattern_elements,$vsc_pattern . '0' . $voip_number->ac . $voip_number->sn);
return '^(' . join('|',@pattern_elements) . ')$';
}
sub subresnum_from_number {
my ($c, $number, $err_code) = @_;
if (!defined $err_code || ref $err_code ne 'CODE') {
$err_code = sub { return 0; };
}
my $num_rs = $c->model('DB')->resultset('voip_numbers')->search(
\[ 'concat(cc,ac,sn) = ?', [ {} => $number ]]
)->search({
'subscriber_id' => { '!=' => undef },
},undef);
unless($num_rs->first) {
return 0 unless &{$err_code}("invalid number '" . $number . "'",'number',"Number does not exist");
}
my $sub = $num_rs->first->subscriber;
unless($sub) {
return 0 unless &{$err_code}("invalid number '" . $number . "', not assigned to any subscriber",'number',"Number is not active");
}
my $res = $num_rs->first->reseller;
unless($res) {
# with ossbss provisioning, reseller is not set on number,
# so take the long way here
$res = $sub->contract->contact->reseller;
unless($res) {
return 0 unless &{$err_code}("invalid number '" . $number . "', not assigned to any reseller",'number',"Number is not active");
}
}
return ($sub, $res, $num_rs->first);
}
1;