зеркало из https://github.com/nextcloud/spreed.git
Merge pull request #363 from nextcloud/long-polling
Use an OCS controller and long polling instead of event sources
This commit is contained in:
Коммит
8e7b8320ce
|
@ -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…
|
||||
|
|
106
js/signaling.js
106
js/signaling.js
|
@ -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,
|
||||
|
|
129
lib/Room.php
129
lib/Room.php
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче