Skip to content

Commit

Permalink
Cache plugin availability in a singelton
Browse files Browse the repository at this point in the history
  • Loading branch information
TheOneRing committed Feb 24, 2023
1 parent 04f1271 commit 6f678fb
Show file tree
Hide file tree
Showing 27 changed files with 117 additions and 85 deletions.
2 changes: 1 addition & 1 deletion src/cmd/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void sync(const SyncCTX &ctx)
selectiveSyncFixup(db, selectiveSyncList);
}

SyncOptions opt { QSharedPointer<Vfs>(createVfsFromPlugin(Vfs::Off).release()) };
SyncOptions opt { QSharedPointer<Vfs>(VfsPluginManager::instance().createVfsFromPlugin(Vfs::Off).release()) };
opt.fillFromEnvironmentVariables();
opt.verifyChunkSizes();
auto engine = new SyncEngine(
Expand Down
88 changes: 54 additions & 34 deletions src/common/vfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,46 +153,58 @@ static QString modeToPluginName(Vfs::Mode mode)

Q_LOGGING_CATEGORY(lcPlugin, "plugins", QtInfoMsg)

bool OCC::isVfsPluginAvailable(Vfs::Mode mode)
{
// TODO: cache plugins available?
auto name = modeToPluginName(mode);
if (name.isEmpty())
return false;
auto pluginPath = pluginFileName(QStringLiteral("vfs"), name);
QPluginLoader loader(pluginPath);
OCC::VfsPluginManager *OCC::VfsPluginManager::_instance = nullptr;

auto basemeta = loader.metaData();
if (basemeta.isEmpty() || !basemeta.contains(QStringLiteral("IID"))) {
qCDebug(lcPlugin) << "Plugin doesn't exist" << loader.fileName();
return false;
}
if (basemeta[QStringLiteral("IID")].toString() != QLatin1String("org.owncloud.PluginFactory")) {
qCWarning(lcPlugin) << "Plugin has wrong IID" << loader.fileName() << basemeta[QStringLiteral("IID")];
return false;
bool OCC::VfsPluginManager::isVfsPluginAvailable(Vfs::Mode mode) const
{
{
auto result = _pluginCache.constFind(mode);
if (result != _pluginCache.cend()) {
return *result;
}
}
const bool out = [mode] {
const QString name = modeToPluginName(mode);
if (!OC_ENSURE_NOT(name.isEmpty())) {
return false;
}
auto pluginPath = pluginFileName(QStringLiteral("vfs"), name);
QPluginLoader loader(pluginPath);

auto metadata = basemeta[QStringLiteral("MetaData")].toObject();
if (metadata[QStringLiteral("type")].toString() != QLatin1String("vfs")) {
qCWarning(lcPlugin) << "Plugin has wrong type" << loader.fileName() << metadata[QStringLiteral("type")];
return false;
}
if (metadata[QStringLiteral("version")].toString() != OCC::Version::version().toString()) {
qCWarning(lcPlugin) << "Plugin has wrong version" << loader.fileName() << metadata[QStringLiteral("version")];
return false;
}
auto basemeta = loader.metaData();
if (basemeta.isEmpty() || !basemeta.contains(QStringLiteral("IID"))) {
qCDebug(lcPlugin) << "Plugin doesn't exist" << loader.fileName();
return false;
}
if (basemeta[QStringLiteral("IID")].toString() != QLatin1String("org.owncloud.PluginFactory")) {
qCWarning(lcPlugin) << "Plugin has wrong IID" << loader.fileName() << basemeta[QStringLiteral("IID")];
return false;
}

// Attempting to load the plugin is essential as it could have dependencies that
// can't be resolved and thus not be available after all.
if (!loader.load()) {
qCWarning(lcPlugin) << "Plugin failed to load:" << loader.errorString();
return false;
}
auto metadata = basemeta[QStringLiteral("MetaData")].toObject();
if (metadata[QStringLiteral("type")].toString() != QLatin1String("vfs")) {
qCWarning(lcPlugin) << "Plugin has wrong type" << loader.fileName() << metadata[QStringLiteral("type")];
return false;
}
if (metadata[QStringLiteral("version")].toString() != OCC::Version::version().toString()) {
qCWarning(lcPlugin) << "Plugin has wrong version" << loader.fileName() << metadata[QStringLiteral("version")];
return false;
}

return true;
// Attempting to load the plugin is essential as it could have dependencies that
// can't be resolved and thus not be available after all.
if (!loader.load()) {
qCWarning(lcPlugin) << "Plugin failed to load:" << loader.errorString();
return false;
}

return true;
}();
_pluginCache[mode] = out;
return out;
}

Vfs::Mode OCC::bestAvailableVfsMode()
Vfs::Mode OCC::VfsPluginManager::bestAvailableVfsMode() const
{
if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
return Vfs::WindowsCfApi;
Expand All @@ -204,7 +216,7 @@ Vfs::Mode OCC::bestAvailableVfsMode()
Q_UNREACHABLE();
}

std::unique_ptr<Vfs> OCC::createVfsFromPlugin(Vfs::Mode mode)
std::unique_ptr<Vfs> OCC::VfsPluginManager::createVfsFromPlugin(Vfs::Mode mode) const
{
auto name = modeToPluginName(mode);
if (name.isEmpty())
Expand Down Expand Up @@ -238,3 +250,11 @@ std::unique_ptr<Vfs> OCC::createVfsFromPlugin(Vfs::Mode mode)
qCInfo(lcPlugin) << "Created VFS instance from plugin" << pluginPath;
return vfs;
}

const VfsPluginManager &VfsPluginManager::instance()
{
if (!_instance) {
_instance = new VfsPluginManager();
}
return *_instance;
}
31 changes: 22 additions & 9 deletions src/common/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,10 @@ class OCSYNC_EXPORT Vfs : public QObject
*
* Currently plugins and modes are one-to-one but that's not required.
*/
enum Mode
{
enum Mode {
Off,
WithSuffix,
WindowsCfApi,
WindowsCfApi
};
Q_ENUM(Mode)
enum class ConvertToPlaceholderResult {
Expand Down Expand Up @@ -276,13 +275,27 @@ public slots:
friend class OwncloudPropagator;
};

/// Check whether the plugin for the mode is available.
OCSYNC_EXPORT bool isVfsPluginAvailable(Vfs::Mode mode);
class OCSYNC_EXPORT VfsPluginManager
{
public:
/// Check whether the plugin for the mode is available.
bool isVfsPluginAvailable(Vfs::Mode mode) const;

/// Return the best available VFS mode.
Vfs::Mode bestAvailableVfsMode() const;

/// Create a VFS instance for the mode, returns nullptr on failure.
std::unique_ptr<Vfs> createVfsFromPlugin(Vfs::Mode mode) const;

/// Return the best available VFS mode.
OCSYNC_EXPORT Vfs::Mode bestAvailableVfsMode();
static const VfsPluginManager &instance();

/// Create a VFS instance for the mode, returns nullptr on failure.
OCSYNC_EXPORT std::unique_ptr<Vfs> createVfsFromPlugin(Vfs::Mode mode);
protected:
VfsPluginManager() = default;

private:
static VfsPluginManager *_instance;

mutable QMap<Vfs::Mode, bool> _pluginCache;
};

} // namespace OCC
4 changes: 2 additions & 2 deletions src/gui/accountsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ void AccountSettings::slotCustomContextMenuRequested(const QPoint &pos)

if (Theme::instance()->showVirtualFilesOption()
&& !folder->virtualFilesEnabled() && FolderMan::instance()->checkVfsAvailability(folder->path())) {
const auto mode = bestAvailableVfsMode();
const auto mode = VfsPluginManager::instance().bestAvailableVfsMode();

if (mode == Vfs::WindowsCfApi || (Theme::instance()->enableExperimentalFeatures() && mode != Vfs::Off)) {
ac = menu->addAction(tr("Enable virtual file support%1...").arg(mode == Vfs::WindowsCfApi ? QString() : tr(" (experimental)")));
Expand Down Expand Up @@ -557,7 +557,7 @@ void AccountSettings::slotEnableVfsCurrentFolder()

// no need to show the message box on Windows
// as a little shortcut, we just re-use the message box's accept handler
if (bestAvailableVfsMode() == Vfs::WindowsCfApi) {
if (VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::WindowsCfApi) {
Q_EMIT messageBox->accepted();
} else {
messageBox->show();
Expand Down
12 changes: 6 additions & 6 deletions src/gui/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,12 @@ Application::Application(int &argc, char **argv, Platform *platform)
qCInfo(lcApplication) << "Plugin search paths:" << libraryPaths();

// Check vfs plugins
if (Theme::instance()->showVirtualFilesOption() && bestAvailableVfsMode() == Vfs::Off) {
if (Theme::instance()->showVirtualFilesOption() && VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::Off) {
qCWarning(lcApplication) << "Theme wants to show vfs mode, but no vfs plugins are available";
}
if (isVfsPluginAvailable(Vfs::WindowsCfApi))
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi))
qCInfo(lcApplication) << "VFS windows plugin is available";
if (isVfsPluginAvailable(Vfs::WithSuffix))
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WithSuffix))
qCInfo(lcApplication) << "VFS suffix plugin is available";

if (!configVersionMigration()) {
Expand All @@ -294,12 +294,12 @@ Application::Application(int &argc, char **argv, Platform *platform)
}

// Check vfs plugins
if (Theme::instance()->showVirtualFilesOption() && bestAvailableVfsMode() == Vfs::Off) {
if (Theme::instance()->showVirtualFilesOption() && VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::Off) {
qCWarning(lcApplication) << "Theme wants to show vfs mode, but no vfs plugins are available";
}
if (isVfsPluginAvailable(Vfs::WindowsCfApi))
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi))
qCInfo(lcApplication) << "VFS windows plugin is available";
if (isVfsPluginAvailable(Vfs::WithSuffix))
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WithSuffix))
qCInfo(lcApplication) << "VFS suffix plugin is available";

if (_quitInstance) {
Expand Down
8 changes: 4 additions & 4 deletions src/gui/folder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ Folder::Folder(const FolderDefinition &definition,
OC_ENFORCE(_vfs);
if (_definition.virtualFilesMode == Vfs::WithSuffix
&& _definition.upgradeVfsMode) {
if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (auto winvfs = createVfsFromPlugin(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (auto winvfs = VfsPluginManager::instance().createVfsFromPlugin(Vfs::WindowsCfApi)) {
// Wipe the existing suffix files from fs and journal
SyncEngine::wipeVirtualFiles(path(), _journal, *_vfs);

Expand Down Expand Up @@ -779,7 +779,7 @@ void Folder::setVirtualFilesEnabled(bool enabled)
{
Vfs::Mode newMode = _definition.virtualFilesMode;
if (enabled && _definition.virtualFilesMode == Vfs::Off) {
newMode = bestAvailableVfsMode();
newMode = VfsPluginManager::instance().bestAvailableVfsMode();
} else if (!enabled && _definition.virtualFilesMode != Vfs::Off) {
newMode = Vfs::Off;
}
Expand All @@ -795,7 +795,7 @@ void Folder::setVirtualFilesEnabled(bool enabled)
disconnect(&_engine->syncFileStatusTracker(), nullptr, _vfs.data(), nullptr);

_vfsIsReady = false;
_vfs.reset(createVfsFromPlugin(newMode).release());
_vfs.reset(VfsPluginManager::instance().createVfsFromPlugin(newMode).release());

_definition.virtualFilesMode = newMode;
startVfs();
Expand Down
6 changes: 3 additions & 3 deletions src/gui/folderman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ void FolderMan::setupFoldersHelper(QSettings &settings, AccountStatePtr account,
SyncJournalDb::maybeMigrateDb(folderDefinition.localPath(), folderDefinition.absoluteJournalPath());
}

auto vfs = createVfsFromPlugin(folderDefinition.virtualFilesMode);
auto vfs = VfsPluginManager::instance().createVfsFromPlugin(folderDefinition.virtualFilesMode);
if (!vfs) {
// TODO: Must do better error handling
qFatal("Could not load plugin");
Expand Down Expand Up @@ -886,7 +886,7 @@ Folder *FolderMan::addFolder(const AccountStatePtr &accountState, const FolderDe
return nullptr;
}

auto vfs = createVfsFromPlugin(folderDefinition.virtualFilesMode);
auto vfs = VfsPluginManager::instance().createVfsFromPlugin(folderDefinition.virtualFilesMode);
if (!vfs) {
qCWarning(lcFolderMan) << "Could not load plugin for mode" << folderDefinition.virtualFilesMode;
return nullptr;
Expand Down Expand Up @@ -1383,7 +1383,7 @@ Folder *FolderMan::addFolderFromWizard(const AccountStatePtr &accountStatePtr, c
folderDefinition.ignoreHiddenFiles = ignoreHiddenFiles();

if (useVfs) {
folderDefinition.virtualFilesMode = bestAvailableVfsMode();
folderDefinition.virtualFilesMode = VfsPluginManager::instance().bestAvailableVfsMode();
}

auto newFolder = addFolder(accountStatePtr, folderDefinition);
Expand Down
2 changes: 1 addition & 1 deletion src/gui/folderman.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ class FolderMan : public QObject
void setDirtyNetworkLimits();

/** Whether or not vfs is supported in the location. */
bool checkVfsAvailability(const QString &path, Vfs::Mode mode = bestAvailableVfsMode()) const;
bool checkVfsAvailability(const QString &path, Vfs::Mode mode = VfsPluginManager::instance().bestAvailableVfsMode()) const;

/** If the folder configuration is no longer supported this will return an error string */
Result<void, QString> unsupportedConfiguration(const QString &path) const;
Expand Down
2 changes: 1 addition & 1 deletion src/gui/folderwizard/folderwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const AccountStatePtr &FolderWizardPrivate::accountState()

bool FolderWizardPrivate::useVirtualFiles() const
{
const auto mode = bestAvailableVfsMode();
const auto mode = VfsPluginManager::instance().bestAvailableVfsMode();
const bool useVirtualFiles = (Theme::instance()->forceVirtualFilesOption() && mode == Vfs::WindowsCfApi) || (_folderWizardSelectiveSyncPage->useVirtualFiles());
if (useVirtualFiles) {
const auto availability = Vfs::checkAvailability(initialLocalPath(), mode);
Expand Down
4 changes: 2 additions & 2 deletions src/gui/folderwizard/folderwizardselectivesync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ FolderWizardSelectiveSync::FolderWizardSelectiveSync(FolderWizardPrivate *parent
_selectiveSync = new SelectiveSyncWidget(folderWizardPrivate()->accountState()->account(), this);
layout->addWidget(_selectiveSync);

const auto vfsMode = bestAvailableVfsMode();
const auto vfsMode = VfsPluginManager::instance().bestAvailableVfsMode();
if (Theme::instance()->forceVirtualFilesOption() && vfsMode == Vfs::WindowsCfApi) {
// using an else if to make the condition not even more complex...
} else if (Theme::instance()->showVirtualFilesOption() && vfsMode != Vfs::Off && (vfsMode == Vfs::WindowsCfApi || Theme::instance()->enableExperimentalFeatures())) {
Expand Down Expand Up @@ -100,7 +100,7 @@ void FolderWizardSelectiveSync::virtualFilesCheckboxClicked()

// no need to show the message box on Windows
// as a little shortcut, we just re-use the message box's accept handler
if (bestAvailableVfsMode() == Vfs::WindowsCfApi) {
if (VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::WindowsCfApi) {
Q_EMIT messageBox->accepted();
} else {
messageBox->show();
Expand Down
2 changes: 1 addition & 1 deletion src/gui/generalsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ GeneralSettings::GeneralSettings(QWidget *parent)
if (!Theme::instance()->aboutShowCopyright()) {
_ui->copyrightLabel->hide();
}
if (Theme::instance()->forceVirtualFilesOption() && bestAvailableVfsMode() == Vfs::WindowsCfApi) {
if (Theme::instance()->forceVirtualFilesOption() && VfsPluginManager::instance().bestAvailableVfsMode() == Vfs::WindowsCfApi) {
_ui->groupBox_non_vfs->hide();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ AccountConfiguredSetupWizardState::AccountConfiguredSetupWizardState(SetupWizard
bool enableVfsByDefault = false;
bool vfsModeIsExperimental = false;

switch (bestAvailableVfsMode()) {
switch (VfsPluginManager::instance().bestAvailableVfsMode()) {
case Vfs::WindowsCfApi:
vfsIsAvailable = true;
enableVfsByDefault = true;
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ QString Theme::aboutVersions(Theme::VersionFormat format) const
_version,
qtVersionString,
QSslSocket::sslLibraryVersionString(),
Vfs::modeToString(bestAvailableVfsMode()),
Vfs::modeToString(VfsPluginManager::instance().bestAvailableVfsMode()),
QSysInfo::productType() % QLatin1Char('-') % QSysInfo::kernelVersion(),
br,
gitUrl,
Expand Down
2 changes: 1 addition & 1 deletion test/testblacklist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private slots:

QTest::newRow("Vfs::Off") << Vfs::Off << false;

if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
QTest::newRow("Vfs::WindowsCfApi dehydrated") << Vfs::WindowsCfApi << true;

// TODO: the hydrated version will fail due to an issue in the winvfs plugin, so leave it disabled for now.
Expand Down
2 changes: 1 addition & 1 deletion test/testdatabaseerror.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private slots:

QTest::newRow("Vfs::Off") << Vfs::Off << false;

if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
QTest::newRow("Vfs::WindowsCfApi dehydrated") << Vfs::WindowsCfApi << true;

// TODO: the hydrated version will fail due to an issue in the winvfs plugin, so leave it disabled for now.
Expand Down
2 changes: 1 addition & 1 deletion test/testdownload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private slots:

QTest::newRow("Vfs::Off") << Vfs::Off << false;

if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
QTest::newRow("Vfs::WindowsCfApi dehydrated") << Vfs::WindowsCfApi << true;

// TODO: the hydrated version will fail due to an issue in the winvfs plugin, so leave it disabled for now.
Expand Down
2 changes: 1 addition & 1 deletion test/testlocaldiscovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private slots:

QTest::newRow("Vfs::Off") << Vfs::Off << false;

if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
QTest::newRow("Vfs::WindowsCfApi dehydrated") << Vfs::WindowsCfApi << true;

// TODO: the hydrated version will fail due to an issue in the winvfs plugin, so leave it disabled for now.
Expand Down
2 changes: 1 addition & 1 deletion test/testlockedfiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private slots:

QTest::newRow("Vfs::Off") << Vfs::Off << false;

if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
QTest::newRow("Vfs::WindowsCfApi dehydrated") << Vfs::WindowsCfApi << true;

// TODO: the hydrated version will fail due to an issue in the winvfs plugin, so leave it disabled for now.
Expand Down
2 changes: 1 addition & 1 deletion test/testpermissions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ private slots:

QTest::newRow("Vfs::Off") << Vfs::Off << false;

if (isVfsPluginAvailable(Vfs::WindowsCfApi)) {
if (VfsPluginManager::instance().isVfsPluginAvailable(Vfs::WindowsCfApi)) {
QTest::newRow("Vfs::WindowsCfApi dehydrated") << Vfs::WindowsCfApi << true;

// TODO: the hydrated version will fail due to an issue in the winvfs plugin, so leave it disabled for now.
Expand Down
Loading

0 comments on commit 6f678fb

Please sign in to comment.