You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcp-panel/lib/NGCP/Panel/Role/API/CallQueues.pm

201 lines
7.0 KiB

package NGCP::Panel::Role::API::CallQueues;
use NGCP::Panel::Utils::Generic qw(:all);
use Sipwise::Base;
use parent 'NGCP::Panel::Role::API';
use boolean qw(true);
use Data::HAL qw();
use Data::HAL::Link qw();
my $redis_callqueue_key_prefix = 'callqueue:';
my $redis_dialogdata_key_prefix = 'dialog:cid::';
my $number_search_limit = 100; # scan redis only if collection gets bigger than this
# todo: move this stash factory method below to some util.
sub _get_redis {
my ($self, $c, $select) = @_;
my $stash_key = 'redis';
if (defined $select) {
$stash_key .= '_' . $select;
} else {
$c->log->error("redis store not specified");
return;
}
my $redis = $c->stash->{$stash_key};
unless ($redis) {
try {
$redis = Redis->new(
server => $c->config->{redis}->{central_url},
reconnect => 10, every => 500000, # 500ms
cnx_timeout => 3,
);
unless ($redis) {
$c->log->error("Failed to connect to central redis url " . $c->config->{redis}->{central_url});
return;
}
$redis->select($select) if defined $select;
$c->stash($stash_key => $redis);
} catch($e) {
$c->log->error("Failed to fetch callqueue information from redis: $e");
return;
}
}
return $redis;
}
sub _item_rs {
my ($self, $c, $id) = @_;
#$c->config->{redis}->{callqueue_db} = 3;
my $redis = $self->_get_redis($c,$c->config->{redis}->{callqueue_db});
my $rs = $c->model('DB')->resultset('voip_subscribers');
if($c->user->roles eq "admin") {
} elsif($c->user->roles eq "reseller") {
$rs = $rs->search_rs({
'contact.reseller_id' => $c->user->reseller_id,
},{
join => { 'contract' => 'contact' }
});
} elsif ($c->user->roles eq "subscriberadmin") {
$rs = $rs->search_rs({
'me.contract_id' => $c->user->account_id,
});
} elsif ($c->user->roles eq "subscriber") {
$rs = $rs->search_rs({
'me.uuid' => $c->user->uuid,
});
}
if ($id) {
my $subs = $rs->find($id);
if ($subs) {
$rs = $rs->search_rs({
'me.uuid' => ($redis->exists($redis_callqueue_key_prefix . $subs->uuid) ? $subs->uuid : -1),
});
}
} else {
my $callqueue_uuids = $c->stash->{callqueue_uuids};
if ($c->req->params->{number}) {
$rs = $rs->search_rs({
'voip_dbaliases.username' => { like => $c->req->params->{number} },
},{
join => { 'provisioning_voip_subscriber' => 'voip_dbaliases' },
distinct => 1,
});
if (not $callqueue_uuids and $rs->search_rs(undef,{ rows => $number_search_limit, })->count < $number_search_limit) {
$callqueue_uuids = [ -1 ];
for my $subs ($rs->all) {
push(@$callqueue_uuids,$subs->uuid) if $redis->exists($redis_callqueue_key_prefix . $subs->uuid);
}
$c->stash(callqueue_uuids => $callqueue_uuids);
}
}
unless ($callqueue_uuids) {
$callqueue_uuids = [ -1 ];
my $cursor = 0;
do {
my $res = $redis->scan($cursor, MATCH => $redis_callqueue_key_prefix . '*', COUNT => 1000);
$cursor = shift @$res;
my $mapkeys = shift @$res;
foreach my $mapkey (@$mapkeys) {
push(@$callqueue_uuids,$mapkey =~ s/^$redis_callqueue_key_prefix//r);
}
} while ($cursor);
$c->stash(callqueue_uuids => $callqueue_uuids);
}
$rs = $rs->search_rs({
'me.uuid' => { -in => $callqueue_uuids },
});
}
return $rs;
}
sub get_form {
my ($self, $c) = @_;
return NGCP::Panel::Form::get("NGCP::Panel::Form::CallQueue::API", $c);
}
sub hal_links {
my($self, $c, $item, $resource, $form) = @_;
return [
Data::HAL::Link->new(relation => 'ngcp:subscribers', href => sprintf("/api/subscribers/%d", $item->id)),
];
}
sub hal_from_item {
my ($self, $c, $item, $form) = @_;
my $hal = Data::HAL->new(
links => [
Data::HAL::Link->new(
relation => 'curies',
href => 'http://purl.org/sipwise/ngcp-api/#rel-{rel}',
name => 'ngcp',
templated => true,
),
Data::HAL::Link->new(relation => 'collection', href => sprintf("/api/%s/", $self->resource_name)),
Data::HAL::Link->new(relation => 'profile', href => 'http://purl.org/sipwise/ngcp-api/'),
Data::HAL::Link->new(relation => 'self', href => sprintf("%s%d", $self->dispatch_path, $item->id)),
Data::HAL::Link->new(relation => 'ngcp:subscribers', href => sprintf("/api/subscribers/%d", $item->id)),
],
relation => 'ngcp:'.$self->resource_name,
);
my $resource = $self->resource_from_item($c, $item, $form);
$hal->resource($resource);
return $hal;
}
sub resource_from_item {
my ($self, $c, $item, $form) = @_;
my %resource = ();
#$c->config->{redis}->{callqueue_db} = 3;
#$c->config->{redis}->{dialog_db} = 23;
my $redis = $self->_get_redis($c,$c->config->{redis}->{callqueue_db});
my $res = $redis->lrange($redis_callqueue_key_prefix . $item->uuid, 0, -1);
$redis = $self->_get_redis($c,$c->config->{redis}->{dialog_db});
my @callqueue = ();
if ($res) {
foreach my $call_id (@$res) {
my $queue_item = {
duration => undef,
caller => undef,
callee => undef,
start_time => undef,
call_id => $call_id,
};
my $dialogentry_keys = $redis->smembers($redis_dialogdata_key_prefix . $call_id);
#use Data::Dumper;
#$c->log->debug($redis_dialogdata_key_prefix . $call_id . ' -> ' . Dumper($dialogentry_keys));
if ($dialogentry_keys) {
foreach my $dialogentry_key (@$dialogentry_keys) {
my %dialogdata = $redis->hgetall($dialogentry_key);
if ($dialogdata{start_time}) {
my $duration = time() - $dialogdata{start_time};
if (not defined $queue_item->{start_time} or $dialogdata{start_time} < $queue_item->{duration}) {
$queue_item->{duration} = time() - $dialogdata{start_time};
$queue_item->{caller} = $dialogdata{from_uri};
$queue_item->{start_time} = $dialogdata{start_time};
$queue_item->{callee} = $dialogdata{to_uri};
}
}
}
}
push(@callqueue,$queue_item);
}
}
$resource{queue} = \@callqueue;
$resource{queue_length} = scalar @callqueue;
return \%resource;
}
1;