diff --git a/docs/schema.mysql b/docs/schema.mysql index a3b9c70..a73fcb5 100644 --- a/docs/schema.mysql +++ b/docs/schema.mysql @@ -20,6 +20,8 @@ DROP TABLE IF EXISTS `participants`; CREATE TABLE `participants` ( `id` int(11) NOT NULL, `participant` varchar(60) NOT NULL, + `peer_id` varchar(40) DEFAULT NULL, + `role` varchar(20) DEFAULT 'participant', PRIMARY KEY (`id`,`participant`) ); #DROP TABLE IF EXISTS `turnusers_lt`; diff --git a/docs/upgrade.mysql b/docs/upgrade.mysql index bc071b8..8dbed04 100644 --- a/docs/upgrade.mysql +++ b/docs/upgrade.mysql @@ -1 +1,3 @@ -ALTER TABLE rooms add COLUMN `owner_password` varchar(160) DEFAULT NULL after `join_password`; +ALTER TABLE `rooms` ADD COLUMN `owner_password` varchar(160) DEFAULT NULL AFTER `join_password`; +ALTER TABLE `participants` ADD COLUMN `peer_id` varchar(40) DEFAULT NULL AFTER `participant`; +ALTER TABLE `participants` ADD COLUMN `role` varchar(20) DEFAULT 'participant' AFTER `peer_id`; diff --git a/public/css/vroom.css b/public/css/vroom.css index dc97d8c..d0a0c9c 100644 --- a/public/css/vroom.css +++ b/public/css/vroom.css @@ -53,7 +53,18 @@ font-family: 'Glyphicons Halflings'; color: red; font-size: 2em; - content: "\e106";; + content: "\e106"; +} +.owner{ + position: absolute; + left: 20px; + top: 0px; +} +.owner:before{ + font-family: 'Glyphicons Halflings'; + color: red; + font-size: 2em; + content: "\e124";; } .displayName { text-align: center; diff --git a/public/js/vroom.js b/public/js/vroom.js index 761f81f..53cd70e 100644 --- a/public/js/vroom.js +++ b/public/js/vroom.js @@ -114,16 +114,21 @@ function initVroom(room) { } // Update our role - function updateRole() { + function updateRole(){ $.ajax({ data: { - action: 'getRole', - room: roomName + action: 'getRoomInfo', + room: roomName, + id: peers.local.id }, - error: function(data) { + error: function(data){ $.notify(locale.ERROR_OCCURED, 'error'); }, - success: function(data) { + success: function(data){ + // Notify others if our role changed + if (data.role != peers.local.role){ + webrtc.sendToAll('role_change', {}); + } peers.local.role = data.role; // Enable owner reserved menu if (data.role == 'owner'){ @@ -144,6 +149,29 @@ function initVroom(room) { }); } + // Get the role of a peer + function getPeerRole(id){ + $.ajax({ + data: { + action: 'getPeerRole', + room: roomName, + id: id + }, + error: function(data){ + $.notify(locale.ERROR_OCCURED, 'error'); + }, + success: function(data){ + peers[id].role = data.role; + if (data.role == 'owner'){ + $("#overlay_" + id).append('
'); + } + else{ + $('#owner_' + id).remove(); + } + } + }); + } + // Select a color (randomly) from this list, used for text chat function chooseColor(){ // Shamelessly taken from http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ @@ -233,6 +261,8 @@ function initVroom(room) { if(!peers.local.hasHistory && chatIndex == 0){ peer.sendDirectly('vroom', 'getHistory', ''); } + // Get the role of this peer + getPeerRole(peer.id); }, 3500); } $(div).attr('id', 'peer_' + id); @@ -446,6 +476,12 @@ function initVroom(room) { $("#overlay_" + data.id).append('
'); }); + // This peer claims he changed its role (usually from participant to owner) + // Lets check this + webrtc.on('role_change', function(data){ + getPeerRole(data.id); + }); + // Handle unmute/resume webrtc.on('unmute', function(data){ if (data.name === 'audio'){ @@ -494,6 +530,7 @@ function initVroom(room) { // Handle the readyToCall event: join the room webrtc.once('readyToCall', function () { peers.local.id = webrtc.connection.socket.sessionid; + updateRole(); webrtc.joinRoom(room); }); @@ -940,9 +977,6 @@ function initVroom(room) { } }); - // Check if we are the owner of the room - updateRole(); - // Ping the room every minutes // Used to detect inactive rooms setInterval(function pingRoom(){ diff --git a/public/vroom.pl b/public/vroom.pl index c31e20f..8c498f5 100755 --- a/public/vroom.pl +++ b/public/vroom.pl @@ -193,6 +193,34 @@ helper get_participants => sub { return @res; }; +# Set the role of a peer +helper set_peer_role => sub { + my $self = shift; + my ($room,$name,$id,$role) = @_; + # Check if this ID isn't the one from another peer first + my $sth = eval { $self->db->prepare("SELECT * FROM participants WHERE peer_id=? AND participant!=? AND id IN (SELECT id FROM rooms WHERE name=?)") } || return undef; + $sth->execute($id,$name,$room) || return undef; + return undef if ($sth->rows > 0); + $sth = eval { $self->db->prepare("UPDATE participants SET peer_id=?,role=? WHERE participant=? AND id IN (SELECT id FROM rooms WHERE name=?)") } || return undef; + $sth->execute($id,$role,$name,$room) || return undef; + return 1; +}; + +# Return the role of a peer, from it's signaling ID +helper get_peer_role => sub { + my $self = shift; + my ($room,$id) = @_; + my $sth = eval { $self->db->prepare("SELECT role from participants WHERE peer_id=? AND id IN (SELECT id FROM rooms WHERE name=?)") } || return undef; + $sth->execute($id,$room) || return undef; + if ($sth->rows == 1){ + my ($role) = $sth->fetchrow_array(); + return $role; + } + else{ + return 'participant'; + } +}; + # Check if a participant has joined a room # Takes two args: the session name, and the room name helper has_joined => sub { @@ -682,17 +710,33 @@ post '/action' => sub { ); } # Return your role and various info about the room - elsif ($action eq 'getRole'){ + elsif ($action eq 'getRoomInfo'){ + my $id = $self->param('id'); + my $res = 'error'; + if ($self->session($room) && $self->session($room)->{role}){ + $res = ($self->set_peer_role($room,$self->session('name'),$id, $self->session($room)->{role})) ? 'success':$res; + } return $self->render( json => { role => $self->session($room)->{role}, owner_auth => ($data->{owner_password}) ? 'yes' : 'no', join_auth => ($data->{join_password}) ? 'yes' : 'no', locked => ($data->{locked}) ? 'yes' : 'no' , - status => 'success' + status => $res }, ); } + # Return the role of a peer + elsif ($action eq 'getPeerRole'){ + my $id = $self->param('id'); + my $role = $self->get_peer_role($room,$id); + return $self->render( + json => { + role => $role, + status => 'success' + } + ); + } }; # use the templates defined in the config