Skip to content

Commit

Permalink
Commit to multicast broadcasts
Browse files Browse the repository at this point in the history
  • Loading branch information
dwightwatson committed Oct 9, 2023
1 parent 3ff72ff commit 6280555
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 156 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: [8.1, 8.2]
laravel: [9.*]
php: [8.2]
laravel: [10.*]
stability: [prefer-lowest, prefer-stable]

name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}
Expand Down
13 changes: 3 additions & 10 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
}
],
"require": {
"php": ">= 8.1",
"php": ">= 8.2",
"guzzlehttp/guzzle": "^7.0",
"illuminate/notifications": "^9.0|^10.0",
"illuminate/support": "^9.0|^10.0",
"illuminate/notifications": "^10.0",
"illuminate/support": "^10.0",
"kreait/laravel-firebase": "^5.0"
},
"require-dev": {
Expand All @@ -32,13 +32,6 @@
"NotificationChannels\\Fcm\\Test\\": "tests"
}
},
"extra": {
"laravel": {
"providers": [
"NotificationChannels\\Fcm\\FcmServiceProvider"
]
}
},
"scripts": {
"test": "vendor/bin/phpunit"
},
Expand Down
29 changes: 0 additions & 29 deletions src/Exceptions/CouldNotSendNotification.php

This file was deleted.

13 changes: 13 additions & 0 deletions src/Exceptions/InvalidPropertyException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace NotificationChannels\Fcm\Exceptions;

use Exception;

class InvalidPropertyException extends Exception
{
public static function mustBeString($key)
{
return new static('The value of ' . $key . ' must be a string');
}
}
116 changes: 26 additions & 90 deletions src/FcmChannel.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,18 @@
use Illuminate\Notifications\Notification;
use Illuminate\Support\Arr;
use Kreait\Firebase\Exception\MessagingException;
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Firebase\Messaging\Message;
use Kreait\Firebase\Messaging\MulticastSendReport;
use Kreait\Firebase\Messaging\SendReport;
use NotificationChannels\Fcm\Exceptions\CouldNotSendNotification;
use ReflectionException;
use Throwable;

