1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

Profile locking

This commit is contained in:
tux3 2015-04-24 18:53:19 +02:00
parent 13d98da1bc
commit bbf75aefb9
No known key found for this signature in database
GPG Key ID: 7E086DD661263264
5 changed files with 132 additions and 1 deletions

View File

@ -430,6 +430,7 @@ SOURCES += \
src/core/coreencryption.cpp \
src/core/corefile.cpp \
src/core/corestructs.cpp \
src/profilelocker.cpp
HEADERS += \
src/audio.h \
@ -454,3 +455,4 @@ HEADERS += \
src/widget/gui.h \
src/toxme.h \
src/misc/qrwidget.h \
src/profilelocker.h

View File

@ -22,6 +22,7 @@
#include "src/widget/gui.h"
#include "src/historykeeper.h"
#include "src/audio.h"
#include "src/profilelocker.h"
#include "corefile.h"
#include <tox/tox.h>
@ -884,6 +885,17 @@ QByteArray Core::loadToxSave(QString path)
QByteArray data;
loadPath = ""; // if not empty upon return, then user forgot a password and is switching
// If we can't get a lock, then another instance is already using that profile
while (!ProfileLocker::lock(QFileInfo(path).baseName()))
{
qWarning() << "Profile "<<QFileInfo(path).baseName()<<" is already in use, pick another";
GUI::showWarning(tr("Profile already in use"),
tr("Your profile is already used by another qTox\n"
"Please select another profile"));
path = Settings::getInstance().askProfiles();
qWarning() << "New profile is "<<QFileInfo(path).baseName();
}
QFile configurationFile(path);
qDebug() << "Core::loadConfiguration: reading from " << path;
@ -913,9 +925,9 @@ QByteArray Core::loadToxSave(QString path)
if (!profile.isEmpty())
{
loadPath = QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT);
Settings::getInstance().switchProfile(profile);
HistoryKeeper::resetInstance();
return loadToxSave(QDir(Settings::getSettingsDirPath()).filePath(profile + TOX_EXT));
}
return QByteArray();
}

View File

@ -21,6 +21,7 @@
#include "src/widget/toxuri.h"
#include "src/widget/toxsave.h"
#include "src/autoupdate.h"
#include "src/profilelocker.h"
#include <QApplication>
#include <QCommandLineParser>
#include <QDateTime>
@ -213,6 +214,13 @@ int main(int argc, char *argv[])
ipc.registerEventHandler("save", &toxSaveEventHandler);
ipc.registerEventHandler("activate", &toxActivateEventHandler);
// If we're the IPC owner and we just started, then
// either we're the only running instance or any other instance
// is already so frozen it lost ownership.
// It's safe to remove any potential stale locks in this situation.
if (ipc.isCurrentOwner())
ProfileLocker::clearAllLocks();
if (parser.positionalArguments().size() > 0)
{
QString firstParam(parser.positionalArguments()[0]);

69
src/profilelocker.cpp Normal file
View File

@ -0,0 +1,69 @@
#include "profilelocker.h"
#include "src/misc/settings.h"
#include <QDir>
#include <QDebug>
using namespace std;
unique_ptr<QLockFile> ProfileLocker::lockfile;
QString ProfileLocker::curLockName;
QString ProfileLocker::lockPathFromName(const QString& name)
{
return Settings::getInstance().getSettingsDirPath()+'/'+name+".lock";
}
bool ProfileLocker::isLockable(QString profile)
{
// If we already have the lock, it's definitely lockable
if (lockfile && curLockName == profile)
return true;
QLockFile newLock(lockPathFromName(profile));
return newLock.tryLock();
}
bool ProfileLocker::lock(QString profile)
{
if (lockfile && curLockName == profile)
return true;
QLockFile* newLock = new QLockFile(lockPathFromName(profile));
if (!newLock->tryLock())
{
delete newLock;
return false;
}
unlock();
lockfile.reset(newLock);
curLockName = profile;
return true;
}
void ProfileLocker::unlock()
{
if (!lockfile)
return;
lockfile->unlock();
delete lockfile.release();
lockfile = nullptr;
curLockName.clear();
}
void ProfileLocker::clearAllLocks()
{
qDebug() << "ProfileLocker::clearAllLocks: Wiping out all lock files";
if (lockfile)
unlock();
QDir dir(Settings::getInstance().getSettingsDirPath());
dir.setFilter(QDir::Files);
dir.setNameFilters({"*.lock"});
QFileInfoList files = dir.entryInfoList();
for (QFileInfo fileInfo : files)
{
QFile file(fileInfo.absoluteFilePath());
file.remove();
}
}

40
src/profilelocker.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef PROFILELOCKER_H
#define PROFILELOCKER_H
#include <QLockFile>
#include <memory>
/// Locks a Tox profile so that multiple instances can not use the same profile.
/// Only one lock can be acquired at the same time, which means
/// that there is little need for manually unlocking.
/// The current lock will expire if you exit or acquire a new one.
class ProfileLocker
{
private:
ProfileLocker()=delete;
public:
/// Checks if a profile is currently locked by *another* instance
/// If we own the lock, we consider it lockable
/// There is no guarantee that the result will still be valid by the
/// time it is returned, this is provided on a best effort basis
static bool isLockable(QString profile);
/// Tries to acquire the lock on a profile, will not block
/// Returns true if we already own the lock
static bool lock(QString profile);
/// Releases the lock on the current profile
static void unlock();
/// Releases all locks on all profiles
/// DO NOT call unless all we're the only qTox instance
/// and we don't hold any lock yet.
static void clearAllLocks();
private:
static QString lockPathFromName(const QString& name);
private:
static std::unique_ptr<QLockFile> lockfile;
static QString curLockName;
};
#endif // PROFILELOCKER_H