Merge pull request #2260 from nextcloud/signaling-room-properties

Get room properties for the signaling server from separate function.
This commit is contained in:
Joas Schilling 2020-03-02 16:20:00 +01:00 коммит произвёл GitHub
Родитель ecc9890fdb c5ba7b5673
Коммит 94c3b4484e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 262 добавлений и 59 удалений

Просмотреть файл

@ -195,3 +195,9 @@ Explanations:
* Event class: `OCA\Talk\Events\SignalingEvent`
* Event name: `OCA\Talk\Controller\SignalingController::EVENT_BACKEND_SIGNALING_ROOMS`
* Since: 8.0.0
### Get conversation properties for signaling
* Event class: `OCA\Talk\Events\SignalingRoomPropertiesEvent`
* Event name: `OCA\Talk\Room::EVENT_BEFORE_SIGNALING_PROPERTIES`
* Since: 8.0.5

Просмотреть файл

@ -78,10 +78,16 @@ class Listener {
});
$dispatcher->addListener(Room::EVENT_AFTER_SESSION_LEAVE_CALL, static function(ModifyParticipantEvent $event) {
$room = $event->getRoom();
if ($event->getParticipant()->getInCallFlags() === Participant::FLAG_DISCONNECTED) {
// This happens in case the user was kicked/lobbied
return;
}
/** @var self $listener */
$listener = \OC::$server->query(self::class);
$listener->sendSystemMessage($room, 'call_left');
$listener->sendSystemMessage($room, 'call_left', [], $event->getParticipant());
});
$dispatcher->addListener(Room::EVENT_AFTER_ROOM_CREATE, static function(RoomEvent $event) {
@ -239,15 +245,22 @@ class Listener {
$dispatcher->addListener(RoomShareProvider::class . '::' . 'share_file_again', $listener);
}
protected function sendSystemMessage(Room $room, string $message, array $parameters = []): void {
$user = $this->userSession->getUser();
if (!$user instanceof IUser) {
$actorType = 'guests';
$sessionId = $this->talkSession->getSessionForRoom($room->getToken());
$actorId = $sessionId ? sha1($sessionId) : 'failed-to-get-session';
protected function sendSystemMessage(Room $room, string $message, array $parameters = [], Participant $participant = null): void {
if ($participant instanceof Participant) {
$actorType = $participant->isGuest() ? 'guests' : 'users';
$sessionId = $participant->getSessionId();
$sessionHash = $sessionId ? sha1($sessionId) : 'failed-to-get-session';
$actorId = $participant->isGuest() ? $sessionHash : $participant->getUser();
} else {
$actorType = 'users';
$actorId = $user->getUID();
$user = $this->userSession->getUser();
if (!$user instanceof IUser) {
$actorType = 'guests';
$sessionId = $this->talkSession->getSessionForRoom($room->getToken());
$actorId = $sessionId ? sha1($sessionId) : 'failed-to-get-session';
} else {
$actorType = 'users';
$actorId = $user->getUID();
}
}
$this->chatManager->addSystemMessage(

Просмотреть файл

@ -102,7 +102,6 @@ class CallController extends AEnvironmentAwareController {
/**
* @PublicPage
* @RequireParticipant
* @RequireModeratorOrNoLobby
*
* @return DataResponse
*/

Просмотреть файл

@ -436,10 +436,7 @@ class SignalingController extends OCSController {
'room' => [
'version' => '1.0',
'roomid' => $room->getToken(),
'properties' => [
'name' => $room->getDisplayName((string) $userId),
'type' => $room->getType(),
],
'properties' => $room->getPropertiesForSignaling((string) $userId),
],
];
if ($event->getSession()) {

Просмотреть файл

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com>
*
* @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\Talk\Events;
use OCA\Talk\Room;
class SignalingRoomPropertiesEvent extends RoomEvent {
/** @var string|null */
protected $userId;
/** @var array */
protected $properties;
public function __construct(Room $room, ?string $userId, array $properties) {
parent::__construct($room);
$this->userId = $userId;
$this->properties = $properties;
}
public function getUserId(): ?string {
return $this->userId;
}
public function getProperties(): array {
return $this->properties;
}
public function setProperty(string $property, $data): void {
$this->properties[$property] = $data;
}
public function unsetProperty(string $property): void {
unset($this->properties[$property]);
}
}

Просмотреть файл

@ -36,6 +36,7 @@ use OCA\Talk\Events\ParticipantEvent;
use OCA\Talk\Events\RemoveParticipantEvent;
use OCA\Talk\Events\RemoveUserEvent;
use OCA\Talk\Events\RoomEvent;
use OCA\Talk\Events\SignalingRoomPropertiesEvent;
use OCA\Talk\Events\VerifyRoomPasswordEvent;
use OCA\Talk\Exceptions\InvalidPasswordException;
use OCA\Talk\Exceptions\ParticipantNotFoundException;
@ -100,6 +101,7 @@ class Room {
public const EVENT_AFTER_SESSION_JOIN_CALL = self::class . '::postSessionJoinCall';
public const EVENT_BEFORE_SESSION_LEAVE_CALL = self::class . '::preSessionLeaveCall';
public const EVENT_AFTER_SESSION_LEAVE_CALL = self::class . '::postSessionLeaveCall';
public const EVENT_BEFORE_SIGNALING_PROPERTIES = self::class . '::beforeSignalingProperties';
/** @var Manager */
private $manager;
@ -278,6 +280,27 @@ class Room {
$this->participant = $participant;
}
/**
* Return the room properties to send to the signaling server.
*
* @param string $userId
* @return array
*/
public function getPropertiesForSignaling(string $userId): array {
$properties = [
'name' => $this->getDisplayName($userId),
'type' => $this->getType(),
'lobby-state' => $this->getLobbyState(),
'lobby-timer' => $this->getLobbyTimer(),
'read-only' => $this->getReadOnly(),
'active-since' => $this->getActiveSince(),
];
$event = new SignalingRoomPropertiesEvent($this, $userId, $properties);
$this->dispatcher->dispatch(self::EVENT_BEFORE_SIGNALING_PROPERTIES, $event);
return $event->getProperties();
}
/**
* @param string|null $userId
* @return Participant
@ -597,6 +620,17 @@ class Room {
$this->dispatcher->dispatch(self::EVENT_AFTER_LOBBY_STATE_SET, $event);
if ($newState === Webinary::LOBBY_NON_MODERATORS) {
$participants = $this->getParticipantsInCall();
foreach ($participants as $participant) {
if ($participant->hasModeratorPermissions()) {
continue;
}
$this->changeInCall($participant, Participant::FLAG_DISCONNECTED);
}
}
return true;
}
@ -961,6 +995,27 @@ class Room {
return $participants;
}
/**
* @return Participant[]
*/
public function getParticipantsInCall(): array {
$query = $this->db->getQueryBuilder();
$query->select('*')
->from('talk_participants')
->where($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->neq('in_call', $query->createNamedParameter(Participant::FLAG_DISCONNECTED)));
$result = $query->execute();
$participants = [];
while ($row = $result->fetch()) {
$participants[] = $this->manager->createParticipantObject($this, $row);
}
$result->closeCursor();
return $participants;
}
/**
* @param int $lastPing When the last ping is older than the given timestamp, the user is ignored
* @return array[] Array of users with [users => [userId => [lastPing, sessionId]], guests => [[lastPing, sessionId]]]

Просмотреть файл

@ -131,10 +131,7 @@ class BackendNotifier {
// TODO(fancycode): We should try to get rid of 'alluserids' and
// find a better way to notify existing users to update the room.
'alluserids' => $room->getParticipantUserIds(),
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
],
'properties' => $room->getPropertiesForSignaling(''),
],
]);
}
@ -155,10 +152,7 @@ class BackendNotifier {
// TODO(fancycode): We should try to get rid of 'alluserids' and
// find a better way to notify existing users to update the room.
'alluserids' => $room->getParticipantUserIds(),
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
],
'properties' => $room->getPropertiesForSignaling(''),
],
]);
}
@ -179,10 +173,7 @@ class BackendNotifier {
// TODO(fancycode): We should try to get rid of 'alluserids' and
// find a better way to notify existing users to update the room.
'alluserids' => $room->getParticipantUserIds(),
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
],
'properties' => $room->getPropertiesForSignaling(''),
],
]);
}
@ -199,10 +190,7 @@ class BackendNotifier {
'type' => 'update',
'update' => [
'userids' => $room->getParticipantUserIds(),
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
],
'properties' => $room->getPropertiesForSignaling(''),
],
]);
}

Просмотреть файл

@ -155,6 +155,9 @@ export default {
},
beforeDestroy() {
if (!getCurrentUser()) {
EventBus.$off('shouldRefreshConversations', this.refreshCurrentConversation)
}
document.removeEventListener('visibilitychange', this.changeWindowVisibility)
},
@ -163,6 +166,7 @@ export default {
EventBus.$once('joinedConversation', () => {
this.fixmeDelayedSetupOfGuestUsers()
})
EventBus.$on('shouldRefreshConversations', this.refreshCurrentConversation)
}
if (this.$route.name === 'conversation') {
@ -199,7 +203,7 @@ export default {
&& !this.$store.getters.conversations[this.token]) {
if (!params.singleConversation) {
console.info('Conversations received, but the current conversation is not in the list, trying to get potential public conversation manually')
this.fetchSingleConversation(this.token)
this.refreshCurrentConversation()
} else {
console.info('Conversation received, but the current conversation is not in the list. Redirecting to /apps/spreed')
this.$router.push('/apps/spreed/not-found')
@ -278,13 +282,17 @@ export default {
fixmeDelayedSetupOfGuestUsers() {
// FIXME Refresh the data now that the user joined the conversation
// The join request returns this data already, but it's lost in the signaling code
this.fetchSingleConversation(this.token)
this.refreshCurrentConversation()
window.setInterval(() => {
this.fetchSingleConversation(this.token)
this.refreshCurrentConversation()
}, 30000)
},
refreshCurrentConversation() {
this.fetchSingleConversation(this.token)
},
changeWindowVisibility() {
this.$store.dispatch('setWindowVisibility', !document.hidden)
if (this.windowIsVisible) {

Просмотреть файл

@ -48,6 +48,18 @@ export default {
},
*/
watch: {
isInLobby: function(isInLobby) {
// User is now blocked by the lobby
if (isInLobby && this.participant.inCall !== PARTICIPANT.CALL_FLAG.DISCONNECTED) {
this.$store.dispatch('leaveCall', {
token: this.token,
participantIdentifier: this.$store.getters.getParticipantIdentifier(),
})
}
},
},
computed: {
conversation() {
return this.$store.getters.conversations[this.token]

Просмотреть файл

@ -366,10 +366,6 @@ class SignalingControllerTest extends \Test\TestCase {
->willReturn($room);
$participant = $this->createMock(Participant::class);
$room->expects($this->once())
->method('getDisplayName')
->with($this->userId)
->willReturn($roomName);
$room->expects($this->once())
->method('getParticipant')
->with($this->userId)
@ -378,8 +374,12 @@ class SignalingControllerTest extends \Test\TestCase {
->method('getToken')
->willReturn($roomToken);
$room->expects($this->once())
->method('getType')
->willReturn(Room::ONE_TO_ONE_CALL);
->method('getPropertiesForSignaling')
->with($this->userId)
->willReturn([
'name' => $roomName,
'type' => Room::ONE_TO_ONE_CALL,
]);
$result = $this->performBackendRequest([
'type' => 'room',
@ -413,10 +413,6 @@ class SignalingControllerTest extends \Test\TestCase {
->willReturn($room);
$participant = $this->createMock(Participant::class);
$room->expects($this->once())
->method('getDisplayName')
->with('')
->willReturn($roomName);
$room->expects($this->once())
->method('getParticipantBySession')
->with($sessionId)
@ -425,8 +421,12 @@ class SignalingControllerTest extends \Test\TestCase {
->method('getToken')
->willReturn($roomToken);
$room->expects($this->once())
->method('getType')
->willReturn(Room::PUBLIC_CALL);
->method('getPropertiesForSignaling')
->with('')
->willReturn([
'name' => $roomName,
'type' => Room::PUBLIC_CALL,
]);
$result = $this->performBackendRequest([
'type' => 'room',
@ -460,10 +460,6 @@ class SignalingControllerTest extends \Test\TestCase {
->willReturn($room);
$participant = $this->createMock(Participant::class);
$room->expects($this->once())
->method('getDisplayName')
->with($this->userId)
->willReturn($roomName);
$room->expects($this->once())
->method('getParticipant')
->with($this->userId)
@ -476,8 +472,12 @@ class SignalingControllerTest extends \Test\TestCase {
->method('getToken')
->willReturn($roomToken);
$room->expects($this->once())
->method('getType')
->willReturn(Room::PUBLIC_CALL);
->method('getPropertiesForSignaling')
->with($this->userId)
->willReturn([
'name' => $roomName,
'type' => Room::PUBLIC_CALL,
]);
$result = $this->performBackendRequest([
'type' => 'room',
@ -549,10 +549,6 @@ class SignalingControllerTest extends \Test\TestCase {
->willReturn($room);
$participant = $this->createMock(Participant::class);
$room->expects($this->once())
->method('getDisplayName')
->with($this->userId)
->willReturn($roomName);
$room->expects($this->once())
->method('getParticipant')
->with($this->userId)
@ -561,8 +557,12 @@ class SignalingControllerTest extends \Test\TestCase {
->method('getToken')
->willReturn($roomToken);
$room->expects($this->once())
->method('getType')
->willReturn(Room::ONE_TO_ONE_CALL);
->method('getPropertiesForSignaling')
->with($this->userId)
->willReturn([
'name' => $roomName,
'type' => Room::ONE_TO_ONE_CALL,
]);
$result = $this->performBackendRequest([
'type' => 'room',

Просмотреть файл

@ -25,6 +25,7 @@ namespace OCA\Talk\Tests\php\Signaling;
use OCA\Talk\AppInfo\Application;
use OCA\Talk\Chat\CommentsManager;
use OCA\Talk\Config;
use OCA\Talk\Events\SignalingRoomPropertiesEvent;
use OCA\Talk\Manager;
use OCA\Talk\Participant;
use OCA\Talk\Room;
@ -42,6 +43,7 @@ use OCP\IUserManager;
use OCP\Security\IHasher;
use OCP\Security\ISecureRandom;
use PHPUnit\Framework\MockObject\MockObject;
use Symfony\Component\EventDispatcher\GenericEvent;
class CustomBackendNotifier extends BackendNotifier {
@ -92,6 +94,8 @@ class BackendNotifierTest extends \Test\TestCase {
protected $app;
/** @var BackendNotifier */
protected $originalBackendNotifier;
/** @var IEventDispatcher */
private $dispatcher;
public function setUp(): void {
parent::setUp();
@ -125,7 +129,7 @@ class BackendNotifierTest extends \Test\TestCase {
});
$dbConnection = \OC::$server->getDatabaseConnection();
$dispatcher = \OC::$server->query(IEventDispatcher::class);
$this->dispatcher = \OC::$server->query(IEventDispatcher::class);
$this->manager = new Manager(
$dbConnection,
$config,
@ -133,7 +137,7 @@ class BackendNotifierTest extends \Test\TestCase {
$this->createMock(IUserManager::class),
$this->createMock(CommentsManager::class),
$this->createMock(TalkSession::class),
$dispatcher,
$this->dispatcher,
$this->timeFactory,
$this->createMock(IHasher::class),
$this->createMock(IL10N::class)
@ -200,6 +204,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
],
],
], $bodies);
@ -233,6 +241,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
],
],
], $bodies);
@ -254,6 +266,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
],
],
], $bodies);
@ -275,6 +291,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
],
],
], $bodies);
@ -296,6 +316,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
],
],
], $bodies);
@ -317,6 +341,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_ONLY,
'active-since' => null,
],
],
], $bodies);
@ -338,6 +366,10 @@ class BackendNotifierTest extends \Test\TestCase {
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NON_MODERATORS,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
],
],
], $bodies);
@ -474,4 +506,41 @@ class BackendNotifierTest extends \Test\TestCase {
], $bodies);
}
public function testRoomPropertiesEvent(): void {
$listener = static function(SignalingRoomPropertiesEvent $event) {
$room = $event->getRoom();
$event->setProperty('foo', 'bar');
$event->setProperty('room', $room->getToken());
};
$this->dispatcher->addListener(Room::EVENT_BEFORE_SIGNALING_PROPERTIES, $listener);
$room = $this->manager->createPublicRoom();
$this->controller->clearRequests();
$room->setName('Test room');
$requests = $this->controller->getRequests();
$bodies = array_map(function($request) use ($room) {
return json_decode($this->validateBackendRequest($this->baseUrl . '/api/v1/room/' . $room->getToken(), $request), true);
}, $requests);
$this->assertContains([
'type' => 'update',
'update' => [
'userids' => [
],
'properties' => [
'name' => $room->getDisplayName(''),
'type' => $room->getType(),
'lobby-state' => Webinary::LOBBY_NONE,
'lobby-timer' => null,
'read-only' => Room::READ_WRITE,
'active-since' => null,
'foo' => 'bar',
'room' => $room->getToken(),
],
],
], $bodies);
}
}