class FcmChannel
{
const MAX_TOKEN_PER_REQUEST = 500;
const TOKENS_PER_REQUEST = 500;

/**
* FcmChannel constructor.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* Create a new channel instance.
*/
public function __construct(protected Dispatcher $events)
{
Expand All @@ -40,125 +36,65 @@ public function __construct(protected Dispatcher $events)
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @return array
*
* @throws \NotificationChannels\Fcm\Exceptions\CouldNotSendNotification
* @throws \Kreait\Firebase\Exception\FirebaseException
* @return void
*/
public function send($notifiable, Notification $notification)
public function send($notifiable, Notification $notification): void
{
$tokens = Arr::wrap($notifiable->routeNotificationFor('fcm', $notification));

if (empty($tokens)) {
return [];
return;
}

// Get the message from the notification class
$fcmMessage = $notification->toFcm($notifiable);

if (!$fcmMessage instanceof Message) {
throw CouldNotSendNotification::invalidMessage();
}

$this->fcmProject = null;
if (method_exists($notification, 'fcmProject')) {
$this->fcmProject = $notification->fcmProject($notifiable, $fcmMessage);
}

$responses = [];

try {
$partialTokens = array_chunk($tokens, self::MAX_TOKEN_PER_REQUEST, false);

foreach ($partialTokens as $tokens) {
$responses[] = $this->sendToFcmMulticast($fcmMessage, $tokens);
}

/** @var MulticastSendReport $failedMulticastSendReport */
foreach (array_filter($responses, fn(MulticastSendReport $report) => $report->hasFailures()) as $failedMulticastSendReport) {
/** @var SendReport $failedSendReport */
foreach (array_filter($failedMulticastSendReport->getItems(), fn(SendReport $sendReport) => $sendReport->isFailure()) as $failedSendReport) {
$this->failedNotification($notifiable, $notification, $failedSendReport->error(), $failedSendReport->target()->value());
}
}

} catch (MessagingException $exception) {
$this->failedNotification($notifiable, $notification, $exception, $tokens);
throw CouldNotSendNotification::serviceRespondedWithAnError($exception);
}

return $responses;
collect($tokens)
->chunk(self::TOKENS_PER_REQUEST)
->map(fn ($tokens) => $this->messaging()->sendMulticast($fcmMessage, $tokens))
->map(function (MulticastSendReport $report) {
collect($report->getItems())
->filter(fn (SendReport $report) => $report->isFailure())
->each(function (SendReport $report) {
$this->failedNotification($notifiable, $notification, $report);
});
});
}

/**
* @return \Kreait\Firebase\Messaging
* Get the messaging instance.
*/
protected function messaging()
protected function messaging(): Messaging
{
try {
$messaging = app('firebase.manager')->project($this->fcmProject)->messaging();
} catch (BindingResolutionException $e) {
$messaging = app('firebase.messaging');
} catch (ReflectionException $e) {
$messaging = app('firebase.messaging');
}

return $messaging;
}

/**
* @param \Kreait\Firebase\Messaging\Message $fcmMessage
* @param $token
* @return array
*
* @throws \Kreait\Firebase\Exception\MessagingException
* @throws \Kreait\Firebase\Exception\FirebaseException
*/
protected function sendToFcm(Message $fcmMessage, $token)
{
if ($fcmMessage instanceof CloudMessage) {
$fcmMessage = $fcmMessage->withChangedTarget('token', $token);
}

if ($fcmMessage instanceof FcmMessage) {
$fcmMessage->setToken($token);
return app('firebase.manager')->project($this->fcmProject)->messaging();
} catch (BindingResolutionException | ReflectionException $e) {
return app('firebase.messaging');
}

return $this->messaging()->send($fcmMessage);
}

/**
* @param $fcmMessage
* @param array $tokens
* @return \Kreait\Firebase\Messaging\MulticastSendReport
*
* @throws \Kreait\Firebase\Exception\MessagingException
* @throws \Kreait\Firebase\Exception\FirebaseException
*/
protected function sendToFcmMulticast($fcmMessage, array $tokens)
{
return $this->messaging()->sendMulticast($fcmMessage, $tokens);
}

/**
* Dispatch failed event.
*
* @param mixed $notifiable
* @param \Illuminate\Notifications\Notification $notification
* @param \Throwable $exception
* @param string|array $token
* @return array|null
* @param \Kreait\Firebase\Messaging\SendReport $report
*/
protected function failedNotification($notifiable, Notification $notification, Throwable $exception, $token)
protected function failedNotification($notifiable, Notification $notification, SendReport $report, $token): void
{
return $this->events->dispatch(new NotificationFailed(
$this->events->dispatch(new NotificationFailed(
$notifiable,
$notification,
self::class,
[
'message' => $exception->getMessage(),
'exception' => $exception,
'token' => $token,
'message' => $report->message(),
'exception' => $report->error(),
'token' => $report->target()->value(),
]
));
}
Expand Down
6 changes: 3 additions & 3 deletions src/FcmMessage.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Illuminate\Support\Traits\Macroable;
use Kreait\Firebase\Messaging\Message;
use NotificationChannels\Fcm\Exceptions\CouldNotSendNotification;
use NotificationChannels\Fcm\Exceptions\InvalidPropertyException;
use NotificationChannels\Fcm\Resources\AndroidConfig;
use NotificationChannels\Fcm\Resources\ApnsConfig;
use NotificationChannels\Fcm\Resources\FcmOptions;
Expand Down Expand Up @@ -101,13 +101,13 @@ public function getData(): ?array
* @param array<string, string>|null $data
* @return $this
*
* @throws \NotificationChannels\Fcm\Exceptions\CouldNotSendNotification
* @throws \NotificationChannels\Fcm\Exceptions\InvalidPropertyException
*/
public function setData(?array $data): self
{
foreach ($data as $key => $item) {
if (! is_string($item)) {
throw CouldNotSendNotification::invalidPropertyInArray($key);
throw InvalidPropertyException::mustBeString($key);
}
}

Expand Down
16 changes: 0 additions & 16 deletions src/FcmServiceProvider.php

This file was deleted.

6 changes: 3 additions & 3 deletions src/Resources/AndroidConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace NotificationChannels\Fcm\Resources;

use NotificationChannels\Fcm\Exceptions\CouldNotSendNotification;
use NotificationChannels\Fcm\Exceptions\InvalidPropertyException;

class AndroidConfig implements FcmResource
{
Expand Down Expand Up @@ -137,13 +137,13 @@ public function getData(): ?array
* @param array|null $data
* @return AndroidConfig
*
* @throws \NotificationChannels\Fcm\Exceptions\CouldNotSendNotification
* @throws \NotificationChannels\Fcm\Exceptions\InvalidPropertyException
*/
public function setData(?array $data): self
{
foreach ($data as $key => $item) {
if (! is_string($item)) {
throw CouldNotSendNotification::invalidPropertyInArray($key);
throw InvalidPropertyException::mustBeString($key);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/Resources/WebpushConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace NotificationChannels\Fcm\Resources;

use NotificationChannels\Fcm\Exceptions\CouldNotSendNotification;
use NotificationChannels\Fcm\Exceptions\InvalidPropertyException;

class WebpushConfig implements FcmResource
{
Expand Down Expand Up @@ -65,13 +65,13 @@ public function getData(): ?array
* @param array|null $data
* @return WebpushConfig
*
* @throws \NotificationChannels\Fcm\Exceptions\CouldNotSendNotification
* @throws \NotificationChannels\Fcm\Exceptions\InvalidPropertyException
*/
public function setData(?array $data): self
{
foreach ($data as $key => $item) {
if (! is_string($item)) {
throw CouldNotSendNotification::invalidPropertyInArray($key);
throw InvalidPropertyException::mustBeString($key);
}
}

Expand Down

0 comments on commit 6280555

Please sign in to comment.