Skip to content

Commit

Permalink
Reorganize how deletes are deferred so we can properly group them
Browse files Browse the repository at this point in the history
Signed-off-by: Joas Schilling <coding@schilljs.com>
  • Loading branch information
nickvergessen committed Jan 26, 2023
1 parent 77be7fd commit 4e7d562
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 19 deletions.
2 changes: 1 addition & 1 deletion lib/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public function markProcessed(INotification $notification): void {
}
foreach ($deleted as $user => $notifications) {
foreach ($notifications as $data) {
$this->push->pushDeleteToDevice((string) $user, $data['id'], $data['app']);
$this->push->pushDeleteToDevice((string) $user, [$data['id']], $data['app']);
}
}
if (!$isAlreadyDeferring) {
Expand Down
2 changes: 1 addition & 1 deletion lib/Controller/EndpointController.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ public function deleteNotification(int $id): DataResponse {
$deleted = $this->handler->deleteById($id, $this->getCurrentUser(), $notification);

if ($deleted) {
$this->push->pushDeleteToDevice($this->getCurrentUser(), $id, $notification->getApp());
$this->push->pushDeleteToDevice($this->getCurrentUser(), [$id], $notification->getApp());
}
} catch (NotificationNotFoundException $e) {
}
Expand Down
72 changes: 55 additions & 17 deletions lib/Push.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class Push {
protected $deferPayloads = false;
/** @var array[] */
protected $deletesToPush = [];
/** @var string[] */
protected $deleteAllsToPush = [];
/** @var INotification[] */
protected $notificationsToPush = [];

Expand Down Expand Up @@ -170,12 +172,18 @@ public function flushPayloads(): void {
$this->notificationsToPush = [];
}

if (!empty($this->deleteAllsToPush)) {
foreach ($this->deleteAllsToPush as $userId) {
$this->pushDeleteToDevice($userId, null);
}
$this->deleteAllsToPush = [];
}

if (!empty($this->deletesToPush)) {
// Check for $id = 0 then only trigger delete all for that user
// Otherwise group by "app" (['spreed', 'talk', 'admin_notification_talk'] OR not!)
// And trigger each chunk per user
foreach ($this->deletesToPush as $id => $data) {
$this->pushDeleteToDevice($data['userId'], $id, $data['app']);
foreach ($this->deletesToPush as $userId => $data) {
foreach ($data as $client => $notificationIds) {
$this->pushDeleteToDevice($userId, $notificationIds, $client);
}
}
$this->deletesToPush = [];
}
Expand Down Expand Up @@ -313,21 +321,47 @@ public function pushToDevice(int $id, INotification $notification, ?OutputInterf
}
}

public function pushDeleteToDevice(string $userId, ?int $notificationId, string $app = ''): void {
/**
* @param string $userId
* @param ?int[] $notificationIds
* @param string $app
* @throws InvalidTokenException FIXME investigate
*/
public function pushDeleteToDevice(string $userId, ?array $notificationIds, string $app = ''): void {
if (!$this->config->getSystemValueBool('has_internet_connection', true)) {
return;
}

if ($this->deferPreparing) {
if ($notificationId === null) {
$notificationId = 0;
if ($notificationIds === null) {
$this->deleteAllsToPush[$userId] = true;
if (isset($this->deletesToPush[$userId])) {
unset($this->deletesToPush[$userId]);
}
} else {
if (isset($this->deleteAllsToPush[$userId])) {
return;
}

$isTalkNotification = \in_array($app, ['spreed', 'talk', 'admin_notification_talk'], true);
$clientGroup = $isTalkNotification ? 'talk' : 'files';

if (!isset($this->deletesToPush[$userId])) {
$this->deletesToPush[$userId] = [];
}
if (!isset($this->deletesToPush[$userId][$clientGroup])) {
$this->deletesToPush[$userId][$clientGroup] = [];
}

foreach ($notificationIds as $notificationId) {
$this->deletesToPush[$userId][$clientGroup][] = $notificationId;
}
}
$this->deletesToPush[$notificationId] = ['userId' => $userId, 'app' => $app]; // FIXME this assumes there is only 1 delete-all per request
$this->loadDevicesForUsers[] = $userId;
return;
}

$deleteAll = $notificationId !== null;
$deleteAll = $notificationIds === null;

$user = $this->createFakeUserObject($userId);

Expand Down Expand Up @@ -358,17 +392,21 @@ public function pushDeleteToDevice(string $userId, ?int $notificationId, string
}

try {
if ($deleteAll) {
$payload = json_encode($this->encryptAndSignDelete($userKey, $device, null));
} else {
$payload = json_encode($this->encryptAndSignDelete($userKey, $device, [$notificationId]));
}

$proxyServer = rtrim($device['proxyserver'], '/');
if (!isset($this->payloadsToSend[$proxyServer])) {
$this->payloadsToSend[$proxyServer] = [];
}
$this->payloadsToSend[$proxyServer][] = $payload;

if ($deleteAll) {
$data = $this->encryptAndSignDelete($userKey, $device, null);
$this->payloadsToSend[$proxyServer][] = json_encode($data['payload']);
} else {
while (!empty($notificationIds)) {
$data = $this->encryptAndSignDelete($userKey, $device, $notificationIds);
$notificationIds = $data['remaining'];
$this->payloadsToSend[$proxyServer][] = json_encode($data['payload']);
}
}
} catch (\InvalidArgumentException $e) {
// Failed to encrypt message for device: public key is invalid
$this->deletePushToken($device['token']);
Expand Down

0 comments on commit 4e7d562

Please sign in to comment.