From e2805beb164984578508854eca0f3265f93c1614 Mon Sep 17 00:00:00 2001 From: Jonathan Treffler Date: Sat, 14 Sep 2024 16:52:54 +0200 Subject: [PATCH] switch to GuzzleHttp for web push transport, parallelize notification sending --- lib/Listener/CalendarListener.php | 18 +++++++++++------- lib/PushTransports/WebPushTransport.php | 22 +++++++++++++--------- lib/Transport/Transport.php | 4 +++- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/Listener/CalendarListener.php b/lib/Listener/CalendarListener.php index b5db97d..59f78a3 100644 --- a/lib/Listener/CalendarListener.php +++ b/lib/Listener/CalendarListener.php @@ -37,6 +37,7 @@ use OCA\DAV\Events\CardDeletedEvent; use OCA\DAV\Events\CardUpdatedEvent; use Psr\Log\LoggerInterface; +use GuzzleHttp\Promise; use OCA\DavPush\Service\SubscriptionService; use OCA\DavPush\Transport\TransportManager; @@ -59,13 +60,16 @@ class CalendarListener implements IEventListener { $collectionName = $event->getCalendarData()['uri']; $subscriptions = $this->subscriptionService->findAll($collectionName); - foreach($subscriptions as $subscription) { - $transport = $this->transportManager->getTransport($subscription->getTransport()); - try { - $transport->notify($subscription->getUserId(), $collectionName, $subscription->getId()); - } catch (\Exception $e) { - $this->logger->error("transport " . $subscription->getTransport() . " failed to deliver notification to subscription " . $subscription->getId()); + $notificationPromises = (function () use ($collectionName, $subscriptions): Generator { + foreach($subscriptions as $subscription) { + $transport = $this->transportManager->getTransport($subscription->getTransport()); + yield $transport->notify($subscription->getUserId(), $collectionName, $subscription->getId()); } - } + })(); + + $responses = Promise\Utils::settle($notificationPromises)->wait(); + + // TODO: iterate over responses and log errors + // $this->logger->error("transport " . $subscription->getTransport() . " failed to deliver notification to subscription " . $subscription->getId()); } } diff --git a/lib/PushTransports/WebPushTransport.php b/lib/PushTransports/WebPushTransport.php index 330446a..7c16843 100644 --- a/lib/PushTransports/WebPushTransport.php +++ b/lib/PushTransports/WebPushTransport.php @@ -30,6 +30,9 @@ use OCA\DavPush\Transport\Transport; use OCA\DavPush\Service\WebPushSubscriptionService; use OCA\DavPush\Errors\WebPushSubscriptionNotFound; +use OCP\Http\Client\IClientService; +use OCP\Http\Client\IPromise; + use Sabre\Xml\Service; class WebPushTransport extends Transport { @@ -37,6 +40,7 @@ class WebPushTransport extends Transport { public function __construct( private WebPushSubscriptionService $webPushSubscriptionService, + private IClientService $httpClientService ) {} private function parseOptions(array $options): array { @@ -79,7 +83,7 @@ class WebPushTransport extends Transport { ]; } - public function notify(string $userId, string $collectionName, int $subscriptionId) { + public function notify(string $userId, string $collectionName, int $subscriptionId): IPromise { $xmlService = new Service(); $pushResource = $this->webPushSubscriptionService->findBySubscriptionId($subscriptionId)->getPushResource(); @@ -88,15 +92,15 @@ class WebPushTransport extends Transport { '{DAV:Push}topic' => $collectionName, ]); - $options = [ - 'http' => [ - 'method' => 'POST', - 'content' => $content, - ], - ]; + $httpClient = $this->httpClientService->newClient(); - $context = stream_context_create($options); - $result = file_get_contents($pushResource, false, $context); + return $httpClient->postAsync($pushResource, [ + "body" => $content, + "timeout" => 10, + "headers" => [ + "Content-Type" => "application/xml", + ], + ]); } public function getSubscriptionIdFromOptions(string $userId, string $collectionName, $options): ?int { diff --git a/lib/Transport/Transport.php b/lib/Transport/Transport.php index f3da2bd..e8f419e 100644 --- a/lib/Transport/Transport.php +++ b/lib/Transport/Transport.php @@ -26,6 +26,8 @@ declare(strict_types=1); namespace OCA\DavPush\Transport; +use OCP\Http\Client\IPromise; + abstract class Transport { protected $id; @@ -69,5 +71,5 @@ abstract class Transport { // Change mutable options of the subscription (if any exist) abstract public function updateSubscription($subsciptionId, $options); - abstract public function notify(string $userId, string $collectionName, int $subscriptionId); + abstract public function notify(string $userId, string $collectionName, int $subscriptionId): IPromise; } \ No newline at end of file