From e63cbaaed1504bb143fc8e6be2c3b4a8ee04b974 Mon Sep 17 00:00:00 2001 From: sualko Date: Wed, 16 Mar 2022 16:12:33 +0100 Subject: [PATCH 1/5] feat: track room state use cron job to check room state every 15 minutes fix #79 --- lib/BackgroundJob/IsRunningJob.php | 54 +++++++++++++++++++ lib/Controller/HookController.php | 2 + lib/Controller/JoinController.php | 25 ++++++++- lib/Db/Room.php | 5 ++ .../Version000000Date20220316151400.php | 42 +++++++++++++++ lib/Service/RoomService.php | 15 ++++++ tests/Unit/Controller/JoinControllerTest.php | 7 ++- ts/Common/Api.ts | 1 + ts/Manager/App.scss | 4 ++ ts/Manager/RoomRow.tsx | 6 +-- ts/filelist.ts | 2 +- 11 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 lib/BackgroundJob/IsRunningJob.php create mode 100644 lib/Migration/Version000000Date20220316151400.php diff --git a/lib/BackgroundJob/IsRunningJob.php b/lib/BackgroundJob/IsRunningJob.php new file mode 100644 index 0000000..d069eb2 --- /dev/null +++ b/lib/BackgroundJob/IsRunningJob.php @@ -0,0 +1,54 @@ +jobList = $jobList; + $this->service = $service; + $this->api = $api; + + $this->setInterval(15 * 60); + } + + protected function run($argument) { + try { + $room = $this->service->find($argument['id']); + } catch (RoomNotFound $e) { + $this->jobList->remove($this, $argument); + return; + } + + if (!$room->running) { + $this->jobList->remove($this, $argument); + return; + } + + $isRunning = $this->api->isRunning($room); + + if (!$isRunning) { + $this->service->updateRunning($room->id, $isRunning); + + $this->jobList->remove($this, $argument); + } + } +} diff --git a/lib/Controller/HookController.php b/lib/Controller/HookController.php index 98c6018..f3a1614 100644 --- a/lib/Controller/HookController.php +++ b/lib/Controller/HookController.php @@ -63,6 +63,8 @@ class HookController extends Controller { $recordingmarks = \boolval($recordingmarks); $room = $this->getRoom(); + $this->service->updateRunning($room->getId(), false); + $this->avatarRepository->clearRoom($room->uid); $this->eventDispatcher->dispatch(MeetingEndedEvent::class, new MeetingEndedEvent($room, $recordingmarks)); diff --git a/lib/Controller/JoinController.php b/lib/Controller/JoinController.php index 727673e..1a56a89 100644 --- a/lib/Controller/JoinController.php +++ b/lib/Controller/JoinController.php @@ -2,6 +2,7 @@ namespace OCA\BigBlueButton\Controller; +use OCA\BigBlueButton\BackgroundJob\IsRunningJob; use OCA\BigBlueButton\BigBlueButton\API; use OCA\BigBlueButton\BigBlueButton\Presentation; use OCA\BigBlueButton\Db\Room; @@ -12,6 +13,7 @@ use OCA\BigBlueButton\Service\RoomService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\BackgroundJob\IJobList; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; @@ -38,6 +40,9 @@ class JoinController extends Controller { /** @var Permission */ private $permission; + /** @var IJobList */ + private $jobList; + public function __construct( string $appName, IRequest $request, @@ -45,7 +50,8 @@ class JoinController extends Controller { IURLGenerator $urlGenerator, IUserSession $userSession, API $api, - Permission $permission + Permission $permission, + IJobList $jobList ) { parent::__construct($appName, $request); @@ -54,6 +60,7 @@ class JoinController extends Controller { $this->userSession = $userSession; $this->api = $api; $this->permission = $permission; + $this->jobList = $jobList; } public function setToken(string $token): void { @@ -129,6 +136,8 @@ class JoinController extends Controller { $creationDate = $this->api->createMeeting($room, $presentation); $joinUrl = $this->api->createJoinUrl($room, $creationDate, $displayname, $isModerator, $userId); + $this->markAsRunning($room); + \OCP\Util::addHeader('meta', ['http-equiv' => 'refresh', 'content' => '3;url='.$joinUrl]); return new TemplateResponse($this->appName, 'forward', [ @@ -153,4 +162,18 @@ class JoinController extends Controller { ), ]); } + + private function markAsRunning(Room $room) { + if (!$room->running) { + $this->service->updateRunning($room->getId(), true); + } + + if (!$this->jobList->has(IsRunningJob::class, [ + 'id' => $room->id, + ])) { + $this->jobList->add(IsRunningJob::class, [ + 'id' => $room->id, + ]); + } + } } diff --git a/lib/Db/Room.php b/lib/Db/Room.php index e7881b8..7fb2816 100644 --- a/lib/Db/Room.php +++ b/lib/Db/Room.php @@ -25,6 +25,7 @@ use OCP\AppFramework\Db\Entity; * @method bool getMediaCheck() * @method bool getCleanLayout() * @method bool getJoinMuted() + * @method bool getRunning() * @method void setUid(string $uid) * @method void setName(string $name) * @method void setAttendeePassword(string $pw) @@ -42,6 +43,7 @@ use OCP\AppFramework\Db\Entity; * @method void setMediaCheck(bool $mediaCheck) * @method void setCleanLayout(bool $cleanLayout) * @method void setJoinMuted(bool $joinMuted) + * @method void setRunning(bool $running) */ class Room extends Entity implements JsonSerializable { public const ACCESS_PUBLIC = 'public'; @@ -71,6 +73,7 @@ class Room extends Entity implements JsonSerializable { public $mediaCheck; public $cleanLayout; public $joinMuted; + public $running; public function __construct() { $this->addType('maxParticipants', 'integer'); @@ -82,6 +85,7 @@ class Room extends Entity implements JsonSerializable { $this->addType('mediaCheck', 'boolean'); $this->addType('cleanLayout', 'boolean'); $this->addType('joinMuted', 'boolean'); + $this->addType('running', 'boolean'); } public function jsonSerialize(): array { @@ -103,6 +107,7 @@ class Room extends Entity implements JsonSerializable { 'mediaCheck' => boolval($this->mediaCheck), 'cleanLayout' => boolval($this->cleanLayout), 'joinMuted' => boolval($this->joinMuted), + 'running' => boolval($this->running), ]; } } diff --git a/lib/Migration/Version000000Date20220316151400.php b/lib/Migration/Version000000Date20220316151400.php new file mode 100644 index 0000000..551b4ae --- /dev/null +++ b/lib/Migration/Version000000Date20220316151400.php @@ -0,0 +1,42 @@ +hasTable('bbb_rooms')) { + $table = $schema->getTable('bbb_rooms'); + + if (!$table->hasColumn('running')) { + $table->addColumn('running', 'boolean', [ + 'notnull' => false, + 'default' => false + ]); + } + + return $schema; + } + + return null; + } +} diff --git a/lib/Service/RoomService.php b/lib/Service/RoomService.php index 198ae95..d8e42b6 100644 --- a/lib/Service/RoomService.php +++ b/lib/Service/RoomService.php @@ -163,6 +163,21 @@ class RoomService { } } + /** + * @return \OCP\AppFramework\Db\Entity|null + */ + public function updateRunning(int $id, bool $running) { + try { + $room = $this->mapper->find($id); + + $room->setRunning($running); + + return $this->mapper->update($room); + } catch (Exception $e) { + $this->handleException($e); + } + } + /** * @return Room|null */ diff --git a/tests/Unit/Controller/JoinControllerTest.php b/tests/Unit/Controller/JoinControllerTest.php index 5bae8b9..0c66091 100644 --- a/tests/Unit/Controller/JoinControllerTest.php +++ b/tests/Unit/Controller/JoinControllerTest.php @@ -11,6 +11,7 @@ use OCA\BigBlueButton\Service\RoomService; use OCP\AppFramework\Http; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\BackgroundJob\IJobList; use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUser; @@ -26,6 +27,7 @@ class JoinControllerTest extends TestCase { private $api; private $permission; private $room; + private $jobList; public function setUp(): void { parent::setUp(); @@ -36,6 +38,7 @@ class JoinControllerTest extends TestCase { $this->urlGenerator = $this->createMock(IURLGenerator::class); $this->api = $this->createMock(API::class); $this->permission = $this->createMock(Permission::class); + $this->jobList = $this->createMock(IJobList::class); $this->controller = new JoinController( 'bbb', @@ -44,10 +47,12 @@ class JoinControllerTest extends TestCase { $this->urlGenerator, $this->userSession, $this->api, - $this->permission + $this->permission, + $this->jobList ); $this->room = new Room(); + $this->room->id = 1; $this->room->uid = 'uid_foo'; $this->room->userId = 'user_foo'; $this->room->access = Room::ACCESS_PUBLIC; diff --git a/ts/Common/Api.ts b/ts/Common/Api.ts index 61c128a..fa6bf1c 100644 --- a/ts/Common/Api.ts +++ b/ts/Common/Api.ts @@ -44,6 +44,7 @@ export interface Room { mediaCheck: boolean, cleanLayout: boolean, joinMuted: boolean, + running: boolean, } export interface RoomShare { diff --git a/ts/Manager/App.scss b/ts/Manager/App.scss index 14085e0..57c8ae7 100644 --- a/ts/Manager/App.scss +++ b/ts/Manager/App.scss @@ -184,6 +184,10 @@ pre { width: 42px; padding: 0; } + + &.name { + width: 100%; + } } tfoot td { diff --git a/ts/Manager/RoomRow.tsx b/ts/Manager/RoomRow.tsx index abf2cdc..d346a10 100644 --- a/ts/Manager/RoomRow.tsx +++ b/ts/Manager/RoomRow.tsx @@ -187,9 +187,9 @@ const RoomRow: React.FC = (props) => { return ( <> - - - + + + {room.running ? t('bbb', 'Join') : t('bbb', 'Start')} diff --git a/ts/filelist.ts b/ts/filelist.ts index 7b4ee08..4846e0f 100644 --- a/ts/filelist.ts +++ b/ts/filelist.ts @@ -65,7 +65,7 @@ async function openDialog(fileId: number, filename: string) { const row = $(''); const button = $(' +