Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/notifications.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2021-04-22 16:01:37 +0300
committerJoas Schilling <coding@schilljs.com>2021-04-22 16:01:37 +0300
commit0cf5dde6bdcc9795b940d1f08a735cac179ca204 (patch)
treec7aac68cae96b0a772a14759610cb3993fa7cec9
parent5ac74461141d8992bf1fb22c6e5fabf0544e5db1 (diff)
Group delete pushes with a delete-multiple for the talk clients as they receive a lotbugfix/noid/reduce-delete-push-spam
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r--lib/Push.php128
1 files changed, 100 insertions, 28 deletions
diff --git a/lib/Push.php b/lib/Push.php
index 1f7654f..af35d66 100644
--- a/lib/Push.php
+++ b/lib/Push.php
@@ -74,6 +74,8 @@ class Push {
protected $output;
/** @var array */
protected $payloadsToSend = [];
+ /** @var array */
+ protected $deferredDeletes = [];
/** @var bool */
protected $deferPayloads = false;
@@ -121,6 +123,11 @@ class Push {
public function flushPayloads(): void {
$this->deferPayloads = false;
+
+ foreach ($this->deferredDeletes as $userId => $deletes) {
+ $this->createDeletePayloads($userId, $deletes);
+ }
+
$this->sendNotificationsToProxies();
}
@@ -234,7 +241,7 @@ class Push {
}
if (!$this->deferPayloads) {
- $this->sendNotificationsToProxies();
+ $this->flushPayloads();
}
}
@@ -243,20 +250,59 @@ class Push {
return;
}
+ if (!isset($this->deferredDeletes[$userId])) {
+ $this->deferredDeletes[$userId] = [];
+ }
+
+ $this->deferredDeletes[$userId] = [
+ 'notificationId' => $notificationId,
+ 'app' => $app,
+ ];
+
+ if (!$this->deferPayloads) {
+ $this->flushPayloads();
+ }
+ }
+
+ public function createDeletePayloads(string $userId, array $deferredDeletes): void {
+ if (!$this->config->getSystemValueBool('has_internet_connection', true)) {
+ return;
+ }
+
+ if (empty($deferredDeletes)) {
+ return;
+ }
+
$user = $this->userManager->get($userId);
if (!($user instanceof IUser)) {
return;
}
$devices = $this->getDevicesForUser($userId);
- if ($notificationId !== 0 && $app !== '') {
- // Only filter when it's not a single delete
- $devices = $this->filterDeviceList($devices, $app);
- }
+
if (empty($devices)) {
return;
}
+ $deleteAll = !empty(array_filter($deferredDeletes, static function($deferredDelete) {
+ return $deferredDelete['notificationId'] === 0;
+ }));
+
+ $talkIds = $otherIds = [];
+ if (!$deleteAll) {
+ $talkIds = array_map(static function ($deferredDelete) {
+ return $deferredDelete['notificationId'];
+ }, array_filter($deferredDeletes, static function($deferredDelete) {
+ return \in_array($deferredDelete['app'], ['spreed', 'talk', 'admin_notification_talk'], true);
+ }));
+
+ $otherIds = array_map(static function ($deferredDelete) {
+ return $deferredDelete['notificationId'];
+ }, array_filter($deferredDeletes, static function($deferredDelete) {
+ return !\in_array($deferredDelete['app'], ['spreed', 'talk', 'admin_notification_talk'], true);
+ }));
+ }
+
// We don't push to devices that are older than 60 days
$maxAge = time() - 60 * 24 * 60 * 60;
@@ -267,22 +313,38 @@ class Push {
continue;
}
- try {
- $payload = json_encode($this->encryptAndSignDelete($userKey, $device, $notificationId));
-
- $proxyServer = rtrim($device['proxyserver'], '/');
- if (!isset($this->payloadsToSend[$proxyServer])) {
- $this->payloadsToSend[$proxyServer] = [];
+ if ($deleteAll) {
+ $this->createPayloadsInChunks($userKey, $device, []);
+ } else if ($device['apptype'] !== 'talk') {
+ foreach ($otherIds as $id) {
+ // Only talk clients handle delete-multiple
+ $this->createPayloadsInChunks($userKey, $device, [$id]);
+ }
+ } else {
+ $ids = $talkIds;
+ while (!empty($ids)) {
+ $ids = $this->createPayloadsInChunks($userKey, $device, $ids);
}
- $this->payloadsToSend[$proxyServer][] = $payload;
- } catch (\InvalidArgumentException $e) {
- // Failed to encrypt message for device: public key is invalid
- $this->deletePushToken($device['token']);
}
}
+ }
- if (!$this->deferPayloads) {
- $this->sendNotificationsToProxies();
+ protected function createPayloadsInChunks(Key $userKey, array $device, array $ids): array {
+ try {
+ $data = $this->encryptAndSignDelete($userKey, $device, $ids);
+ $payload = json_encode($data['payload']);
+
+ $proxyServer = rtrim($device['proxyserver'], '/');
+ if (!isset($this->payloadsToSend[$proxyServer])) {
+ $this->payloadsToSend[$proxyServer] = [];
+ }
+ $this->payloadsToSend[$proxyServer][] = $payload;
+
+ return $data['remaining'];
+ } catch (\InvalidArgumentException $e) {
+ // Failed to encrypt message for device: public key is invalid
+ $this->deletePushToken($device['token']);
+ return [];
}
}
@@ -472,21 +534,28 @@ class Push {
/**
* @param Key $userKey
* @param array $device
- * @param int $id
+ * @param int[] $ids
* @return array
* @throws InvalidTokenException
* @throws \InvalidArgumentException
*/
- protected function encryptAndSignDelete(Key $userKey, array $device, int $id): array {
- if ($id === 0) {
+ protected function encryptAndSignDelete(Key $userKey, array $device, array $ids): array {
+ $remainingIds = [];
+ if (empty($ids)) {
$data = [
'delete-all' => true,
];
- } else {
+ } else if (count($ids) === 1) {
$data = [
- 'nid' => $id,
+ 'nid' => array_pop($ids),
'delete' => true,
];
+ } else {
+ $remainingIds = array_splice($ids, 10);
+ $data = [
+ 'nids' => $ids,
+ 'delete-multiple' => true,
+ ];
}
if (!openssl_public_encrypt(json_encode($data), $encryptedSubject, $device['devicepublickey'], OPENSSL_PKCS1_PADDING)) {
@@ -499,12 +568,15 @@ class Push {
$base64Signature = base64_encode($signature);
return [
- 'deviceIdentifier' => $device['deviceidentifier'],
- 'pushTokenHash' => $device['pushtokenhash'],
- 'subject' => $base64EncryptedSubject,
- 'signature' => $base64Signature,
- 'priority' => 'normal',
- 'type' => 'background',
+ 'remaining' => $remainingIds,
+ 'payload' => [
+ 'deviceIdentifier' => $device['deviceidentifier'],
+ 'pushTokenHash' => $device['pushtokenhash'],
+ 'subject' => $base64EncryptedSubject,
+ 'signature' => $base64Signature,
+ 'priority' => 'normal',
+ 'type' => 'background',
+ ],
];
}