Revision 332

Date:
2013/05/03 13:35:48
Author:
ahitrov
Revision Log:
TokBox Plugin
Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/tokbox/comps/contenido/tokbox/autohandler

     
    1 <%init>
    2
    3 $r->content_type('text/html');
    4 $m->call_next();
    5
    6 </%init>
  • utf8/plugins/tokbox/comps/contenido/tokbox/dhandler

     
    1 <& $call, %ARGS &>
    2 <%init>
    3
    4 my $call;
    5 if ( $r->uri eq '/contenido/tokbox/' ) {
    6 $call = 'index.html';
    7 } else {
    8 &abort404;
    9 }
    10
    11 </%init>
  • utf8/plugins/tokbox/comps/contenido/tokbox/index.html

     
    1 <& "/contenido/components/header.msn" &>
    2 <& "/contenido/components/naviline.msn" &>
    3
    4 <p>PLugin [tokbox]</p>
    5
    6 </body>
    7 </html>
  • utf8/plugins/tokbox/config.proto

     
    1 #############################################################################
    2 #
    3 # Параметры данного шаблона необходимо ВРУЧНУЮ добавить в config.mk проекта
    4 # и привести в соответствие с требованиями проекта
    5 #
    6 #############################################################################
    7 PLUGINS += tokbox
    8
    9 TOKBOX_API_KEY =
    10 TOKBOX_SECRET =
    11
    12 REWRITE += TOKBOX_API_KEY TOKBOX_SECRET
  • utf8/plugins/tokbox/lib/tokbox/Apache.pm

     
    1 package tokbox::Apache;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use tokbox::State;
    7 use Contenido::Globals;
    8
    9
    10 sub child_init {
    11 # встраиваем keeper плагина в keeper проекта
    12 $keeper->{tokbox} = tokbox::Keeper->new($state->tokbox);
    13 }
    14
    15 sub request_init {
    16 }
    17
    18 sub child_exit {
    19 }
    20
    21 1;
  • utf8/plugins/tokbox/lib/tokbox/Init.pm

     
    1 package tokbox::Init;
    2
    3 use strict;
    4 use warnings 'all';
    5
    6 use Contenido::Globals;
    7 use tokbox::Apache;
    8 use tokbox::Keeper;
    9 use tokbox::Session;
    10
    11
    12 # загрузка всех необходимых плагину классов
    13 # tokbox::SQL::SomeTable
    14 # tokbox::SomeClass
    15 Contenido::Init::load_classes(qw(
    16 ));
    17
    18 sub init {
    19 0;
    20 }
    21
    22 1;
  • utf8/plugins/tokbox/lib/tokbox/Keeper.pm

     
    1 package tokbox::Keeper;
    2
    3 use strict;
    4 use warnings 'all';
    5 use Time::HiRes;
    6 use MIME::Base64;
    7 use Digest::SHA1 qw(sha1 sha1_hex);
    8 use LWP::UserAgent;
    9 use URI;
    10 use Data::Dumper;
    11 use XML::Fast;
    12
    13 use base qw(Contenido::Keeper);
    14
    15 use Contenido::Globals;
    16
    17 our $SUBSCRIBER = "subscriber";
    18 our $PUBLISHER = "publisher";
    19 our $MODERATOR = "moderator";
    20
    21 sub OpenTokSession {
    22 my ($self, $sessionId, $properties) = @_;
    23 return tokbox::Session->new( sessionId => $sessionId, properties => $properties );
    24 }
    25
    26
    27 ### - Generate a token
    28 #
    29 # session_id - If session_id is not blank, this token can only join the call with the specified session_id.
    30 # role - One of the constants defined in RoleConstants. Default is publisher, look in the documentation to learn more about roles.
    31 # expire_time - Optional timestamp to change when the token expires. See documentation on token for details.
    32 # connection_data - Optional string data to pass into the stream. See documentation on token for details.
    33 #
    34 ##########################################################################################################
    35 sub generateToken {
    36 my ($self, %opts) = @_;
    37
    38 my $session_id = delete $opts{session_id} || '';
    39 my $role = delete $opts{role} || '';
    40 my $expire_time = delete $opts{expire_time};
    41 my $connection_data = delete $opts{connection_data} || '';
    42
    43 my $create_time = time;
    44 my $nonce = gettimeofday() . rand();
    45
    46 if ( !$role ) {
    47 $role = $PUBLISHER;
    48 } elsif ( $role ne $SUBSCRIBER && $role ne $PUBLISHER && $role ne $MODERATOR ) {
    49 warn "unknown role $role\n";
    50 return;
    51 }
    52 my $data_string = "session_id=$session_id&create_time=$create_time&role=$role&nonce=$nonce";
    53 if ( defined $expire_time ) {
    54 if ( $expire_time =~ /\D/ ) {
    55 warn "Expire time must be a number\n";
    56 return;
    57 } elsif ( $expire_time < $create_time ) {
    58 warn "Expire time must be in the future\n";
    59 return;
    60 } elsif ( $expire_time > $create_time + 2592000 ) {
    61 warn "Expire time must be in the next 30 days\n";
    62 return;
    63 }
    64 $data_string .= "&expire_time=$expire_time";
    65 }
    66 if ( $connection_data ) {
    67 if ( length $connection_data > 1000 ) {
    68 warn "Connection data must be less than 1000 characters\n";
    69 return;
    70 }
    71 $data_string .= "&connection_data=" . Utils::HTML::url_escape($connection_data);
    72 }
    73 my $sig = $self->_sign_string($data_string, $self->state->{tokbox_secret});
    74 my $api_key = $self->state->{tokbox_api_key};
    75
    76 return "T1==" . encode_base64("partner_id=$api_key&sig=$sig:$data_string");
    77 }
    78
    79
    80 ###
    81 #
    82 # Creates a new session.
    83 # location - IP address to geolocate the call around.
    84 # properties - Optional array, keys are defined in SessionPropertyConstants
    85 #
    86 ###################################################################################
    87 sub createSession {
    88 my ($self, %opts) = @_;
    89
    90 my $location = delete $opts{location} || '';
    91 my $properties = delete $opts{properties} || {};
    92 $properties->{"location"} = $location;
    93 $properties->{"api_key"} = $self->state->{tokbox_api_key};
    94
    95 my $createSessionResult = $self->_do_request("/session/create", $properties);
    96 return unless $createSessionResult;
    97 my $createSessionXML = xml2hash ($createSessionResult);
    98 unless ( ref $createSessionXML ) {
    99 warn "Failed to create session: Invalid response from server\n";
    100 return;
    101 }
    102
    103 unless( exists $createSessionXML->{sessions}{Session}{session_id} ) {
    104 warn "Failed to create session.\n";
    105 warn Dumper $createSessionXML;
    106 return;
    107 }
    108 my $sessionId = $createSessionXML->{sessions}{Session}{session_id};
    109
    110 return $self->OpenTokSession( $sessionId );
    111 }
    112
    113
    114
    115 ########################################################
    116 # Inner functions
    117 ########################################################
    118 sub _sign_string {
    119 my ($self, $string, $secret) = @_;
    120 return sha1_hex($string, $secret);
    121 }
    122
    123 sub _do_request {
    124 my ($self, $url, $data, $auth) = @_;
    125
    126 $auth = {} unless ref $auth;
    127 $auth->{'type'} = 'partner' unless exists $auth->{type};
    128
    129 $url = $self->state->{tokbox_server} . $url;
    130
    131 my %authHeader;
    132 if ( $auth->{type} eq 'token' ) {
    133 $authHeader{"X-TB-TOKEN-AUTH"} = $auth->{'token'};
    134 } else {
    135 $authHeader{"X-TB-PARTNER-AUTH"} = $self->state->{tokbox_api_key}.":".$self->state->{tokbox_secret};
    136 }
    137
    138 my $req = URI->new( $url );
    139 my $ua = LWP::UserAgent->new;
    140 $ua->timeout(3);
    141 $ua->default_header( 'Content-type' => 'application/x-www-form-urlencoded' );
    142 $ua->default_header( %authHeader );
    143 warn "Post: [$url] params:".Dumper($data) if $DEBUG;
    144 my $res = $ua->post( $req, $data );
    145 unless ($res->code == 200) {
    146 warn "Request failed: ".$res->status_line;
    147 return undef;
    148 } else {
    149 warn "Responce: ".Dumper($res) if $DEBUG;
    150 }
    151 return $res->content;
    152 }
    153
    154
    155 1;
  • utf8/plugins/tokbox/lib/tokbox/Session.pm

     
    1 package tokbox::Session;
    2
    3 use strict;
    4 use warnings 'all';
    5 use Contenido::Globals;
    6 use tokbox::Keeper;
    7
    8 our $P2P_PREFERENCE = 'p2p.preference';
    9
    10 sub new {
    11 my ($proto, %params) = @_;
    12 my $class = ref($proto) || $proto;
    13 my $self = {};
    14 bless $self, $class;
    15
    16 $self->{sessionId} = $params{sessionId} || '';
    17 $self->{sessionProperties} = $params{properties};
    18
    19 return $self;
    20 }
    21
    22
    23 sub sessionId {
    24 my $self = shift;
    25 return exists $self->{sessionId} && $self->{sessionId} ? $self->{sessionId} : undef;
    26 }
    27
    28 sub sessionProperties {
    29 my $self = shift;
    30 return exists $self->{sessionProperties} && $self->{sessionProperties} ? $self->{sessionProperties} : undef;
    31 }
    32
    33 sub getSessionId {
    34 my $self = shift;
    35 return $self->sessionId;
    36 }
    37
    38 sub id {
    39 my $self = shift;
    40 return $self->sessionId;
    41 }
    42
    43 1;
  • utf8/plugins/tokbox/lib/tokbox/State.pm.proto

     
    1 package tokbox::State;
    2
    3 use strict;
    4 use warnings 'all';
    5 use vars qw($AUTOLOAD);
    6
    7
    8 sub new {
    9 my ($proto) = @_;
    10 my $class = ref($proto) || $proto;
    11 my $self = {};
    12 bless $self, $class;
    13
    14 # configured
    15 $self->{debug} = (lc('') eq 'yes');
    16 $self->{project} = '';
    17
    18 # зашитая конфигурация плагина
    19 $self->{db_type} = 'none'; ### For REAL database use 'remote'
    20 $self->{db_keepalive} = 0;
    21 $self->{db_host} = '';
    22 $self->{db_name} = '';
    23 $self->{db_user} = '';
    24 $self->{db_password} = '';
    25 $self->{db_port} = '';
    26 $self->{store_method} = 'toast';
    27 $self->{cascade} = 1;
    28 $self->{db_prepare} = 0;
    29
    30 $self->{memcached_enable} = lc( '' ) eq 'yes' ? 1 : 0;
    31 $self->{memcached_enable_compress} = 1;
    32 $self->{memcached_backend} = '';
    33 $self->{memcached_servers} = [qw()];
    34 $self->{memcached_busy_lock} = 60;
    35 $self->{memcached_delayed} = lc('') eq 'yes' ? 1 : 0;
    36
    37 $self->{serialize_with} = 'json'; ### or 'dumper'
    38
    39 # not implemented really (core compatibility)
    40 $self->{binary_directory} = '/nonexistent';
    41 $self->{data_directory} = '/nonexistent';
    42 $self->{images_directory} = '/nonexistent';
    43 $self->{preview} = '0';
    44
    45 $self->{tokbox_api_key} = '@TOKBOX_API_KEY@';
    46 $self->{tokbox_secret} = '@TOKBOX_SECRET@';
    47 $self->{tokbox_server} = 'http://api.opentok.com/hl';
    48
    49 $self->_init_();
    50 $self;
    51 }
    52
    53 sub info {
    54 my $self = shift;
    55 return unless ref $self;
    56
    57 for (sort keys %{$self->{attributes}}) {
    58 my $la = length $_;
    59 warn "\t$_".("\t" x (2-int($la/8))).": $self->{$_}\n";
    60 }
    61 }
    62
    63 sub _init_ {
    64 my $self = shift;
    65
    66 # зашитая конфигурация плагина
    67 $self->{attributes}->{$_} = 'SCALAR' for qw(
    68 debug
    69 project
    70
    71 db_type
    72 db_keepalive
    73 db_host
    74 db_port
    75 db_name
    76 db_user
    77 db_password
    78 store_method
    79 cascade
    80 db_prepare
    81 db_client_encoding
    82
    83 memcached_enable
    84 memcached_enable_compress
    85 memcached_backend
    86 memcached_servers
    87 memcached_busy_lock
    88 memcached_delayed
    89
    90 binary_directory
    91 data_directory
    92 images_directory
    93 preview
    94 );
    95 }
    96
    97 sub AUTOLOAD {
    98 my $self = shift;
    99 my $attribute = $AUTOLOAD;
    100
    101 $attribute =~ s/.*:://;
    102 return unless $attribute =~ /[^A-Z]/; # Отключаем методы типа DESTROY
    103
    104 if (!exists $self->{attributes}->{$attribute}) {
    105 warn "Contenido Error (tokbox::State): Вызов метода, для которого не существует обрабатываемого свойства: ->$attribute()\n";
    106 return;
    107 }
    108
    109 $self->{$attribute} = shift @_ if $#_>=0;
    110 $self->{$attribute};
    111 }
    112
    113 1;

Небольшая справка по веткам

cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.

koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.

utf8 – актуальная ветка, заточенная под UTF-8.

Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.