From b992cde35769899e4ee99fcdb8a096dcfd8868d4 Mon Sep 17 00:00:00 2001 From: Jonathan Treffler <mail@jonathan-treffler.de> Date: Fri, 5 Apr 2024 20:26:15 +0200 Subject: [PATCH] app init; implemented service detection --- .vscode/launch.json | 38 +++++++++ appinfo/info.xml | 18 ++++ appinfo/routes.php | 11 +++ lib/AppInfo/Application.php | 30 +++++++ lib/Dav/ServiceDetectionPlugin.php | 106 ++++++++++++++++++++++++ lib/Event/RegisterTransportsEvent.php | 28 +++++++ lib/Listener/SabrePluginAddListener.php | 25 ++++++ lib/PushTransports/WebPushTransport.php | 11 +++ lib/Transport/Transport.php | 17 ++++ lib/Transport/TransportManager.php | 38 +++++++++ 10 files changed, 322 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 appinfo/info.xml create mode 100644 appinfo/routes.php create mode 100644 lib/AppInfo/Application.php create mode 100644 lib/Dav/ServiceDetectionPlugin.php create mode 100644 lib/Event/RegisterTransportsEvent.php create mode 100644 lib/Listener/SabrePluginAddListener.php create mode 100644 lib/PushTransports/WebPushTransport.php create mode 100644 lib/Transport/Transport.php create mode 100644 lib/Transport/TransportManager.php diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..317d206 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,38 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch built-in server and debug", + "type": "php", + "request": "launch", + "runtimeArgs": [ + "-S", + "localhost:8000", + "-t", + "." + ], + "port": 9003, + "serverReadyAction": { + "action": "openExternally" + } + }, + { + "name": "Debug current script in console", + "type": "php", + "request": "launch", + "program": "${file}", + "cwd": "${fileDirname}", + "externalConsole": false, + "port": 9003 + }, + { + "name": "Listen for Xdebug", + "type": "php", + "request": "launch", + "port": 9003 + } + ] +} \ No newline at end of file diff --git a/appinfo/info.xml b/appinfo/info.xml new file mode 100644 index 0000000..722063e --- /dev/null +++ b/appinfo/info.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> + <id>dav_push</id> + <name>DAV Push</name> + <summary>Implements the DAV Push specification</summary> + <description><![CDATA[This app allows you to send push notifications from your Nextcloud server to different clients, including mobile devices, desktop computers, and web browsers.]]></description> + <version>0.0.1</version> + <licence>agpl</licence> + <author mail="info@bitfire.at" homepage="https://github.com/bitfireAT/webdav-push">bitfire web engineering</author> + <author mail="mail@jonathan-treffler.de">Jonathan Treffler</author> + <namespace>DavPush</namespace> + <category>tools</category> + <bugs>https://github.com/bitfireAT/nc-ext-caldav-carddav-push/issues</bugs> + <dependencies> + <nextcloud min-version="28" max-version="28"/> + </dependencies> +</info> \ No newline at end of file diff --git a/appinfo/routes.php b/appinfo/routes.php new file mode 100644 index 0000000..b9eca4d --- /dev/null +++ b/appinfo/routes.php @@ -0,0 +1,11 @@ +<?php +declare(strict_types=1); +// SPDX-FileCopyrightText: bitfire web engineering GmbH <info@bitfire.at> +// SPDX-License-Identifier: AGPL-3.0-or-later + +return [ + 'resources' => [ + ], + 'routes' => [ + ] +]; \ No newline at end of file diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php new file mode 100644 index 0000000..43fabd5 --- /dev/null +++ b/lib/AppInfo/Application.php @@ -0,0 +1,30 @@ +<?php + +// SPDX-FileCopyrightText: bitfire web engineering GmbH <info@bitfire.at> +// SPDX-License-Identifier: AGPL-3.0-or-later + +namespace OCA\DavPush\AppInfo; + +use OCP\AppFramework\App; +use OCP\AppFramework\Bootstrap\IBootstrap; +use OCP\AppFramework\Bootstrap\IRegistrationContext; +use OCP\AppFramework\Bootstrap\IBootContext; + +use OCA\DAV\Events\SabrePluginAddEvent; + +use OCA\DavPush\Listener\SabrePluginAddListener; + +class Application extends App implements IBootstrap { + public const APP_ID = 'dav_push'; + + public function __construct() { + parent::__construct(self::APP_ID); + } + + public function register(IRegistrationContext $context): void { + $context->registerEventListener(SabrePluginAddEvent::class, SabrePluginAddListener::class); + } + + public function boot(IBootContext $context): void { + } +} \ No newline at end of file diff --git a/lib/Dav/ServiceDetectionPlugin.php b/lib/Dav/ServiceDetectionPlugin.php new file mode 100644 index 0000000..c5a4da6 --- /dev/null +++ b/lib/Dav/ServiceDetectionPlugin.php @@ -0,0 +1,106 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright 2024 Christopher Ng <chrng8@gmail.com> + * + * @author Christopher Ng <chrng8@gmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\DavPush\Dav; + +use OCP\IUser; +use OCP\IUserSession; + +use OCP\AppFramework\Db\DoesNotExistException; +use OCA\DAV\Connector\Sabre\Node; +use OCA\DavPush\Transport\TransportManager; + +use Sabre\DAV\INode; +use Sabre\DAV\PropFind; +use Sabre\DAV\Server; +use Sabre\DAV\ServerPlugin; + +class ServiceDetectionPlugin extends ServerPlugin { + + public const PUSH_PREFIX = '{DAV:Push}'; + public const PROPERTY_PUSH_TRANSPORTS = self::PUSH_PREFIX . 'push-transports'; + public const PROPERTY_PUSH_TOPIC = self::PUSH_PREFIX . 'topic'; + + + public function __construct( + private IUserSession $userSession, + private TransportManager $transportManager, + ) { + } + + public function initialize(Server $server): void { + $server->on('propFind', [$this, 'propFind']); + } + + public function propFind(PropFind $propFind, INode $node) { + if (count(array_intersect([self::PROPERTY_PUSH_TRANSPORTS, self::PROPERTY_PUSH_TOPIC], $propFind->getRequestedProperties())) == 0) { + return; + } + + //if (!($node instanceof Node)) { + // return; + //} + + $propFind->handle( + self::PROPERTY_PUSH_TRANSPORTS, + function () use ($node) { + //$user = $this->userSession->getUser(); + //if (!($user instanceof IUser)) { + // return []; + //} + + $transports = $this->transportManager->getTransports(); + + $result = []; + + foreach($transports as $transport) { + $result[] = [ + (self::PUSH_PREFIX . "transport") => [ + (self::PUSH_PREFIX . $transport->getId()) => $transport->getAdditionalInformation(), + ] + ]; + } + + //throw new \Exception( "\$result = " . json_encode($result) ); + + return $result; + }, + ); + + $propFind->handle( + self::PROPERTY_PUSH_TOPIC, + //function () use ($node) { + //$user = $this->userSession->getUser(); + //if (!($user instanceof IUser)) { + // return []; + //} + + // return "test-return-push"; + //}, + "test-return-push-topic" + ); + } +} \ No newline at end of file diff --git a/lib/Event/RegisterTransportsEvent.php b/lib/Event/RegisterTransportsEvent.php new file mode 100644 index 0000000..34a3db9 --- /dev/null +++ b/lib/Event/RegisterTransportsEvent.php @@ -0,0 +1,28 @@ +<?php + +declare(strict_types=1); + +namespace OCA\DavPush\Event; + +use OCP\EventDispatcher\Event; + +use OCA\DavPush\Transport\TransportManager; + +/** + * This event is triggered during the initialization of DAV Push. + * Use it to register external push transports. + */ +class RegisterTransportsEvent extends Event { + + /** @var TransportManager */ + private $transportManager; + + public function __construct(TransportManager $transportManager) { + parent::__construct(); + $this->transportManager = $transportManager; + } + + public function getTransportManager(): TransportManager { + return $this->transportManager; + } +} \ No newline at end of file diff --git a/lib/Listener/SabrePluginAddListener.php b/lib/Listener/SabrePluginAddListener.php new file mode 100644 index 0000000..ef2876d --- /dev/null +++ b/lib/Listener/SabrePluginAddListener.php @@ -0,0 +1,25 @@ +<?php + +declare(strict_types=1); + +namespace OCA\DavPush\Listener; + +use OCA\DAV\Events\SabrePluginAddEvent; +use OCA\DavPush\Dav\ServiceDetectionPlugin; + +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; + +use Psr\Container\ContainerInterface; + +class SabrePluginAddListener implements IEventListener { + public function __construct(private ContainerInterface $container) {} + + public function handle(Event $event): void { + if ($event instanceof SabrePluginAddEvent) { + $serviceDetectionPlugin = $this->container->get(ServiceDetectionPlugin::class); + + $event->getServer()->addPlugin($serviceDetectionPlugin); + } + } +} \ No newline at end of file diff --git a/lib/PushTransports/WebPushTransport.php b/lib/PushTransports/WebPushTransport.php new file mode 100644 index 0000000..6a8333a --- /dev/null +++ b/lib/PushTransports/WebPushTransport.php @@ -0,0 +1,11 @@ +<?php + +declare(strict_types=1); + +namespace OCA\DavPush\PushTransports; + +use OCA\DavPush\Transport\Transport; + +class WebPushTransport extends Transport { + protected $id = "web-push"; +} \ No newline at end of file diff --git a/lib/Transport/Transport.php b/lib/Transport/Transport.php new file mode 100644 index 0000000..a0cc6ff --- /dev/null +++ b/lib/Transport/Transport.php @@ -0,0 +1,17 @@ +<?php + +declare(strict_types=1); + +namespace OCA\DavPush\Transport; + +abstract class Transport { + protected $id; + + public function getId() { + return $this->id; + } + + public function getAdditionalInformation() { + return []; + } +} \ No newline at end of file diff --git a/lib/Transport/TransportManager.php b/lib/Transport/TransportManager.php new file mode 100644 index 0000000..d82fb6e --- /dev/null +++ b/lib/Transport/TransportManager.php @@ -0,0 +1,38 @@ +<?php + +declare(strict_types=1); + +namespace OCA\DavPush\Transport; + +use OCP\EventDispatcher\IEventDispatcher; + +use OCA\DavPush\Event\RegisterTransportsEvent; +use OCA\DavPush\PushTransports\WebPushTransport; + +class TransportManager { + /** + * @var Transport[] + */ + private array $transports = []; + + public function __construct(IEventDispatcher $dispatcher) { + // register integrated transports + $this->registerTransport(new WebPushTransport()); + + // register transports provided by other apps + $event = new RegisterTransportsEvent($this); + $dispatcher->dispatchTyped($event); + } + + /** + * @return Transport[] + */ + public function getTransports(): array { + return $this->transports; + } + + public function registerTransport(Transport $transport): self { + $this->transports[] = $transport; + return $this; + } +} \ No newline at end of file