Merge pull request #16158 from owncloud/mountprovider-after-setup

Call newly registered mount providers after the filesystem is setup
This commit is contained in:
Thomas Müller 2015-06-08 13:42:02 +02:00
commit a968b8409d
13 changed files with 206 additions and 97 deletions

View File

@ -22,12 +22,16 @@
namespace OC\Files\Config;
use OC\Hooks\Emitter;
use OC\Hooks\EmitterTrait;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IUser;
class MountProviderCollection implements IMountProviderCollection {
class MountProviderCollection implements IMountProviderCollection, Emitter {
use EmitterTrait;
/**
* @var \OCP\Files\Config\IMountProvider[]
*/
@ -65,5 +69,6 @@ class MountProviderCollection implements IMountProviderCollection {
*/
public function registerProvider(IMountProvider $provider) {
$this->providers[] = $provider;
$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
}
}

View File

@ -59,7 +59,11 @@
namespace OC\Files;
use OC\Cache\File;
use OC\Files\Config\MountProviderCollection;
use OC\Files\Storage\StorageFactory;
use OCP\Files\Config\IMountProvider;
use OCP\IUserManager;
class Filesystem {
@ -78,6 +82,8 @@ class Filesystem {
static private $normalizedPathCache = array();
static private $listeningForProviders = false;
/**
* classname which used for hooks handling
* used as signalclass in OC_Hooks::emit()
@ -371,14 +377,15 @@ class Filesystem {
$root = \OC_User::getHome($user);
$userObject = \OC_User::getManager()->get($user);
$userManager = \OC::$server->getUserManager();
$userObject = $userManager->get($user);
if (is_null($userObject)) {
\OCP\Util::writeLog('files', ' Backends provided no user object for '.$user, \OCP\Util::ERROR);
\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
throw new \OC\User\NoUserException();
}
$homeStorage = \OC_Config::getValue( 'objectstore' );
$homeStorage = \OC_Config::getValue('objectstore');
if (!empty($homeStorage)) {
// sanity checks
if (empty($homeStorage['class'])) {
@ -412,16 +419,41 @@ class Filesystem {
self::mountCacheDir($user);
// Chance to mount for other storages
if($userObject) {
$mountConfigManager = \OC::$server->getMountProviderCollection();
/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
$mountConfigManager = \OC::$server->getMountProviderCollection();
if ($userObject) {
$mounts = $mountConfigManager->getMountsForUser($userObject);
array_walk($mounts, array(self::$mounts, 'addMount'));
}
self::listenForNewMountProviders($mountConfigManager, $userManager);
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
}
/**
* Get mounts from mount providers that are registered after setup
*
* @param MountProviderCollection $mountConfigManager
* @param IUserManager $userManager
*/
private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
if (!self::$listeningForProviders) {
self::$listeningForProviders = true;
$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
foreach (Filesystem::$usersSetup as $user => $setup) {
$userObject = $userManager->get($user);
if ($userObject) {
$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
array_walk($mounts, array(self::$mounts, 'addMount'));
}
}
});
}
}
/**
* Mounts the cache directory
*
* @param string $user user name
*/
private static function mountCacheDir($user) {
@ -455,6 +487,7 @@ class Filesystem {
/**
* get the relative path of the root data directory for the current user
*
* @return string
*
* Returns path like /admin/files
@ -537,7 +570,7 @@ class Filesystem {
if (!$path || $path[0] !== '/') {
$path = '/' . $path;
}
if (strpos($path, '/../') !== FALSE || strrchr($path, '/') === '/..') {
if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
return false;
}
return true;
@ -577,6 +610,7 @@ class Filesystem {
/**
* check if the directory should be ignored when scanning
* NOTE: the special directories . and .. would cause never ending recursion
*
* @param String $dir
* @return boolean
*/
@ -745,6 +779,7 @@ class Filesystem {
/**
* Fix common problems with a file path
*
* @param string $path
* @param bool $stripTrailingSlash
* @param bool $isAbsolutePath
@ -761,7 +796,7 @@ class Filesystem {
$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath]);
if(isset(self::$normalizedPathCache[$cacheKey])) {
if (isset(self::$normalizedPathCache[$cacheKey])) {
return self::$normalizedPathCache[$cacheKey];
}

View File

@ -94,7 +94,7 @@ class Root extends Folder implements IRootFolder {
* @param string $method
* @param callable $callback
*/
public function listen($scope, $method, $callback) {
public function listen($scope, $method, callable $callback) {
$this->emitter->listen($scope, $method, $callback);
}
@ -103,7 +103,7 @@ class Root extends Folder implements IRootFolder {
* @param string $method optional
* @param callable $callback optional
*/
public function removeListener($scope = null, $method = null, $callback = null) {
public function removeListener($scope = null, $method = null, callable $callback = null) {
$this->emitter->removeListener($scope, $method, $callback);
}

View File

@ -23,81 +23,5 @@
namespace OC\Hooks;
abstract class BasicEmitter implements Emitter {
/**
* @var (callable[])[] $listeners
*/
protected $listeners = array();
/**
* @param string $scope
* @param string $method
* @param callable $callback
*/
public function listen($scope, $method, $callback) {
$eventName = $scope . '::' . $method;
if (!isset($this->listeners[$eventName])) {
$this->listeners[$eventName] = array();
}
if (array_search($callback, $this->listeners[$eventName]) === false) {
$this->listeners[$eventName][] = $callback;
}
}
/**
* @param string $scope optional
* @param string $method optional
* @param callable $callback optional
*/
public function removeListener($scope = null, $method = null, $callback = null) {
$names = array();
$allNames = array_keys($this->listeners);
if ($scope and $method) {
$name = $scope . '::' . $method;
if (isset($this->listeners[$name])) {
$names[] = $name;
}
} elseif ($scope) {
foreach ($allNames as $name) {
$parts = explode('::', $name, 2);
if ($parts[0] == $scope) {
$names[] = $name;
}
}
} elseif ($method) {
foreach ($allNames as $name) {
$parts = explode('::', $name, 2);
if ($parts[1] == $method) {
$names[] = $name;
}
}
} else {
$names = $allNames;
}
foreach ($names as $name) {
if ($callback) {
$index = array_search($callback, $this->listeners[$name]);
if ($index !== false) {
unset($this->listeners[$name][$index]);
}
} else {
$this->listeners[$name] = array();
}
}
}
/**
* @param string $scope
* @param string $method
* @param array $arguments optional
*/
protected function emit($scope, $method, $arguments = array()) {
$eventName = $scope . '::' . $method;
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $callback) {
call_user_func_array($callback, $arguments);
}
}
}
use EmitterTrait;
}

View File

@ -37,7 +37,7 @@ interface Emitter {
* @param callable $callback
* @return void
*/
public function listen($scope, $method, $callback);
public function listen($scope, $method, callable $callback);
/**
* @param string $scope optional
@ -45,5 +45,5 @@ interface Emitter {
* @param callable $callback optional
* @return void
*/
public function removeListener($scope = null, $method = null, $callback = null);
public function removeListener($scope = null, $method = null, callable $callback = null);
}

View File

@ -0,0 +1,103 @@
<?php
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OC\Hooks;
trait EmitterTrait {
/**
* @var (callable[])[] $listeners
*/
protected $listeners = array();
/**
* @param string $scope
* @param string $method
* @param callable $callback
*/
public function listen($scope, $method, callable $callback) {
$eventName = $scope . '::' . $method;
if (!isset($this->listeners[$eventName])) {
$this->listeners[$eventName] = array();
}
if (array_search($callback, $this->listeners[$eventName], true) === false) {
$this->listeners[$eventName][] = $callback;
}
}
/**
* @param string $scope optional
* @param string $method optional
* @param callable $callback optional
*/
public function removeListener($scope = null, $method = null, callable $callback = null) {
$names = array();
$allNames = array_keys($this->listeners);
if ($scope and $method) {
$name = $scope . '::' . $method;
if (isset($this->listeners[$name])) {
$names[] = $name;
}
} elseif ($scope) {
foreach ($allNames as $name) {
$parts = explode('::', $name, 2);
if ($parts[0] == $scope) {
$names[] = $name;
}
}
} elseif ($method) {
foreach ($allNames as $name) {
$parts = explode('::', $name, 2);
if ($parts[1] == $method) {
$names[] = $name;
}
}
} else {
$names = $allNames;
}
foreach ($names as $name) {
if ($callback) {
$index = array_search($callback, $this->listeners[$name], true);
if ($index !== false) {
unset($this->listeners[$name][$index]);
}
} else {
$this->listeners[$name] = array();
}
}
}
/**
* @param string $scope
* @param string $method
* @param array $arguments optional
*/
protected function emit($scope, $method, array $arguments = array()) {
$eventName = $scope . '::' . $method;
if (isset($this->listeners[$eventName])) {
foreach ($this->listeners[$eventName] as $callback) {
call_user_func_array($callback, $arguments);
}
}
}
}

View File

@ -40,7 +40,7 @@ abstract class ForwardingEmitter extends BasicEmitter {
* @param string $method
* @param callable $callback
*/
public function listen($scope, $method, $callback) {
public function listen($scope, $method, callable $callback) {
parent::listen($scope, $method, $callback);
foreach ($this->forwardEmitters as $emitter) {
$emitter->listen($scope, $method, $callback);
@ -50,7 +50,7 @@ abstract class ForwardingEmitter extends BasicEmitter {
/**
* @param \OC\Hooks\Emitter $emitter
*/
protected function forward($emitter) {
protected function forward(Emitter $emitter) {
$this->forwardEmitters[] = $emitter;
//forward all previously connected hooks

View File

@ -23,7 +23,7 @@
namespace OC\Hooks;
abstract class LegacyEmitter extends BasicEmitter {
protected function emit($scope, $method, $arguments = array()) {
protected function emit($scope, $method, array $arguments = array()) {
\OC_Hook::emit($scope, $method, $arguments);
parent::emit($scope, $method, $arguments);
}

View File

@ -28,7 +28,7 @@ class PublicEmitter extends BasicEmitter {
* @param string $method
* @param array $arguments optional
*/
public function emit($scope, $method, $arguments = array()) {
public function emit($scope, $method, array $arguments = array()) {
parent::emit($scope, $method, $arguments);
}
}

View File

@ -142,7 +142,7 @@ class Repair extends BasicEmitter {
*
* Re-declared as public to allow invocation from within the closure above in php 5.3
*/
public function emit($scope, $method, $arguments = array()) {
public function emit($scope, $method, array $arguments = array()) {
parent::emit($scope, $method, $arguments);
}
}

View File

@ -81,7 +81,7 @@ class Session implements IUserSession, Emitter {
* @param string $method
* @param callable $callback
*/
public function listen($scope, $method, $callback) {
public function listen($scope, $method, callable $callback) {
$this->manager->listen($scope, $method, $callback);
}
@ -90,7 +90,7 @@ class Session implements IUserSession, Emitter {
* @param string $method optional
* @param callable $callback optional
*/
public function removeListener($scope = null, $method = null, $callback = null) {
public function removeListener($scope = null, $method = null, callable $callback = null) {
$this->manager->removeListener($scope, $method, $callback);
}

View File

@ -22,11 +22,39 @@
namespace Test\Files;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Temporary;
use OC\User\NoUserException;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IUser;
class DummyMountProvider implements IMountProvider {
private $mounts = [];
/**
* @param array $mounts
*/
public function __construct(array $mounts) {
$this->mounts = $mounts;
}
/**
* Get the pre-registered mount points
*
* @param IUser $user
* @param IStorageFactory $loader
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
return isset($this->mounts[$user->getUID()]) ? $this->mounts[$user->getUID()] : [];
}
}
class Filesystem extends \Test\TestCase {
const TEST_FILESYSTEM_USER1 = "test-filesystem-user1";
const TEST_FILESYSTEM_USER2 = "test-filesystem-user1";
/**
* @var array tmpDirs
@ -44,6 +72,10 @@ class Filesystem extends \Test\TestCase {
protected function setUp() {
parent::setUp();
$userBackend = new \OC_User_Dummy();
$userBackend->createUser(self::TEST_FILESYSTEM_USER1, self::TEST_FILESYSTEM_USER1);
$userBackend->createUser(self::TEST_FILESYSTEM_USER2, self::TEST_FILESYSTEM_USER2);
\OC::$server->getUserManager()->registerBackend($userBackend);
$this->loginAsUser();
}
@ -271,6 +303,7 @@ class Filesystem extends \Test\TestCase {
/**
* Tests that an exception is thrown when passed user does not exist.
*
* @expectedException \OC\User\NoUserException
*/
public function testLocalMountWhenUserDoesNotExist() {
@ -380,4 +413,13 @@ class Filesystem extends \Test\TestCase {
\OC_Config::setValue('cache_path', $oldCachePath);
}
public function testRegisterMountProviderAfterSetup() {
\OC\Files\Filesystem::initMountPoints(self::TEST_FILESYSTEM_USER2);
$this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/foo/bar'));
$mount = new MountPoint(new Temporary([]), '/foo/bar');
$mountProvider = new DummyMountProvider([self::TEST_FILESYSTEM_USER2 => [$mount]]);
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
$this->assertEquals('/foo/bar/', \OC\Files\Filesystem::getMountPoint('/foo/bar'));
}
}

View File

@ -17,7 +17,7 @@ class DummyForwardingEmitter extends \OC\Hooks\ForwardingEmitter {
/**
* @param \OC\Hooks\Emitter $emitter
*/
public function forward($emitter) {
public function forward(\OC\Hooks\Emitter $emitter) {
parent::forward($emitter);
}
}