my $U = 'OpenILS::Application::AppUtils';
-# $last_channel_used is:
+# %last_channel_used is, per event def with params or the config file:
# ~ index (not literal value) of last channel used in a callfile
-# ~ index is of position in @channels (zero-based)
+# ~ index is of position in the array of channels (zero-based)
# ~ cached at package level
# ~ typically for Zap (PSTN), not VOIP
-our @channels;
-our $last_channel_used = 0;
+our %last_channel_used = ();
our $telephony;
sub ABOUT {
- return <<ABOUT;
+ return <<'ABOUT';
The AstCall reactor module creates a callfile for Asterisk, given a
template describing the message and an environment defining
necessary information for contacting the Asterisk server and scheduling
a call with it.
+ If you have only one SIP server, you can set it up like this in the
+ opensrf.xml configuration file:
+
+ <telephony>
+ <!-- replace all values below when telephony server is configured -->
+ <enabled>0</enabled>
+ <driver>SIP</driver> <!-- SIP (default) or multi -->
+ <channels> <!-- explicit list of channels used if multi -->
+ <!-- A channel specifies technology/resource -->
+ <channel>Zap/1</channel>
+ <channel>Zap/2</channel>
+ <channel>IAX/user:secret@widgets.biz</channel>
+ </channels>
+ <host>localhost</host>
+ <port>10080</port>
+ <user>evergreen</user>
+ <pw>evergreen</pw>
+ <!--
+ The overall composition of callfiles is determined by the
+ relevant template, but this section can be invoked for callfile
+ configs common to all outbound calls.
+ callfile_lines will be inserted into ALL generated callfiles
+ after the Channel line. This content mat be overridden
+ (in whole) by the org unit setting callfile_lines.
+ Warning: Invalid syntax may break ALL outbound calls.
+ -->
+ <!-- <callfile_lines>
+ MaxRetries: 3
+ RetryTime: 60
+ WaitTime: 30
+ Archive: 1
+ Extension: 10
+ </callfile_lines> -->
+ </telephony>
+
+ To support more than one SIP server, say, per library, you can use
+ Action/Trigger parameters like these, which model the same information
+ as above:
+
+ enabled = 0
+ driver = "SIP"
+ channels = ["Zap/1", "Zap/2", "IAX/user:secret@widgets.biz"]
+ host = "localhost"
+ port = "10080"
+ user = "evergreen"
+ pw = "evergreen"
+ callfile_lines = ["MaxRetries: 3", "RetryTime: 60", "WaitTime: 30", "Archive: 1", "Extension: 10"]
+
ABOUT
}
sub get_conf {
+ my $part = shift;
+ my $env = shift;
+
+ # get the part they want from the environment, if we have it
+ return $env->{params}{$part} if ( $part && $env && exists $env->{params}{$part});
# $logger->info(__PACKAGE__ . ": get_conf()");
- $telephony and return $telephony;
- my $config = OpenSRF::Utils::SettingsClient->new;
- # config object cached by package
- $telephony = $config->config_value('notifications', 'telephony');
+
+ # failing all of that, just fetch the config file if we don't have it
+ if (!$telephony) {
+ my $config = OpenSRF::Utils::SettingsClient->new;
+ # config object cached by package
+ $telephony = $config->config_value('notifications', 'telephony');
+ }
+
+ # if they want a part, and we have the config file data, return that
+ return $$telephony{$part} if ( $part && $telephony && exists $$telephony{$part});
+
+ # but if they don't want a part, and we have the whole config file thing, return it
return $telephony;
}
+sub channels_from {
+ my $env = shift;
+
+ # report the event def id if we get the channels from params
+ return $env->{EventProcessor}{event}->event_def->id
+ if ( exists $env->{params}{channels});
+
+ # else just say '*'
+ return '*';
+}
+
sub get_channels {
- @channels and return @channels;
- my $config = get_conf(); # populated $telephony object
- @channels = @{ $config->{channels} };
- return @channels;
+ my $env = shift;
+ @{ get_conf( channels => $env ) };
}
sub next_channel {
+ my $env = shift;
# Increments $last_channel_used, or resets it to zero, as necessary.
# Returns appropriate value from channels array.
- my @chans = get_channels();
+ my $source = channels_from($env);
+ my @chans = get_channels($env);
unless(@chans) {
$logger->error(__PACKAGE__ . ": Cannot build call using " .
(shift ||'driver') .
", no notifications.telephony.channels found in config!");
return;
}
- if (++$last_channel_used > $#chans) {
- $last_channel_used = 0;
+ if (++$last_channel_used{$source} > $#chans) {
+ $last_channel_used{$source} = 0;
}
- return $chans[$last_channel_used]; # say, 'Zap/1' or 'Zap/12'
+ return $chans[$last_channel_used{$source}]; # say, 'Zap/1' or 'Zap/12'
}
sub channel {
- my $tech = get_conf()->{driver} || 'SIP';
+ my $env = shift;
+ my $tech = get_conf( driver => $env ) || 'SIP';
if ($tech !~ /^SIP/) {
- return next_channel($tech);
+ return next_channel($env, $tech);
}
return $tech; # say, 'SIP' or 'SIP/ubab33'
}
sub get_extra_lines {
- my $lines = get_conf()->{callfile_lines} or return '';
+ my $env = shift;
+ my $lines = get_conf( callfile_lines => $env ) or return '';
+ return '' if (ref($lines) && (ref($lines) !~ /ARRAY/));
+ $lines = [ split "\n", $lines ] unless (ref($lines));
+
my @fixed;
- foreach (split "\n", $lines) {
+ foreach (@$lines) {
s/^\s*//g; # strip leading spaces
/\S/ or next; # skip empty lines
push @fixed, $_;
}
sub host_string {
- my $conf = get_conf();
- my $host = $conf->{host};
+ my $env = shift;
+ my $host = get_conf( host => $env );
+ my $port = get_conf( port => $env );
+
unless ($host) {
$logger->error(__PACKAGE__ . ": No telephony/host in config.");
return;
}
+ $logger->info(__PACKAGE__ . ": host [$host], port [$port]");
# prepend http:// if no protocol specified
- $host =~ /^\S+:\/\// or $host = 'http://' . $host;
+ if ($host !~ /^\S+:\/\//) {
+ $host = 'http://' . $host;
+ }
# append port number if specified
- $conf->{port} and $host .= ":" . $conf->{port};
+ if ($port) {
+ $host .= ":" . $port;
+ }
+ $logger->info(__PACKAGE__ . ": final host string [$host]");
return $host;
}
sub rpc_client {
$logger->info(__PACKAGE__ . ": entered handler");
# assignment, not comparison
- unless ($env->{channel_prefix} = channel()) {
+ unless ($env->{channel_prefix} = channel($env)) {
$logger->error(__PACKAGE__ . ": Cannot find tech/resource in config");
return 0;
}
- $env->{extra_lines} = get_extra_lines() || '';
+ $env->{extra_lines} = get_extra_lines($env) || '';
my $tmpl_output = $self->run_TT($env);
if (not $tmpl_output) {
$logger->error(__PACKAGE__ . ": no template input");
# TODO: add scheduling intelligence and use it here... or not if
# relying only on crontab
- my $client = rpc_client();
+ my $client = rpc_client(host_string($env));
my $resp = $client->send_request(
'inject', $tmpl_output, $filename_fragment, 0
); # FIXME: 0 could be seconds-from-epoch UTC if deferred call needed
}
sub retrieve {
- $logger->info("retrieve() not implemented. how'd we get here?"); # XXX
- return;
+ $logger->info("retrieve() not implemented. how'd we get here?"); # XXX
+ return;
}
#sub retrieve {