Merge pull request #363 from nextcloud/long-polling

Use an OCS controller and long polling instead of event sources
This commit is contained in:
Ivan Sein 2017-09-26 11:30:42 +02:00 коммит произвёл GitHub
Родитель 8be4d99321 4f9207b389
Коммит 8e7b8320ce
14 изменённых файлов: 340 добавлений и 191 удалений

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

@ -19,6 +19,9 @@
*
*/
$app = new \OCA\Spreed\AppInfo\Application();
$app->registerHooks();
// For the navigation $l->t('Video calls')
$manager = \OC::$server->getNotificationManager();

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

@ -28,16 +28,6 @@ return [
'url' => '/',
'verb' => 'GET',
],
[
'name' => 'Signalling#signalling',
'url' => '/signalling',
'verb' => 'POST',
],
[
'name' => 'Signalling#pullMessages',
'url' => '/messages',
'verb' => 'GET',
],
[
'name' => 'AppSettings#setSpreedSettings',
'url' => '/settings/admin',
@ -45,6 +35,22 @@ return [
],
],
'ocs' => [
[
'name' => 'Signaling#signaling',
'url' => '/api/{apiVersion}/signaling',
'verb' => 'POST',
'requirements' => [
'apiVersion' => 'v1',
],
],
[
'name' => 'Signaling#pullMessages',
'url' => '/api/{apiVersion}/signaling',
'verb' => 'GET',
'requirements' => [
'apiVersion' => 'v1',
],
],
[
'name' => 'Call#getPeersForCall',
'url' => '/api/{apiVersion}/call/{token}',

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

@ -23,7 +23,7 @@
* [Join a call](#join-a-call)
* [Send ping to keep the call alive](#send-ping-to-keep-the-call-alive)
* [Leave a call (but staying in the room for future calls)](#leave-a-call--but-staying-in-the-room-for-future-calls-)
- [Signalling](#signalling)
- [Signaling](#signaling)
Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
@ -351,6 +351,6 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
+ `200 OK`
+ `404 Not Found` When the room could not be found for the participant
## Signalling
## Signaling
To be defined
See the [Draft](https://github.com/nextcloud/spreed/wiki/Signaling-API) in the wiki…

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

@ -96,6 +96,7 @@
this.pingFails = 0;
this.pingInterval = null;
this.isSendingMessages = false;
this.sendInterval = window.setInterval(function(){
this.sendPendingMessages();
@ -149,11 +150,32 @@
var message = [{
ev: ev
}];
$.post(OC.generateUrl('/apps/spreed/signalling'), {
messages: JSON.stringify(message)
}, function(data) {
this._trigger(ev, [data]);
}.bind(this));
this._sendMessages(message).done(function(result) {
this._trigger(ev, [result.ocs.data]);
}.bind(this)).fail(function(/*xhr, textStatus, errorThrown*/) {
console.log('Sending signaling message with callback has failed.');
// TODO: Add error handling
});
};
InternalSignaling.prototype._sendMessages = function(messages) {
var defer = $.Deferred();
$.ajax({
url: OC.linkToOCS('apps/spreed/api/v1', 2) + 'signaling',
type: 'POST',
data: {messages: JSON.stringify(messages)},
beforeSend: function (request) {
request.setRequestHeader('Accept', 'application/json');
},
success: function (result) {
defer.resolve(result);
},
error: function (xhr, textStatus, errorThrown) {
defer.reject(xhr, textStatus, errorThrown);
}
});
return defer;
};
InternalSignaling.prototype.joinCall = function(token, callback, password) {
@ -165,7 +187,7 @@
// 3. Pass information about the clients that need to be called by you to the callback.
//
// The clients will then use the message command to exchange
// their signalling information.
// their signaling information.
$.ajax({
url: OC.linkToOCS('apps/spreed/api/v1/call', 2) + token,
type: 'POST',
@ -180,7 +202,7 @@
this.sessionId = result.ocs.data.sessionId;
this.currentCallToken = token;
this._startPingCall();
this._openEventSource();
this._startPullingMessages();
this._getCallPeers(token).then(function(peers) {
var callDescription = {
'clients': {}
@ -288,27 +310,41 @@
/**
* @private
*/
InternalSignaling.prototype._openEventSource = function() {
InternalSignaling.prototype._startPullingMessages = function() {
// Connect to the messages endpoint and pull for new messages
this.source = new OC.EventSource(OC.generateUrl('/apps/spreed/messages'));
this.source.listen('usersInRoom', function(users) {
this._trigger('usersInRoom', [users]);
}.bind(this));
this.source.listen('message', function(message) {
if (typeof(message) === 'string') {
message = JSON.parse(message);
}
this._trigger('message', [message]);
}.bind(this));
this.source.listen('__internal__', function(data) {
if (data === 'close') {
console.log('signaling connection closed - will reopen');
setTimeout(function() {
this._openEventSource();
}.bind(this), 0);
}
}.bind(this));
$.ajax({
url: OC.linkToOCS('apps/spreed/api/v1', 2) + 'signaling',
type: 'GET',
dataType: 'json',
beforeSend: function (request) {
request.setRequestHeader('Accept', 'application/json');
},
success: function (result) {
$.each(result.ocs.data, function(id, message) {
switch(message.type) {
case "usersInRoom":
this._trigger('usersInRoom', [message.data]);
break;
case "message":
if (typeof(message.data) === 'string') {
message.data = JSON.parse(message.data);
}
this._trigger('message', [message.data]);
break;
default:
console.log('Unknown Signaling Message');
break;
}
}.bind(this));
this._startPullingMessages();
}.bind(this),
error: function (/*jqXHR, textStatus, errorThrown*/) {
//Retry to pull messages after 5 seconds
window.setTimeout(function() {
this._startPullingMessages();
}.bind(this), 5000);
}.bind(this)
});
};
/**
@ -325,14 +361,20 @@
* @private
*/
InternalSignaling.prototype.sendPendingMessages = function() {
if (!this.spreedArrayConnection.length) {
if (!this.spreedArrayConnection.length || this.isSendingMessages) {
return;
}
$.post(OC.generateUrl('/apps/spreed/signalling'), {
messages: JSON.stringify(this.spreedArrayConnection)
});
this.spreedArrayConnection = [];
var pendingMessagesLength = this.spreedArrayConnection.length;
this.isSendingMessages = true;
this._sendMessages(this.spreedArrayConnection).done(function(/*result*/) {
this.spreedArrayConnection.splice(0, pendingMessagesLength);
this.isSendingMessages = false;
}.bind(this)).fail(function(/*xhr, textStatus, errorThrown*/) {
console.log('Sending pending signaling messages has failed.');
this.isSendingMessages = false;
}.bind(this));
};
/**

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

@ -17760,7 +17760,7 @@
}
};
// send via signalling channel
// send via signaling channel
Peer.prototype.send = function (messageType, payload) {
var message = {
to: this.id,

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

@ -21,7 +21,10 @@
namespace OCA\Spreed\AppInfo;
use OCA\Spreed\Room;
use OCA\Spreed\Signaling\Messages;
use OCP\AppFramework\App;
use Symfony\Component\EventDispatcher\GenericEvent;
class Application extends App {
@ -29,4 +32,21 @@ class Application extends App {
parent::__construct('spreed', $urlParams);
}
public function registerHooks() {
$listener = function(GenericEvent $event) {
/** @var Room $room */
$room = $event->getSubject();
/** @var Messages $messages */
$messages = $this->getContainer()->query(Messages::class);
$messages->addMessageForAllParticipants($room, 'refresh-participant-list');
};
$dispatcher = $this->getContainer()->getServer()->getEventDispatcher();
$dispatcher->addListener(Room::class . '::postUserEnterRoom', $listener);
$dispatcher->addListener(Room::class . '::postGuestEnterRoom', $listener);
$dispatcher->addListener(Room::class . '::postRemoveUser', $listener);
$dispatcher->addListener(Room::class . '::postRemoveBySession', $listener);
$dispatcher->addListener(Room::class . '::postUserDisconnectRoom', $listener);
}
}

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

@ -30,7 +30,7 @@ use OCA\Spreed\Exceptions\ParticipantNotFoundException;
use OCA\Spreed\Exceptions\RoomNotFoundException;
use OCA\Spreed\Manager;
use OCA\Spreed\Participant;
use OCA\Spreed\Signalling\Messages;
use OCA\Spreed\Signaling\Messages;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
@ -201,26 +201,23 @@ class CallController extends OCSController {
* @return DataResponse
*/
public function leaveCall($token) {
if ($this->userId !== null) {
try {
$room = $this->manager->getRoomForParticipantByToken($token, $this->userId);
$sessionId = $this->session->get('spreed-session');
$this->session->remove('spreed-session');
try {
$room = $this->manager->getRoomForParticipantByToken($token, $this->userId);
if ($this->userId === null) {
$participant = $room->getParticipantBySession($sessionId);
$room->removeParticipantBySession($participant);
} else {
$participant = $room->getParticipant($this->userId);
if ($participant->getParticipantType() === Participant::USER_SELF_JOINED) {
$room->removeParticipantBySession($participant);
}
} catch (RoomNotFoundException $e) {
} catch (\RuntimeException $e) {
$room->disconnectUserFromAllRooms($participant->getUser());
}
// As a pre-caution we simply disconnect the user from all rooms
$this->manager->disconnectUserFromAllRooms($this->userId);
} else {
$sessionId = $this->session->get('spreed-session');
$this->manager->removeSessionFromAllRooms($sessionId);
} catch (RoomNotFoundException $e) {
} catch (ParticipantNotFoundException $e) {
}
$this->session->remove('spreed-session');
return new DataResponse();
}

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

@ -340,9 +340,14 @@ class RoomController extends OCSController {
return new DataResponse(['token' => $room->getToken()], Http::STATUS_OK);
} catch (RoomNotFoundException $e) {
$room = $this->manager->createOne2OneRoom();
$room->addParticipant($currentUser->getUID(), Participant::OWNER);
$room->addUsers([
'userId' => $currentUser->getUID(),
'participantType' => Participant::OWNER,
], [
'userId' => $targetUser->getUID(),
'participantType' => Participant::OWNER,
]);
$room->addParticipant($targetUser->getUID(), Participant::OWNER);
$this->createNotification($currentUser, $targetUser, $room);
return new DataResponse(['token' => $room->getToken()], Http::STATUS_CREATED);
@ -371,19 +376,27 @@ class RoomController extends OCSController {
// Create the room
$room = $this->manager->createGroupRoom($targetGroup->getGID());
$room->addParticipant($currentUser->getUID(), Participant::OWNER);
$room->addUsers([
'userId' => $currentUser->getUID(),
'participantType' => Participant::OWNER,
]);
$usersInGroup = $targetGroup->getUsers();
$participants = [];
foreach ($usersInGroup as $user) {
if ($currentUser->getUID() === $user->getUID()) {
// Owner is already added.
continue;
}
$room->addUser($user);
$participants[] = [
'userId' => $user->getUID(),
];
$this->createNotification($currentUser, $user, $room);
}
call_user_func_array([$room, 'addUsers'], $participants);
return new DataResponse(['token' => $room->getToken()], Http::STATUS_CREATED);
}
@ -393,9 +406,18 @@ class RoomController extends OCSController {
* @return DataResponse
*/
protected function createPublicRoom() {
$currentUser = $this->userManager->get($this->userId);
if (!$currentUser instanceof IUser) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
// Create the room
$room = $this->manager->createPublicRoom();
$room->addParticipant($this->userId, Participant::OWNER);
$room->addUsers([
'userId' => $currentUser->getUID(),
'participantType' => Participant::OWNER,
]);
return new DataResponse(['token' => $room->getToken()], Http::STATUS_CREATED);
}
@ -535,13 +557,17 @@ class RoomController extends OCSController {
// In case a user is added to a one2one call, we change the call to a group call
$room->changeType(Room::GROUP_CALL);
$room->addUser($newUser);
$room->addUsers([
'userId' => $newUser->getUID(),
]);
$this->createNotification($currentUser, $newUser, $room);
return new DataResponse(['type' => $room->getType()]);
}
$room->addUser($newUser);
$room->addUsers([
'userId' => $newUser->getUID(),
]);
$this->createNotification($currentUser, $newUser, $room);
return new DataResponse([]);

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

@ -27,14 +27,15 @@ use OCA\Spreed\Config;
use OCA\Spreed\Exceptions\RoomNotFoundException;
use OCA\Spreed\Manager;
use OCA\Spreed\Room;
use OCA\Spreed\Signalling\Messages;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCA\Spreed\Signaling\Messages;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IDBConnection;
use OCP\IRequest;
use OCP\ISession;
class SignallingController extends Controller {
class SignalingController extends OCSController {
/** @var Config */
private $config;
/** @var ISession */
@ -45,7 +46,7 @@ class SignallingController extends Controller {
private $dbConnection;
/** @var Messages */
private $messages;
/** @var string */
/** @var string|null */
private $userId;
/**
@ -79,9 +80,9 @@ class SignallingController extends Controller {
* @PublicPage
*
* @param string $messages
* @return JSONResponse
* @return DataResponse
*/
public function signalling($messages) {
public function signaling($messages) {
$response = [];
$messages = json_decode($messages, true);
foreach($messages as $message) {
@ -128,83 +129,63 @@ class SignallingController extends Controller {
}
}
return new JSONResponse($response);
return new DataResponse($response);
}
/**
* @PublicPage
* @return DataResponse
*/
public function pullMessages() {
set_time_limit(0);
$eventSource = \OC::$server->createEventSource();
$data = [];
$seconds = 30;
$sessionId = '';
while(true) {
while ($seconds > 0) {
if ($this->userId === null) {
$sessionId = $this->session->get('spreed-session');
if (empty($sessionId)) {
// User is not active anywhere
$eventSource->send('usersInRoom', []);
$currentParticipant = false;
break;
} else {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('spreedme_room_participants')
->where($qb->expr()->eq('sessionId', $qb->createNamedParameter($sessionId)))
->andWhere($qb->expr()->eq('userId', $qb->createNamedParameter((string)$this->userId)));
$result = $qb->execute();
$currentParticipant = $result->fetch();
$result->closeCursor();
}
} else {
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
->from('spreedme_room_participants')
->where($qb->expr()->neq('sessionId', $qb->createNamedParameter('0')))
->andWhere($qb->expr()->eq('userId', $qb->createNamedParameter((string)$this->userId)))
->orderBy('lastPing', 'DESC')
->setMaxResults(1);
$result = $qb->execute();
$currentParticipant = $result->fetch();
$result->closeCursor();
if ($currentParticipant === false) {
$sessionId = null;
} else {
$sessionId = $currentParticipant['sessionId'];
}
$sessionId = $this->manager->getCurrentSessionId($this->userId);
}
if ($sessionId === null) {
// User is not active anywhere
$eventSource->send('usersInRoom', []);
} else {
// Check if the connection is still active, if not: Kill all existing
// messages and end the event source
if ($currentParticipant) {
try {
$room = $this->manager->getRoomForParticipant($currentParticipant['roomId'], $this->userId);
$eventSource->send('usersInRoom', $this->getUsersInRoom($room));
} catch (RoomNotFoundException $e) {
$eventSource->send('usersInRoom', []);
}
} else {
$eventSource->send('usersInRoom', []);
}
return new DataResponse([['type' => 'usersInRoom', 'data' => []]], Http::STATUS_NOT_FOUND);
}
$messages = $this->messages->getAndDeleteMessages($sessionId);
foreach ($messages as $row) {
$eventSource->send('message', $row['data']);
// Query all messages and send them to the user
$data = $this->messages->getAndDeleteMessages($sessionId);
$messageCount = count($data);
$data = array_filter($data, function($message) {
return $message['data'] !== 'refresh-participant-list';
});
if ($messageCount !== count($data)) {
try {
$room = $this->manager->getRoomForSession($this->userId, $sessionId);
$data[] = ['type' => 'usersInRoom', 'data' => $this->getUsersInRoom($room)];
} catch (RoomNotFoundException $e) {
return new DataResponse([['type' => 'usersInRoom', 'data' => []]], Http::STATUS_NOT_FOUND);
}
}
$this->dbConnection->close();
if (empty($data)) {
$seconds--;
} else {
break;
}
sleep(1);
}
$eventSource->close();
exit;
try {
// Add an update of the room participants at the end of the waiting
$room = $this->manager->getRoomForSession($this->userId, $sessionId);
$data[] = ['type' => 'usersInRoom', 'data' => $this->getUsersInRoom($room)];
} catch (RoomNotFoundException $e) {
}
return new DataResponse($data);
}
/**

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

@ -241,7 +241,7 @@ class Manager {
}
/**
* @param string $userId
* @param string|null $userId
* @param string $sessionId
* @return Room
* @throws RoomNotFoundException
@ -394,27 +394,6 @@ class Manager {
return $row['sessionId'];
}
/**
* @param string $userId
*/
public function disconnectUserFromAllRooms($userId) {
$query = $this->db->getQueryBuilder();
$query->update('spreedme_room_participants')
->set('sessionId', $query->createNamedParameter('0'))
->where($query->expr()->eq('userId', $query->createNamedParameter($userId)));
$query->execute();
}
/**
* @param string $sessionId
*/
public function removeSessionFromAllRooms($sessionId) {
$query = $this->db->getQueryBuilder();
$query->delete('spreedme_room_participants')
->where($query->expr()->eq('sessionId', $query->createNamedParameter($sessionId)));
$query->execute();
}
/**
* @param string $userId
* @return string[]

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

@ -31,8 +31,8 @@ class Version2001Date20170913104501 extends SimpleMigrationStep {
/** @var Schema $schema */
$schema = $schemaClosure();
if (!$schema->hasTable('videocalls_signalling')) {
$table = $schema->createTable('videocalls_signalling');
if (!$schema->hasTable('videocalls_signaling')) {
$table = $schema->createTable('videocalls_signaling');
$table->addColumn('sender', Type::STRING, [
'notnull' => true,

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

@ -196,6 +196,8 @@ class Room {
}
public function deleteRoom() {
$this->dispatcher->dispatch(self::class . '::preDeleteRoom', new GenericEvent($this));
$query = $this->db->getQueryBuilder();
// Delete all participants
@ -207,10 +209,12 @@ class Room {
$query->delete('spreedme_rooms')
->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
$query->execute();
$this->dispatcher->dispatch(self::class . '::postDeleteRoom', new GenericEvent($this));
}
/**
* @param string $newName Currently it is only allowed to rename: Room::GROUP_CALL, Room::PUBLIC_CALL
* @param string $newName Currently it is only allowed to rename: self::GROUP_CALL, self::PUBLIC_CALL
* @return bool True when the change was valid, false otherwise
*/
public function setName($newName) {
@ -222,6 +226,13 @@ class Room {
return false;
}
$oldName = $this->getName();
$this->dispatcher->dispatch(self::class . '::preSetName', new GenericEvent($this, [
'newName' => $newName,
'oldName' => $oldName,
]));
$query = $this->db->getQueryBuilder();
$query->update('spreedme_rooms')
->set('name', $query->createNamedParameter($newName))
@ -229,6 +240,11 @@ class Room {
$query->execute();
$this->name = $newName;
$this->dispatcher->dispatch(self::class . '::postSetName', new GenericEvent($this, [
'newName' => $newName,
'oldName' => $oldName,
]));
return true;
}
@ -254,7 +270,7 @@ class Room {
}
/**
* @param int $newType Currently it is only allowed to change to: Room::GROUP_CALL, Room::PUBLIC_CALL
* @param int $newType Currently it is only allowed to change to: self::GROUP_CALL, self::PUBLIC_CALL
* @return bool True when the change was valid, false otherwise
*/
public function changeType($newType) {
@ -262,12 +278,17 @@ class Room {
return true;
}
if (!in_array($newType, [Room::GROUP_CALL, Room::PUBLIC_CALL], true)) {
if (!in_array($newType, [self::GROUP_CALL, self::PUBLIC_CALL], true)) {
return false;
}
$oldType = $this->getType();
$this->dispatcher->dispatch(self::class . '::preChangeType', new GenericEvent($this, [
'newType' => $newType,
'oldType' => $oldType,
]));
$query = $this->db->getQueryBuilder();
$query->update('spreedme_rooms')
->set('type', $query->createNamedParameter($newType, IQueryBuilder::PARAM_INT))
@ -276,7 +297,7 @@ class Room {
$this->type = (int) $newType;
if ($oldType === Room::PUBLIC_CALL) {
if ($oldType === self::PUBLIC_CALL) {
// Kick all guests and users that were not invited
$query = $this->db->getQueryBuilder();
$query->delete('spreedme_room_participants')
@ -285,34 +306,45 @@ class Room {
$query->execute();
}
$this->dispatcher->dispatch(self::class . '::postChangeType', new GenericEvent($this, [
'newType' => $newType,
'oldType' => $oldType,
]));
return true;
}
/**
* @param IUser $user
* @param array[] ...$participants
*/
public function addUser(IUser $user) {
$this->addParticipant($user->getUID(), Participant::USER);
}
public function addUsers(array ...$participants) {
$this->dispatcher->dispatch(self::class . '::preAddUsers', new GenericEvent($this, [
'users' => $participants,
]));
/**
* @param string $participant
* @param int $participantType
* @param string $sessionId
*/
public function addParticipant($participant, $participantType, $sessionId = '0') {
$query = $this->db->getQueryBuilder();
$query->insert('spreedme_room_participants')
->values(
[
'userId' => $query->createNamedParameter($participant),
'userId' => $query->createParameter('userId'),
'sessionId' => $query->createParameter('sessionId'),
'participantType' => $query->createParameter('participantType'),
'roomId' => $query->createNamedParameter($this->getId()),
'lastPing' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
'sessionId' => $query->createNamedParameter($sessionId),
'participantType' => $query->createNamedParameter($participantType, IQueryBuilder::PARAM_INT),
]
);
$query->execute();
foreach ($participants as $participant) {
$query->setParameter('userId', $participant['userId'])
->setParameter('sessionId', isset($participant['sessionId']) ? $participant['sessionId'] : '0')
->setParameter('participantType', isset($participant['participantType']) ? $participant['participantType'] : Participant::USER, IQueryBuilder::PARAM_INT);
$query->execute();
}
$this->dispatcher->dispatch(self::class . '::postAddUsers', new GenericEvent($this, [
'users' => $participants,
]));
}
/**
@ -332,22 +364,38 @@ class Room {
* @param IUser $user
*/
public function removeUser(IUser $user) {
$this->dispatcher->dispatch(self::class . '::preRemoveUser', new GenericEvent($this, [
'user' => $user,
]));
$query = $this->db->getQueryBuilder();
$query->delete('spreedme_room_participants')
->where($query->expr()->eq('roomId', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('userId', $query->createNamedParameter($user->getUID())));
$query->execute();
$this->dispatcher->dispatch(self::class . '::postRemoveUser', new GenericEvent($this, [
'user' => $user,
]));
}
/**
* @param Participant $participant
*/
public function removeParticipantBySession(Participant $participant) {
$this->dispatcher->dispatch(self::class . '::preRemoveBySession', new GenericEvent($this, [
'participant' => $participant,
]));
$query = $this->db->getQueryBuilder();
$query->delete('spreedme_room_participants')
->where($query->expr()->eq('roomId', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('sessionId', $query->createNamedParameter($participant->getSessionId())));
$query->execute();
$this->dispatcher->dispatch(self::class . '::postRemoveBySession', new GenericEvent($this, [
'participant' => $participant,
]));
}
/**
@ -359,6 +407,8 @@ class Room {
public function enterRoomAsUser($userId, $password) {
$this->dispatcher->dispatch(self::class . '::preUserEnterRoom', new GenericEvent($this));
$this->disconnectUserFromAllRooms($userId);
$query = $this->db->getQueryBuilder();
$query->update('spreedme_room_participants')
->set('sessionId', $query->createParameter('sessionId'))
@ -375,7 +425,11 @@ class Room {
}
// User joining a public room, without being invited
$this->addParticipant($userId, Participant::USER_SELF_JOINED, $sessionId);
$this->addUsers([
'userId' => $userId,
'participantType' => Participant::USER_SELF_JOINED,
'sessionId' => $sessionId,
]);
}
while (!$this->isSessionUnique($sessionId)) {
@ -384,18 +438,35 @@ class Room {
$query->execute();
}
$query = $this->db->getQueryBuilder();
$query->update('spreedme_room_participants')
->set('sessionId', $query->createNamedParameter('0'))
->where($query->expr()->neq('roomId', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->eq('userId', $query->createNamedParameter($userId)));
$query->execute();
$this->dispatcher->dispatch(self::class . '::postUserEnterRoom', new GenericEvent($this));
return $sessionId;
}
/**
* @param string $userId
*/
public function disconnectUserFromAllRooms($userId) {
$this->dispatcher->dispatch(self::class . '::preUserDisconnectRoom', new GenericEvent($this));
// Reset sessions on all normal rooms
$query = $this->db->getQueryBuilder();
$query->update('spreedme_room_participants')
->set('sessionId', $query->createNamedParameter('0'))
->where($query->expr()->eq('userId', $query->createNamedParameter($userId)))
->andWhere($query->expr()->neq('participantType', $query->createNamedParameter(Participant::USER_SELF_JOINED, IQueryBuilder::PARAM_INT)));
$query->execute();
// And kill session on all self joined rooms
$query = $this->db->getQueryBuilder();
$query->delete('spreedme_room_participants')
->where($query->expr()->eq('userId', $query->createNamedParameter($userId)))
->andWhere($query->expr()->eq('participantType', $query->createNamedParameter(Participant::USER_SELF_JOINED, IQueryBuilder::PARAM_INT)));
$query->execute();
$this->dispatcher->dispatch(self::class . '::postUserDisconnectRoom', new GenericEvent($this));
}
/**
* @param string $password
* @return string
@ -530,15 +601,15 @@ class Room {
}
/**
* @param string $participant
* @param string $userId
* @param string $sessionId
* @param int $timestamp
*/
public function ping($participant, $sessionId, $timestamp) {
public function ping($userId, $sessionId, $timestamp) {
$query = $this->db->getQueryBuilder();
$query->update('spreedme_room_participants')
->set('lastPing', $query->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT))
->where($query->expr()->eq('userId', $query->createNamedParameter((string) $participant)))
->where($query->expr()->eq('userId', $query->createNamedParameter((string) $userId)))
->andWhere($query->expr()->eq('sessionId', $query->createNamedParameter($sessionId)))
->andWhere($query->expr()->eq('roomId', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));

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

@ -19,9 +19,10 @@
*
*/
namespace OCA\Spreed\Signalling;
namespace OCA\Spreed\Signaling;
use OCA\Spreed\Room;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
@ -48,7 +49,7 @@ class Messages {
*/
public function deleteMessages(array $sessionIds) {
$query = $this->db->getQueryBuilder();
$query->delete('videocalls_signalling')
$query->delete('videocalls_signaling')
->where($query->expr()->in('recipient', $query->createNamedParameter($sessionIds, IQueryBuilder::PARAM_STR_ARRAY)))
->orWhere($query->expr()->in('sender', $query->createNamedParameter($sessionIds, IQueryBuilder::PARAM_STR_ARRAY)));
$query->execute();
@ -61,7 +62,7 @@ class Messages {
*/
public function addMessage($senderSessionId, $recipientSessionId, $message) {
$query = $this->db->getQueryBuilder();
$query->insert('videocalls_signalling')
$query->insert('videocalls_signaling')
->values(
[
'sender' => $query->createNamedParameter($senderSessionId),
@ -73,6 +74,29 @@ class Messages {
$query->execute();
}
/**
* @param Room $room
* @param string $message
*/
public function addMessageForAllParticipants(Room $room, $message) {
$query = $this->db->getQueryBuilder();
$query->insert('videocalls_signaling')
->values(
[
'sender' => $query->createParameter('sender'),
'recipient' => $query->createParameter('recipient'),
'timestamp' => $query->createNamedParameter($this->time->getTime()),
'message' => $query->createNamedParameter($message),
]
);
foreach ($room->getActiveSessions() as $sessionId) {
$query->setParameter('sender', $sessionId)
->setParameter('recipient', $sessionId)
->execute();
}
}
/**
* Get messages and delete them afterwards
*
@ -90,7 +114,7 @@ class Messages {
$query = $this->db->getQueryBuilder();
$query->select('*')
->from('videocalls_signalling')
->from('videocalls_signaling')
->where($query->expr()->eq('recipient', $query->createNamedParameter($sessionId)))
->andWhere($query->expr()->lte('timestamp', $query->createNamedParameter($time)));
$result = $query->execute();
@ -101,7 +125,7 @@ class Messages {
$result->closeCursor();
$query = $this->db->getQueryBuilder();
$query->delete('videocalls_signalling')
$query->delete('videocalls_signaling')
->where($query->expr()->eq('recipient', $query->createNamedParameter($sessionId)))
->andWhere($query->expr()->lte('timestamp', $query->createNamedParameter($time)));
$query->execute();

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

@ -51,7 +51,7 @@ class ApiController extends OCSController {
public function resetSpreed() {
$query = $this->db->getQueryBuilder();
$query->delete('videocalls_signalling')->execute();
$query->delete('videocalls_signaling')->execute();
$query = $this->db->getQueryBuilder();
$query->delete('spreedme_rooms')->execute();