Browse Source
Implement backend APIs to be used by standalone signaling server.
Implement backend APIs to be used by standalone signaling server.
A standalone signaling server can be configured in the admin UI and is notified through the BackendController on changes that should be sent to connected clients. See #339 for a description of the backend API. Signed-off-by: Joachim Bauch <bauch@struktur.de>pull/366/head
Failed to extract signature
10 changed files with 595 additions and 3 deletions
-
1appinfo/info.xml
-
8appinfo/routes.php
-
43js/admin/signaling-server.js
-
82lib/Config.php
-
183lib/Controller/BackendController.php
-
12lib/Controller/PageController.php
-
23lib/Controller/RoomController.php
-
154lib/Controller/SignalingController.php
-
68lib/Settings/Admin/SignalingServer.php
-
24templates/settings/admin/signaling-server.php
@ -0,0 +1,43 @@ |
|||
/* global OC, OCP, OCA, $, _, Handlebars */ |
|||
|
|||
(function(OC, OCP, OCA, $) { |
|||
'use strict'; |
|||
|
|||
OCA.VideoCalls = OCA.VideoCalls || {}; |
|||
OCA.VideoCalls.Admin = OCA.VideoCalls.Admin || {}; |
|||
OCA.VideoCalls.Admin.SignalingServer = { |
|||
|
|||
$signaling: undefined, |
|||
|
|||
init: function() { |
|||
this.$signaling = $('div.signaling-server'); |
|||
this.$signaling.find('input').on('change', this.saveServer); |
|||
}, |
|||
|
|||
saveServer: function() { |
|||
// this.$signaling.find('input').removeClass('error');
|
|||
// this.$signaling.find('.icon-checkmark-color').addClass('hidden');
|
|||
|
|||
// OCP.AppConfig.setValue('spreed', $(this).attr('name'), $(this).value, {
|
|||
// success: function() {
|
|||
// self.temporaryShowSuccess($server);
|
|||
// }
|
|||
// });
|
|||
}, |
|||
|
|||
temporaryShowSuccess: function($server) { |
|||
var $icon = $server.find('.icon-checkmark-color'); |
|||
$icon.removeClass('hidden'); |
|||
setTimeout(function() { |
|||
$icon.addClass('hidden'); |
|||
}, 2000); |
|||
} |
|||
|
|||
}; |
|||
|
|||
|
|||
})(OC, OCP, OCA, $); |
|||
|
|||
$(document).ready(function(){ |
|||
OCA.VideoCalls.Admin.SignalingServer.init(); |
|||
}); |
|||
@ -0,0 +1,183 @@ |
|||
<?php |
|||
/** |
|||
* @copyright Copyright (c) 2017 Joachim Bauch <bauch@struktur.de> |
|||
* |
|||
* @author Joachim Bauch <bauch@struktur.de> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Spreed\Controller; |
|||
|
|||
use OCA\Spreed\Config; |
|||
use OCA\Spreed\Room; |
|||
use OCP\AppFramework\Controller; |
|||
use OCP\Http\Client\IClientService; |
|||
use OCP\ILogger; |
|||
use OCP\IRequest; |
|||
use OCP\Security\ISecureRandom; |
|||
|
|||
class BackendController extends Controller { |
|||
/** @var Config */ |
|||
private $config; |
|||
/** @var ILogger */ |
|||
private $logger; |
|||
/** @var IClientService */ |
|||
private $clientService; |
|||
/** @var ISecureRandom */ |
|||
private $secureRandom; |
|||
|
|||
/** |
|||
* @param string $appName |
|||
* @param IRequest $request |
|||
* @param IConfig $config |
|||
* @param ILogger $logger |
|||
* @param IClientService $clientService |
|||
*/ |
|||
public function __construct($appName, |
|||
IRequest $request, |
|||
Config $config, |
|||
ILogger $logger, |
|||
IClientService $clientService, |
|||
ISecureRandom $secureRandom) { |
|||
parent::__construct($appName, $request); |
|||
$this->config = $config; |
|||
$this->logger = $logger; |
|||
$this->clientService = $clientService; |
|||
$this->secureRandom = $secureRandom; |
|||
} |
|||
|
|||
/** |
|||
* Perform a request to the signaling backend. |
|||
* |
|||
* @param string $url |
|||
* @param array $data |
|||
*/ |
|||
private function backendRequest($url, $data) { |
|||
$signaling = $this->config->getSignalingServer(); |
|||
if (empty($signaling)) { |
|||
return; |
|||
} |
|||
|
|||
if (substr($signaling, -1) === '/') { |
|||
$signaling = substr($signaling, 0, strlen($signaling) - 1); |
|||
} |
|||
$url = $signaling . $url; |
|||
if (substr($url, 0, 6) === 'wss://') { |
|||
$url = 'https://' . substr($url, 6); |
|||
} else if (substr($url, 0, 5) === 'ws://') { |
|||
$url = 'http://' . substr($url, 5); |
|||
} |
|||
$client = $this->clientService->newClient(); |
|||
$body = json_encode($data); |
|||
$headers = [ |
|||
'Content-Type' => 'application/json', |
|||
]; |
|||
|
|||
$random = $this->secureRandom->generate(64); |
|||
$hash = hash_hmac('sha256', $random . $body, $this->config->getSignalingSecret()); |
|||
$headers['Spreed-Signaling-Random'] = $random; |
|||
$headers['Spreed-Signaling-Checksum'] = $hash; |
|||
|
|||
$response = $client->post($url, [ |
|||
'headers' => $headers, |
|||
'body' => $body, |
|||
'verify' => false, |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* The given users are now invited to a room. |
|||
* |
|||
* @param Room $room |
|||
* @param array $userIds |
|||
*/ |
|||
public function roomInvited($room, $userIds) { |
|||
$this->logger->info("Now invited to " . $room->getToken() . ": " + print_r($userIds, true)); |
|||
$this->backendRequest('/api/v1/room/' . $room->getToken(), [ |
|||
'type' => 'invite', |
|||
'invite' => [ |
|||
'userids' => $userIds, |
|||
'properties' => [ |
|||
'name' => $room->getName(), |
|||
'type' => $room->getType(), |
|||
], |
|||
], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* The given users are no longer invited to a room. |
|||
* |
|||
* @param Room $room |
|||
* @param array $userIds |
|||
*/ |
|||
public function roomsDisinvited($room, $userIds) { |
|||
$this->logger->info("No longer invited to " . $room->getToken() . ": " + print_r($userIds, true)); |
|||
$this->backendRequest('/api/v1/room/' . $room->getToken(), [ |
|||
'type' => 'disinvite', |
|||
'disinvite' => [ |
|||
'userids' => $userIds, |
|||
], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* The given room has been modified. |
|||
* |
|||
* @param Room $room |
|||
*/ |
|||
public function roomModified($room) { |
|||
$this->logger->info("Room modified: " . $room->getToken()); |
|||
$participants = $room->getParticipants(); |
|||
$userIds = []; |
|||
foreach ($participants['users'] as $participant => $data) { |
|||
array_push($userIds, $participant); |
|||
} |
|||
$this->backendRequest('/api/v1/room/' . $room->getToken(), [ |
|||
'type' => 'update', |
|||
'update' => [ |
|||
'userids' => $userIds, |
|||
'properties' => [ |
|||
'name' => $room->getName(), |
|||
'type' => $room->getType(), |
|||
], |
|||
], |
|||
]); |
|||
} |
|||
|
|||
/** |
|||
* The given room has been deleted. |
|||
* |
|||
* @param Room $room |
|||
*/ |
|||
public function roomDeleted($room) { |
|||
$this->logger->info("Room deleted: " . $room->getToken()); |
|||
$participants = $room->getParticipants(); |
|||
$userIds = []; |
|||
foreach ($participants['users'] as $participant => $data) { |
|||
array_push($userIds, $participant); |
|||
} |
|||
$this->backendRequest('/api/v1/room/' . $room->getToken(), [ |
|||
'type' => 'delete', |
|||
'delete' => [ |
|||
'userids' => $userIds, |
|||
], |
|||
]); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,68 @@ |
|||
<?php |
|||
/** |
|||
* @author Joachim Bauch <mail@joachim-bauch.de> |
|||
* |
|||
* @license GNU AGPL version 3 or any later version |
|||
* |
|||
* This program is free software: you can redistribute it and/or modify |
|||
* it under the terms of the GNU Affero General Public License as |
|||
* published by the Free Software Foundation, either version 3 of the |
|||
* License, or (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
* GNU Affero General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU Affero General Public License |
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|||
* |
|||
*/ |
|||
|
|||
namespace OCA\Spreed\Settings\Admin; |
|||
|
|||
|
|||
use OCP\AppFramework\Http\TemplateResponse; |
|||
use OCP\IConfig; |
|||
use OCP\Settings\ISettings; |
|||
|
|||
class SignalingServer implements ISettings { |
|||
|
|||
/** @var IConfig */ |
|||
private $config; |
|||
|
|||
public function __construct(IConfig $config) { |
|||
$this->config = $config; |
|||
} |
|||
|
|||
/** |
|||
* @return TemplateResponse |
|||
*/ |
|||
public function getForm() { |
|||
$parameters = [ |
|||
'signalingServer' => $this->config->getAppValue('spreed', 'signaling_server'), |
|||
'signalingSecret' => $this->config->getAppValue('spreed', 'signaling_secret'), |
|||
]; |
|||
|
|||
return new TemplateResponse('spreed', 'settings/admin/signaling-server', $parameters, ''); |
|||
} |
|||
|
|||
/** |
|||
* @return string the section ID, e.g. 'sharing' |
|||
*/ |
|||
public function getSection() { |
|||
return 'videocalls'; |
|||
} |
|||
|
|||
/** |
|||
* @return int whether the form should be rather on the top or bottom of |
|||
* the admin section. The forms are arranged in ascending order of the |
|||
* priority values. It is required to return a value between 0 and 100. |
|||
* |
|||
* E.g.: 70 |
|||
*/ |
|||
public function getPriority() { |
|||
return 75; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
<?php |
|||
/** @var array $_ */ |
|||
/** @var \OCP\IL10N $l */ |
|||
script('spreed', ['admin/signaling-server']); |
|||
style('spreed', ['settings-admin']); |
|||
?>
|
|||
|
|||
<div class="videocalls section signaling-server"> |
|||
<h3><?php p($l->t('Signaling server')) ?></h3>
|
|||
<p class="settings-hint"><?php p($l->t('An external signaling server can optionally be used for larger installations. Leave empty to use the internal signaling server.')) ?></p>
|
|||
|
|||
<p> |
|||
<label for="signaling_server"><?php p($l->t('External signaling server')) ?></label>
|
|||
<input type="text" id="signaling_server" |
|||
name="signaling_server" placeholder="wss://signaling.example.org" |
|||
value="<?php p($_['signalingServer']) ?>" /> |
|||
</p> |
|||
<p> |
|||
<label for="signaling_secret"><?php p($l->t('Shared secret')) ?></label>
|
|||
<input type="text" id="signaling_secret" |
|||
name="signaling_secret" placeholder="shared secret" |
|||
value="<?php p($_['signalingSecret']) ?>" /> |
|||
</p> |
|||
</div> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue