Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2020-04-07 17:27:36 +0300
committerJoas Schilling <coding@schilljs.com>2020-05-12 11:40:19 +0300
commit6ddd276dd0bc8ef91cf1724363f3f33ec38fa8f0 (patch)
tree406e7410c1570acf80f93aece4b4a71b6631d617 /lib
parent6c3b4836c49aeab07cd7c84dc25c6756e1b4d2e3 (diff)
Extend the signaling setting API to allow somewhat clustering
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Config.php43
-rw-r--r--lib/Controller/SignalingController.php107
-rw-r--r--lib/Manager.php6
-rw-r--r--lib/Migration/Version8000Date20200407115318.php39
-rw-r--r--lib/Room.php21
5 files changed, 160 insertions, 56 deletions
diff --git a/lib/Config.php b/lib/Config.php
index 0388e1028..3e63719a8 100644
--- a/lib/Config.php
+++ b/lib/Config.php
@@ -94,49 +94,6 @@ class Config {
return $this->config->getUserValue($userId, 'spreed', 'attachment_folder', '/Talk');
}
- public function getSettings(?string $userId): array {
- $stun = [];
- $stunServer = $this->getStunServer();
- if ($stunServer) {
- $stun[] = [
- 'url' => 'stun:' . $stunServer,
- ];
- }
- $turn = [];
- $turnSettings = $this->getTurnSettings();
- if (!empty($turnSettings['server'])) {
- $protocols = explode(',', $turnSettings['protocols']);
- foreach ($protocols as $proto) {
- $turn[] = [
- 'url' => ['turn:' . $turnSettings['server'] . '?transport=' . $proto],
- 'urls' => ['turn:' . $turnSettings['server'] . '?transport=' . $proto],
- 'username' => $turnSettings['username'],
- 'credential' => $turnSettings['password'],
- ];
- }
- }
-
- $signaling = [];
- $servers = $this->getSignalingServers();
- if (!empty($servers)) {
- try {
- $signaling = $servers[random_int(0, count($servers) - 1)];
- } catch (\Exception $e) {
- $signaling = $servers[0];
- }
- $signaling = $signaling['server'];
- }
-
- return [
- 'userId' => $userId,
- 'hideWarning' => !empty($signaling) || $this->getHideSignalingWarning(),
- 'server' => $signaling,
- 'ticket' => $this->getSignalingTicket($userId),
- 'stunservers' => $stun,
- 'turnservers' => $turn,
- ];
- }
-
/**
* @return string[]
*/
diff --git a/lib/Controller/SignalingController.php b/lib/Controller/SignalingController.php
index b10eaed64..09e9e536b 100644
--- a/lib/Controller/SignalingController.php
+++ b/lib/Controller/SignalingController.php
@@ -39,6 +39,9 @@ use OCP\AppFramework\OCSController;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Http\Client\IClientService;
+use OCP\ICache;
+use OCP\ICacheFactory;
+use OCP\IConfig;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\IUser;
@@ -52,7 +55,11 @@ class SignalingController extends OCSController {
public const EVENT_BACKEND_SIGNALING_ROOMS = self::class . '::signalingBackendRoom';
/** @var Config */
- private $config;
+ private $talkConfig;
+ /** @var IConfig */
+ private $serverConfig;
+ /** @var ICache */
+ private $cache;
/** @var TalkSession */
private $session;
/** @var Manager */
@@ -74,7 +81,9 @@ class SignalingController extends OCSController {
public function __construct(string $appName,
IRequest $request,
- Config $config,
+ Config $talkConfig,
+ IConfig $serverConfig,
+ ICacheFactory $cacheFactory,
TalkSession $session,
Manager $manager,
IDBConnection $connection,
@@ -85,7 +94,9 @@ class SignalingController extends OCSController {
IClientService $clientService,
?string $UserId) {
parent::__construct($appName, $request);
- $this->config = $config;
+ $this->talkConfig = $talkConfig;
+ $this->serverConfig = $serverConfig;
+ $this->cache = $cacheFactory->createDistributed('hpb_servers');
$this->session = $session;
$this->dbConnection = $connection;
$this->manager = $manager;
@@ -100,13 +111,83 @@ class SignalingController extends OCSController {
/**
* @PublicPage
*
- * Only available for logged in users because guests can not use the apps
- * right now.
- *
+ * @param string $token
* @return DataResponse
*/
- public function getSettings(): DataResponse {
- return new DataResponse($this->config->getSettings($this->userId));
+ public function getSettings(string $token = ''): DataResponse {
+ $stun = [];
+ $stunServer = $this->talkConfig->getStunServer();
+ if ($stunServer) {
+ $stun[] = [
+ 'url' => 'stun:' . $stunServer,
+ ];
+ }
+
+ $turn = [];
+ $turnSettings = $this->talkConfig->getTurnSettings();
+ if (!empty($turnSettings['server'])) {
+ $protocols = explode(',', $turnSettings['protocols']);
+ foreach ($protocols as $proto) {
+ $turn[] = [
+ 'url' => ['turn:' . $turnSettings['server'] . '?transport=' . $proto],
+ 'urls' => ['turn:' . $turnSettings['server'] . '?transport=' . $proto],
+ 'username' => $turnSettings['username'],
+ 'credential' => $turnSettings['password'],
+ ];
+ }
+ }
+
+ $signaling = '';
+ $servers = $this->talkConfig->getSignalingServers();
+ if (!empty($servers)) {
+ try {
+ $serverId = random_int(0, count($servers) - 1);
+ } catch (\Exception $e) {
+ $serverId = 0;
+ }
+ $signalingClusterMode = $this->serverConfig->getAppValue('spreed', 'hpb_cluster_mode', '');
+ if ($signalingClusterMode === 'conversation') {
+ try {
+ $serverId = $this->getSignalingServerForConversation($this->userId, $serverId, $token);
+ } catch (RoomNotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ }
+ $signaling = $servers[$serverId]['server'];
+ }
+
+ return new DataResponse([
+ 'userId' => $this->userId,
+ 'hideWarning' => $signaling !== '' || $this->talkConfig->getHideSignalingWarning(),
+ 'server' => $signaling,
+ 'ticket' => $this->talkConfig->getSignalingTicket($this->userId),
+ 'stunservers' => $stun,
+ 'turnservers' => $turn,
+ ]);
+ }
+
+ /**
+ * @param string|null $userId
+ * @param int $randomServerId
+ * @param string $token
+ * @throws RoomNotFoundException
+ * @return int
+ */
+ protected function getSignalingServerForConversation(?string $userId, int $randomServerId, string $token): int {
+ $room = $this->manager->getRoomForParticipantByToken($token, $userId);
+ $serverId = $room->getAssignedSignalingServer();
+
+ if ($serverId === null) {
+ // Avoid concurrency issues
+ $serverId = $this->cache->get($token);
+ if ($serverId === null) {
+ $this->cache->set($token, $randomServerId);
+ $serverId = $randomServerId;
+ $room->setAssignedSignalingServer($randomServerId);
+ }
+ }
+
+ return $serverId;
}
/**
@@ -117,7 +198,7 @@ class SignalingController extends OCSController {
* @return DataResponse
*/
public function getWelcomeMessage(int $serverId): DataResponse {
- $signalingServers = $this->config->getSignalingServers();
+ $signalingServers = $this->talkConfig->getSignalingServers();
if (empty($signalingServers) || !isset($signalingServers[$serverId])) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
@@ -161,7 +242,7 @@ class SignalingController extends OCSController {
* @return DataResponse
*/
public function signaling(string $token, string $messages): DataResponse {
- $signaling = $this->config->getSignalingServers();
+ $signaling = $this->talkConfig->getSignalingServers();
if (!empty($signaling)) {
return new DataResponse('Internal signaling disabled.', Http::STATUS_BAD_REQUEST);
}
@@ -207,7 +288,7 @@ class SignalingController extends OCSController {
* @return DataResponse
*/
public function pullMessages(string $token): DataResponse {
- $signaling = $this->config->getSignalingServers();
+ $signaling = $this->talkConfig->getSignalingServers();
if (!empty($signaling)) {
return new DataResponse('Internal signaling disabled.', Http::STATUS_BAD_REQUEST);
}
@@ -332,7 +413,7 @@ class SignalingController extends OCSController {
if (empty($checksum)) {
return false;
}
- $hash = hash_hmac('sha256', $random . $data, $this->config->getSignalingSecret());
+ $hash = hash_hmac('sha256', $random . $data, $this->talkConfig->getSignalingSecret());
return hash_equals($hash, strtolower($checksum));
}
@@ -394,7 +475,7 @@ class SignalingController extends OCSController {
private function backendAuth(array $auth): DataResponse {
$params = $auth['params'];
$userId = $params['userid'];
- if (!$this->config->validateSignalingTicket($userId, $params['ticket'])) {
+ if (!$this->talkConfig->validateSignalingTicket($userId, $params['ticket'])) {
return new DataResponse([
'type' => 'error',
'error' => [
diff --git a/lib/Manager.php b/lib/Manager.php
index 002afb624..f4c8bfde7 100644
--- a/lib/Manager.php
+++ b/lib/Manager.php
@@ -140,6 +140,11 @@ class Manager {
]));
}
+ $assignedSignalingServer = $row['assigned_hpb'];
+ if ($assignedSignalingServer !== null) {
+ $assignedSignalingServer = (int) $assignedSignalingServer;
+ }
+
return new Room(
$this,
$this->db,
@@ -151,6 +156,7 @@ class Manager {
(int) $row['type'],
(int) $row['read_only'],
(int) $row['lobby_state'],
+ $assignedSignalingServer,
(string) $row['token'],
(string) $row['name'],
(string) $row['password'],
diff --git a/lib/Migration/Version8000Date20200407115318.php b/lib/Migration/Version8000Date20200407115318.php
new file mode 100644
index 000000000..7764fd7c0
--- /dev/null
+++ b/lib/Migration/Version8000Date20200407115318.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OCA\Talk\Migration;
+
+use Closure;
+use Doctrine\DBAL\Types\Type;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+/**
+ * Auto-generated migration step: Please modify to your needs!
+ */
+class Version8000Date20200407115318 extends SimpleMigrationStep {
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $table = $schema->getTable('talk_rooms');
+ if (!$table->hasColumn('assigned_hpb')) {
+ $table->addColumn('assigned_hpb', Type::INTEGER, [
+ 'notnull' => false,
+ 'length' => 4,
+ 'unsigned' => false,
+ 'default' => null,
+ ]);
+ }
+
+ return $schema;
+ }
+}
diff --git a/lib/Room.php b/lib/Room.php
index 3e7d2fdd3..9ab23c51e 100644
--- a/lib/Room.php
+++ b/lib/Room.php
@@ -124,6 +124,8 @@ class Room {
private $readOnly;
/** @var int */
private $lobbyState;
+ /** @var int|null */
+ private $assignedSignalingServer;
/** @var \DateTime|null */
private $lobbyTimer;
/** @var string */
@@ -162,6 +164,7 @@ class Room {
int $type,
int $readOnly,
int $lobbyState,
+ ?int $assignedSignalingServer,
string $token,
string $name,
string $password,
@@ -183,6 +186,7 @@ class Room {
$this->type = $type;
$this->readOnly = $readOnly;
$this->lobbyState = $lobbyState;
+ $this->assignedSignalingServer = $assignedSignalingServer;
$this->token = $token;
$this->name = $name;
$this->password = $password;
@@ -224,6 +228,10 @@ class Room {
}
}
+ public function getAssignedSignalingServer(): ?int {
+ return $this->assignedSignalingServer;
+ }
+
public function getToken(): string {
return $this->token;
}
@@ -501,6 +509,19 @@ class Room {
return (bool) $query->execute();
}
+ public function setAssignedSignalingServer(?int $signalingServer): bool {
+ $query = $this->db->getQueryBuilder();
+ $query->update('talk_rooms')
+ ->set('assigned_hpb', $query->createNamedParameter($signalingServer))
+ ->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
+
+ if ($signalingServer !== null) {
+ $query->andWhere($query->expr()->isNull('assigned_hpb'));
+ }
+
+ return (bool) $query->execute();
+ }
+
/**
* @param int $newType Currently it is only allowed to change between `self::GROUP_CALL` and `self::PUBLIC_CALL`
* @return bool True when the change was valid, false otherwise