--- /dev/null
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @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\Files_External\Lib\Notify;
+
+use OC\Files\Notify\Change;
+use OC\Files\Notify\RenameChange;
+use OCP\Files\Notify\IChange;
+use OCP\Files\Notify\INotifyHandler;
+
+class SMBNotifyHandler implements INotifyHandler {
+ /**
+ * @var \Icewind\SMB\INotifyHandler
+ */
+ private $shareNotifyHandler;
+
+ /**
+ * @var string
+ */
+ private $root;
+
+ private $oldRenamePath = null;
+
+ /**
+ * SMBNotifyHandler constructor.
+ *
+ * @param \Icewind\SMB\INotifyHandler $shareNotifyHandler
+ * @param string $root
+ */
+ public function __construct(\Icewind\SMB\INotifyHandler $shareNotifyHandler, $root) {
+ $this->shareNotifyHandler = $shareNotifyHandler;
+ $this->root = $root;
+ }
+
+ private function relativePath($fullPath) {
+ if ($fullPath === $this->root) {
+ return '';
+ } else if (substr($fullPath, 0, strlen($this->root)) === $this->root) {
+ return substr($fullPath, strlen($this->root));
+ } else {
+ return null;
+ }
+ }
+
+ public function listen(callable $callback) {
+ $oldRenamePath = null;
+ $this->shareNotifyHandler->listen(function (\Icewind\SMB\Change $shareChange) use ($callback) {
+ $change = $this->mapChange($shareChange);
+ if (!is_null($change)) {
+ return $callback($change);
+ } else {
+ return true;
+ }
+ });
+ }
+
+ /**
+ * Get all changes detected since the start of the notify process or the last call to getChanges
+ *
+ * @return IChange[]
+ */
+ public function getChanges() {
+ $shareChanges = $this->shareNotifyHandler->getChanges();
+ $changes = [];
+ foreach ($shareChanges as $shareChange) {
+ $change = $this->mapChange($shareChange);
+ if ($change) {
+ $changes[] = $change;
+ }
+ }
+ return $changes;
+ }
+
+ /**
+ * Stop listening for changes
+ *
+ * Note that any pending changes will be discarded
+ */
+ public function stop() {
+ $this->shareNotifyHandler->stop();
+ }
+
+ /**
+ * @param \Icewind\SMB\Change $change
+ * @return IChange|null
+ */
+ private function mapChange(\Icewind\SMB\Change $change) {
+ $path = $this->relativePath($change->getPath());
+ if (is_null($path)) {
+ return null;
+ }
+ if ($change->getCode() === \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_OLD) {
+ $this->oldRenamePath = $path;
+ return null;
+ }
+ $type = $this->mapNotifyType($change->getCode());
+ if (is_null($type)) {
+ return null;
+ }
+ if ($type === IChange::RENAMED) {
+ if (!is_null($this->oldRenamePath)) {
+ $result = new RenameChange($type, $this->oldRenamePath, $path);
+ $this->oldRenamePath = null;
+ } else {
+ $result = null;
+ }
+ } else {
+ $result = new Change($type, $path);
+ }
+ return $result;
+ }
+
+ private function mapNotifyType($smbType) {
+ switch ($smbType) {
+ case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED:
+ return IChange::ADDED;
+ case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED:
+ return IChange::REMOVED;
+ case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED:
+ case \Icewind\SMB\INotifyHandler::NOTIFY_ADDED_STREAM:
+ case \Icewind\SMB\INotifyHandler::NOTIFY_MODIFIED_STREAM:
+ case \Icewind\SMB\INotifyHandler::NOTIFY_REMOVED_STREAM:
+ return IChange::MODIFIED;
+ case \Icewind\SMB\INotifyHandler::NOTIFY_RENAMED_NEW:
+ return IChange::RENAMED;
+ default:
+ return null;
+ }
+ }
+}
use OC\Cache\CappedMemoryCache;
use OC\Files\Filesystem;
use OC\Files\Storage\Common;
+use OCA\Files_External\Lib\Notify\SMBNotifyHandler;
+use OCP\Files\Notify\IChange;
+use OCP\Files\Notify\IRenameChange;
use OCP\Files\Storage\INotifyStorage;
use OCP\Files\StorageNotAvailableException;
foreach ($files as $file) {
$this->statCache[$path . '/' . $file->getName()] = $file;
}
- return array_filter($files, function(IFileInfo $file) {
+ return array_filter($files, function (IFileInfo $file) {
return !$file->isHidden();
});
} catch (ConnectException $e) {
}
public function listen($path, callable $callback) {
- $fullPath = $this->buildPath($path);
- $oldRenamePath = null;
- $this->share->notify($fullPath)->listen(function (Change $change) use (&$oldRenamePath, $callback) {
- $path = $this->relativePath($change->getPath());
- if (is_null($path)) {
- return true;
- }
- if ($change->getCode() === INotifyHandler::NOTIFY_RENAMED_OLD) {
- $oldRenamePath = $path;
- return true;
- }
- $type = $this->mapNotifyType($change->getCode());
- if (is_null($type)) {
- return true;
- }
- if ($type === INotifyStorage::NOTIFY_RENAMED) {
- if (!is_null($oldRenamePath)) {
- $result = $callback($type, $oldRenamePath, $path);
- $oldRenamePath = null;
- }
+ $this->notify($path)->listen(function (IChange $change) use ($callback) {
+ if ($change instanceof IRenameChange) {
+ return $callback($change->getType(), $change->getPath(), $change->getTargetPath());
} else {
- $result = $callback($type, $path);
+ return $callback($change->getType(), $change->getPath());
}
- return $result;
});
}
- private function mapNotifyType($smbType) {
- switch ($smbType) {
- case INotifyHandler::NOTIFY_ADDED:
- return INotifyStorage::NOTIFY_ADDED;
- case INotifyHandler::NOTIFY_REMOVED:
- return INotifyStorage::NOTIFY_REMOVED;
- case INotifyHandler::NOTIFY_MODIFIED:
- case INotifyHandler::NOTIFY_ADDED_STREAM:
- case INotifyHandler::NOTIFY_MODIFIED_STREAM:
- case INotifyHandler::NOTIFY_REMOVED_STREAM:
- return INotifyStorage::NOTIFY_MODIFIED;
- case INotifyHandler::NOTIFY_RENAMED_NEW:
- return INotifyStorage::NOTIFY_RENAMED;
- default:
- return null;
- }
+ public function notify($path) {
+ $shareNotifyHandler = $this->share->notify($this->buildPath($path));
+ return new SMBNotifyHandler($shareNotifyHandler, $this->root);
}
}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @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 OC\Files\Notify;
+
+use OCP\Files\Notify\IChange;
+
+class Change implements IChange {
+ /** @var int */
+ private $type;
+
+ /** @var string */
+ private $path;
+
+ /**
+ * Change constructor.
+ *
+ * @param int $type
+ * @param string $path
+ */
+ public function __construct($type, $path) {
+ $this->type = $type;
+ $this->path = $path;
+ }
+
+ /**
+ * Get the type of the change
+ *
+ * @return int IChange::ADDED, IChange::REMOVED, IChange::MODIFIED or IChange::RENAMED
+ */
+ public function getType() {
+ return $this->type;
+ }
+
+ /**
+ * Get the path of the file that was changed relative to the root of the storage
+ *
+ * Note, for rename changes this path is the old path for the file
+ *
+ * @return mixed
+ */
+ public function getPath() {
+ return $this->path;
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @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 OC\Files\Notify;
+
+use OCP\Files\Notify\IRenameChange;
+
+class RenameChange extends Change implements IRenameChange {
+ /** @var string */
+ private $targetPath;
+
+ /**
+ * Change constructor.
+ *
+ * @param int $type
+ * @param string $path
+ * @param string $targetPath
+ */
+ public function __construct($type, $path, $targetPath) {
+ parent::__construct($type, $path);
+ $this->targetPath = $targetPath;
+ }
+
+ /**
+ * Get the new path of the renamed file relative to the storage root
+ *
+ * @return string
+ */
+ public function getTargetPath() {
+ return $this->targetPath;
+ }
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @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 OCP\Files\Notify;
+
+interface IChange {
+ const ADDED = 1;
+ const REMOVED = 2;
+ const MODIFIED = 3;
+ const RENAMED = 4;
+
+ /**
+ * Get the type of the change
+ *
+ * @return int IChange::ADDED, IChange::REMOVED, IChange::MODIFIED or IChange::RENAMED
+ */
+ public function getType();
+
+ /**
+ * Get the path of the file that was changed relative to the root of the storage
+ *
+ * Note, for rename changes this path is the old path for the file
+ *
+ * @return mixed
+ */
+ public function getPath();
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @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 OCP\Files\Notify;
+
+interface INotifyHandler {
+ /**
+ * Start listening for update notifications
+ *
+ * The provided callback will be called for every incoming notification with the following parameters
+ * - IChange|IRenameChange $change
+ *
+ * Note that this call is blocking and will not exit on it's own, to stop listening for notifications return `false` from the callback
+ *
+ * @param callable $callback
+ */
+ public function listen(callable $callback);
+
+ /**
+ * Get all changes detected since the start of the notify process or the last call to getChanges
+ *
+ * @return IChange[]
+ */
+ public function getChanges();
+
+ /**
+ * Stop listening for changes
+ *
+ * Note that any pending changes will be discarded
+ */
+ public function stop();
+}
--- /dev/null
+<?php
+/**
+ * @copyright Copyright (c) 2017 Robin Appelman <robin@icewind.nl>
+ *
+ * @author Robin Appelman <robin@icewind.nl>
+ *
+ * @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 OCP\Files\Notify;
+
+interface IRenameChange extends IChange {
+ /**
+ * Get the new path of the renamed file relative to the storage root
+ *
+ * @return string
+ */
+ public function getTargetPath();
+}
namespace OCP\Files\Storage;
+use OCP\Files\Notify\INotifyHandler;
+
/**
* Storage backend that support active notifications
*
* @param callable $callback
*
* @since 9.1.0
+ * @deprecated 12.0.0 use INotifyStorage::notify()->listen() instead
*/
public function listen($path, callable $callback);
+
+ /**
+ * Start the notification handler for this storage
+ *
+ * @param $path
+ * @return INotifyHandler
+ *
+ * @since 12.0.0
+ */
+ public function notify($path);
}