diff options
author | Joas Schilling <coding@schilljs.com> | 2022-02-27 00:21:00 +0300 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2022-03-08 14:11:06 +0300 |
commit | 4348f61fdea704916273822f9603532e2ba56abe (patch) | |
tree | 262bf2f3aaa1b506425e0c8ccf7803e49ca8180a /lib | |
parent | 9a7852376ab223cca82485837efe81e8cc8be60f (diff) |
Only update the last_message and last_activity once
Especially when adding multiple system messages we updated the room
data way too often.
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AppInfo/Application.php | 4 | ||||
-rw-r--r-- | lib/Chat/ChatManager.php | 18 | ||||
-rw-r--r-- | lib/Chat/SystemMessage/Listener.php | 19 | ||||
-rw-r--r-- | lib/Events/AddParticipantsEvent.php | 22 | ||||
-rw-r--r-- | lib/Events/ChatEvent.php | 22 | ||||
-rw-r--r-- | lib/Service/ParticipantService.php | 23 |
6 files changed, 95 insertions, 13 deletions
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 24075635b..a91636635 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -217,6 +217,10 @@ class Application extends App implements IBootstrap { protected function registerRoomActivityHooks(IEventDispatcher $dispatcher): void { $listener = function (ChatEvent $event): void { + if ($event->shouldSkipLastActivityUpdate()) { + return; + } + $room = $event->getRoom(); /** @var ITimeFactory $timeFactory */ $timeFactory = $this->getContainer()->query(ITimeFactory::class); diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php index 315116835..c50cf7005 100644 --- a/lib/Chat/ChatManager.php +++ b/lib/Chat/ChatManager.php @@ -118,6 +118,11 @@ class ChatManager { * @param bool $sendNotifications * @param string|null $referenceId * @param int|null $parentId + * @param bool $shouldSkipLastMessageUpdate If multiple messages will be posted + * (e.g. when adding multiple users to a room) we can skip the last + * message and last activity update until the last entry was created + * and then update with those values. + * This will replace O(n) with 1 database update. * @return IComment */ public function addSystemMessage( @@ -128,7 +133,8 @@ class ChatManager { \DateTime $creationDateTime, bool $sendNotifications, ?string $referenceId = null, - ?int $parentId = null + ?int $parentId = null, + bool $shouldSkipLastMessageUpdate = false ): IComment { $comment = $this->commentsManager->create($actorType, $actorId, 'chat', (string) $chat->getId()); $comment->setMessage($message, self::MAX_CHAT_LENGTH); @@ -152,14 +158,16 @@ class ChatManager { $comment->setVerb('system'); } - $event = new ChatEvent($chat, $comment); + $event = new ChatEvent($chat, $comment, $shouldSkipLastMessageUpdate); $this->dispatcher->dispatch(self::EVENT_BEFORE_SYSTEM_MESSAGE_SEND, $event); try { $this->commentsManager->save($comment); - // Update last_message - $chat->setLastMessage($comment); - $this->unreadCountCache->clear($chat->getId() . '-'); + if (!$shouldSkipLastMessageUpdate) { + // Update last_message + $chat->setLastMessage($comment); + $this->unreadCountCache->clear($chat->getId() . '-'); + } if ($sendNotifications) { $this->notifier->notifyOtherParticipant($chat, $comment, []); diff --git a/lib/Chat/SystemMessage/Listener.php b/lib/Chat/SystemMessage/Listener.php index 0ecbd4636..2308b061b 100644 --- a/lib/Chat/SystemMessage/Listener.php +++ b/lib/Chat/SystemMessage/Listener.php @@ -43,6 +43,7 @@ use OCA\Talk\Share\RoomShareProvider; use OCA\Talk\TalkSession; use OCA\Talk\Webinary; use OCP\AppFramework\Utility\ITimeFactory; +use OCP\Comments\IComment; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventListener; @@ -263,7 +264,15 @@ class Listener implements IEventListener { || $listener->getUserId() !== $participant['actorId'] // - has joined a listable room on their own || $participantType === Participant::USER) { - $listener->sendSystemMessage($room, 'user_added', ['user' => $participant['actorId']]); + $comment = $listener->sendSystemMessage( + $room, + 'user_added', + ['user' => $participant['actorId']], + null, + $event->shouldSkipLastMessageUpdate() + ); + + $event->setLastMessage($comment); } } }); @@ -379,7 +388,7 @@ class Listener implements IEventListener { } } - protected function sendSystemMessage(Room $room, string $message, array $parameters = [], Participant $participant = null): void { + protected function sendSystemMessage(Room $room, string $message, array $parameters = [], Participant $participant = null, bool $shouldSkipLastMessageUpdate = false): IComment { if ($participant instanceof Participant) { $actorType = $participant->getAttendee()->getActorType(); $actorId = $participant->getAttendee()->getActorId(); @@ -408,11 +417,13 @@ class Listener implements IEventListener { $referenceId = (string) $referenceId; } - $this->chatManager->addSystemMessage( + return $this->chatManager->addSystemMessage( $room, $actorType, $actorId, json_encode(['message' => $message, 'parameters' => $parameters]), $this->timeFactory->getDateTime(), $message === 'file_shared', - $referenceId + $referenceId, + null, + $shouldSkipLastMessageUpdate ); } diff --git a/lib/Events/AddParticipantsEvent.php b/lib/Events/AddParticipantsEvent.php index 5d214bfb2..f05c02354 100644 --- a/lib/Events/AddParticipantsEvent.php +++ b/lib/Events/AddParticipantsEvent.php @@ -24,17 +24,25 @@ declare(strict_types=1); namespace OCA\Talk\Events; use OCA\Talk\Room; +use OCP\Comments\IComment; class AddParticipantsEvent extends RoomEvent { /** @var array */ protected $participants; + /** @var bool */ + protected $skipLastMessageUpdate; + + /** @var IComment|null */ + protected $lastMessage; public function __construct(Room $room, - array $participants) { + array $participants, + bool $skipLastMessageUpdate = false) { parent::__construct($room); $this->participants = $participants; + $this->skipLastMessageUpdate = $skipLastMessageUpdate; } /** @@ -43,4 +51,16 @@ class AddParticipantsEvent extends RoomEvent { public function getParticipants(): array { return $this->participants; } + + public function shouldSkipLastMessageUpdate(): bool { + return $this->skipLastMessageUpdate; + } + + public function setLastMessage(IComment $lastMessage): void { + $this->lastMessage = $lastMessage; + } + + public function getLastMessage(): ?IComment { + return $this->lastMessage; + } } diff --git a/lib/Events/ChatEvent.php b/lib/Events/ChatEvent.php index 2a9e548e2..1f552f7d7 100644 --- a/lib/Events/ChatEvent.php +++ b/lib/Events/ChatEvent.php @@ -31,13 +31,33 @@ class ChatEvent extends RoomEvent { /** @var IComment */ protected $comment; + /** @var bool */ + protected $skipLastActivityUpdate; - public function __construct(Room $room, IComment $comment) { + public function __construct(Room $room, + IComment $comment, + bool $skipLastActivityUpdate = false) { parent::__construct($room); $this->comment = $comment; + $this->skipLastActivityUpdate = $skipLastActivityUpdate; } public function getComment(): IComment { return $this->comment; } + + /** + * If multiple messages will be posted (e.g. when adding multiple users to a room) + * we can skip the last message and last activity update until the last entry + * was created and then update with those values. + * This will replace O(n) with 1 database update. + * + * A ChatManager::EVENT_AFTER_MULTIPLE_SYSTEM_MESSAGE_SEND will be triggered + * as a final event when all messages have been created. + * + * @return bool + */ + public function shouldSkipLastActivityUpdate(): bool { + return $this->skipLastActivityUpdate; + } } diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index 960330cee..c02a4910a 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -59,6 +59,7 @@ use OCP\Comments\IComment; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\EventDispatcher\IEventDispatcher; +use OCP\ICacheFactory; use OCP\IConfig; use OCP\IDBConnection; use OCP\IGroup; @@ -94,6 +95,8 @@ class ParticipantService { private $notifications; /** @var ITimeFactory */ private $timeFactory; + /** @var ICacheFactory */ + private $cacheFactory; public function __construct(IConfig $serverConfig, Config $talkConfig, @@ -107,7 +110,8 @@ class ParticipantService { IGroupManager $groupManager, MembershipService $membershipService, Notifications $notifications, - ITimeFactory $timeFactory) { + ITimeFactory $timeFactory, + ICacheFactory $cacheFactory) { $this->serverConfig = $serverConfig; $this->talkConfig = $talkConfig; $this->attendeeMapper = $attendeeMapper; @@ -120,6 +124,7 @@ class ParticipantService { $this->groupManager = $groupManager; $this->membershipService = $membershipService; $this->timeFactory = $timeFactory; + $this->cacheFactory = $cacheFactory; $this->notifications = $notifications; } @@ -367,7 +372,7 @@ class ParticipantService { if (empty($participants)) { return; } - $event = new AddParticipantsEvent($room, $participants); + $event = new AddParticipantsEvent($room, $participants, true); $this->dispatcher->dispatch(Room::EVENT_BEFORE_USERS_ADD, $event); $lastMessage = 0; @@ -426,9 +431,23 @@ class ParticipantService { $this->dispatcher->dispatchTyped($attendeeEvent); $this->dispatcher->dispatch(Room::EVENT_AFTER_USERS_ADD, $event); + + $lastMessage = $event->getLastMessage(); + if ($lastMessage instanceof IComment) { + $this->updateRoomLastMessage($room, $lastMessage); + } } } + protected function updateRoomLastMessage(Room $room, IComment $message): void { + $room->setLastMessage($message); + $room->setLastActivity($message->getCreationDateTime()); + $lastMessageCache = $this->cacheFactory->createDistributed('talk/lastmsgid'); + $lastMessageCache->remove($room->getToken()); + $unreadCountCache = $this->cacheFactory->createDistributed('talk/unreadcount'); + $unreadCountCache->clear($room->getId() . '-'); + } + public function getHighestPermissionAttendee(Room $room): ?Attendee { try { $roomOwners = $this->attendeeMapper->getActorsByParticipantTypes($room->getId(), [Participant::OWNER]); |