Revision 332 (by ahitrov, 2013/05/03 13:35:48) |
TokBox Plugin
|
package tokbox::Keeper;
use strict;
use warnings 'all';
use Time::HiRes;
use MIME::Base64;
use Digest::SHA1 qw(sha1 sha1_hex);
use LWP::UserAgent;
use URI;
use Data::Dumper;
use XML::Fast;
use base qw(Contenido::Keeper);
use Contenido::Globals;
our $SUBSCRIBER = "subscriber";
our $PUBLISHER = "publisher";
our $MODERATOR = "moderator";
sub OpenTokSession {
my ($self, $sessionId, $properties) = @_;
return tokbox::Session->new( sessionId => $sessionId, properties => $properties );
}
### - Generate a token
#
# session_id - If session_id is not blank, this token can only join the call with the specified session_id.
# role - One of the constants defined in RoleConstants. Default is publisher, look in the documentation to learn more about roles.
# expire_time - Optional timestamp to change when the token expires. See documentation on token for details.
# connection_data - Optional string data to pass into the stream. See documentation on token for details.
#
##########################################################################################################
sub generateToken {
my ($self, %opts) = @_;
my $session_id = delete $opts{session_id} || '';
my $role = delete $opts{role} || '';
my $expire_time = delete $opts{expire_time};
my $connection_data = delete $opts{connection_data} || '';
my $create_time = time;
my $nonce = gettimeofday() . rand();
if ( !$role ) {
$role = $PUBLISHER;
} elsif ( $role ne $SUBSCRIBER && $role ne $PUBLISHER && $role ne $MODERATOR ) {
warn "unknown role $role\n";
return;
}
my $data_string = "session_id=$session_id&create_time=$create_time&role=$role&nonce=$nonce";
if ( defined $expire_time ) {
if ( $expire_time =~ /\D/ ) {
warn "Expire time must be a number\n";
return;
} elsif ( $expire_time < $create_time ) {
warn "Expire time must be in the future\n";
return;
} elsif ( $expire_time > $create_time + 2592000 ) {
warn "Expire time must be in the next 30 days\n";
return;
}
$data_string .= "&expire_time=$expire_time";
}
if ( $connection_data ) {
if ( length $connection_data > 1000 ) {
warn "Connection data must be less than 1000 characters\n";
return;
}
$data_string .= "&connection_data=" . Utils::HTML::url_escape($connection_data);
}
my $sig = $self->_sign_string($data_string, $self->state->{tokbox_secret});
my $api_key = $self->state->{tokbox_api_key};
return "T1==" . encode_base64("partner_id=$api_key&sig=$sig:$data_string");
}
###
#
# Creates a new session.
# location - IP address to geolocate the call around.
# properties - Optional array, keys are defined in SessionPropertyConstants
#
###################################################################################
sub createSession {
my ($self, %opts) = @_;
my $location = delete $opts{location} || '';
my $properties = delete $opts{properties} || {};
$properties->{"location"} = $location;
$properties->{"api_key"} = $self->state->{tokbox_api_key};
my $createSessionResult = $self->_do_request("/session/create", $properties);
return unless $createSessionResult;
my $createSessionXML = xml2hash ($createSessionResult);
unless ( ref $createSessionXML ) {
warn "Failed to create session: Invalid response from server\n";
return;
}
unless( exists $createSessionXML->{sessions}{Session}{session_id} ) {
warn "Failed to create session.\n";
warn Dumper $createSessionXML;
return;
}
my $sessionId = $createSessionXML->{sessions}{Session}{session_id};
return $self->OpenTokSession( $sessionId );
}
########################################################
# Inner functions
########################################################
sub _sign_string {
my ($self, $string, $secret) = @_;
return sha1_hex($string, $secret);
}
sub _do_request {
my ($self, $url, $data, $auth) = @_;
$auth = {} unless ref $auth;
$auth->{'type'} = 'partner' unless exists $auth->{type};
$url = $self->state->{tokbox_server} . $url;
my %authHeader;
if ( $auth->{type} eq 'token' ) {
$authHeader{"X-TB-TOKEN-AUTH"} = $auth->{'token'};
} else {
$authHeader{"X-TB-PARTNER-AUTH"} = $self->state->{tokbox_api_key}.":".$self->state->{tokbox_secret};
}
my $req = URI->new( $url );
my $ua = LWP::UserAgent->new;
$ua->timeout(3);
$ua->default_header( 'Content-type' => 'application/x-www-form-urlencoded' );
$ua->default_header( %authHeader );
warn "Post: [$url] params:".Dumper($data) if $DEBUG;
my $res = $ua->post( $req, $data );
unless ($res->code == 200) {
warn "Request failed: ".$res->status_line;
return undef;
} else {
warn "Responce: ".Dumper($res) if $DEBUG;
}
return $res->content;
}
1;