Files
f7push/lib/Service/PushDispatcher.php
T
root df4e2dddec Add f7push v0.1: FCM device registry and push API for F7cloud.
Portable occ-based config, OCS endpoints for APK registration, notification relay, and server-side push dispatch.
2026-05-24 10:26:36 +03:00

147 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\F7Push\Service;
use OCA\F7Push\Db\Device;
use OCA\F7Push\Db\DeviceMapper;
use OCA\F7Push\Model\PushMessage;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Notification\INotification;
use Psr\Log\LoggerInterface;
class PushDispatcher {
public function __construct(
private DeviceMapper $deviceMapper,
private FirebaseClient $firebaseClient,
private ConfigService $config,
private ITimeFactory $timeFactory,
private LoggerInterface $logger,
) {
}
public function registerDevice(
string $userId,
string $deviceId,
string $fcmToken,
string $platform,
string $clientApp,
): Device {
$now = $this->timeFactory->getTime();
try {
$device = $this->deviceMapper->findByUserAndDevice($userId, $deviceId);
$device->setFcmToken($fcmToken);
$device->setPlatform($platform);
$device->setClientApp($clientApp);
$device->setLastSeen($now);
return $this->deviceMapper->update($device);
} catch (DoesNotExistException) {
$device = new Device();
$device->setUserId($userId);
$device->setDeviceId($deviceId);
$device->setFcmToken($fcmToken);
$device->setPlatform($platform);
$device->setClientApp($clientApp);
$device->setCreatedAt($now);
$device->setLastSeen($now);
return $this->deviceMapper->insert($device);
}
}
public function unregisterDevice(string $userId, string $deviceId): void {
$this->deviceMapper->deleteByUserAndDevice($userId, $deviceId);
}
/**
* @return Device[]
*/
public function listDevices(string $userId): array {
return $this->deviceMapper->findByUser($userId);
}
public function dispatch(PushMessage $message): int {
if (!$this->config->isEnabled()) {
return 0;
}
if (!$this->config->isSourceEnabled($message->source)) {
return 0;
}
$devices = $this->deviceMapper->findByUser($message->userId);
if ($devices === []) {
return 0;
}
$url = $message->url ?? $this->config->getDefaultClickUrl();
$sent = 0;
foreach ($devices as $device) {
$token = $device->getFcmToken();
if ($token === '') {
continue;
}
if ($this->firebaseClient->sendToToken($token, $message->title, $message->body, $url, $message->priority)) {
$sent++;
}
}
$this->logger->debug('f7push: dispatched push', [
'app' => 'f7push',
'user' => $message->userId,
'source' => $message->source,
'sent' => $sent,
'devices' => count($devices),
]);
return $sent;
}
public function dispatchFromNotification(INotification $notification): int {
if (!$this->config->listenNotifications()) {
return 0;
}
$user = $notification->getUser();
if ($user === null || $user === '') {
return 0;
}
$source = $notification->getApp();
if (!$this->config->isSourceEnabled($source)) {
return 0;
}
$title = $notification->getParsedSubject();
if ($title === '') {
$title = $notification->getSubject();
}
$body = $notification->getParsedMessage();
if ($body === '') {
$body = $notification->getMessage();
}
if ($title === '' && $body === '') {
return 0;
}
if ($title === '') {
$title = $body;
}
$link = $notification->getLink();
if ($link !== '' && !str_starts_with($link, 'http://') && !str_starts_with($link, 'https://')) {
$link = $this->config->getDefaultClickUrl() . $link;
}
$priority = $source === 'spreed' ? 'high' : 'normal';
return $this->dispatch(new PushMessage(
userId: $user,
title: $title,
body: $body,
source: $source,
priority: $priority,
url: $link !== '' ? $link : null,
));
}
}