瀏覽代碼

SocketAPI: Only push status for files requested by the shell #5361

We currently push the SYNC status for all files that will be propagated,
and then the OK status when those files are propagated.
On top of this, we send those statuses to all clients connected, even
if the socket is kept open by an application that only needed to show
a file open dialog. On macOS we're also using an NSConnection which
means that we have to wait for the RPC call to return from the
extension, which makes bulk status changes possibly heavy.

Reduce the time spent needlessly sending status pushes by limiting
them to files requested through that socket since it connected.
To limit the data to store, only remember the parent directory of
files requested, and store those in a bloom filter.

Note that this adds a requirement to shell extensions: they should
make sure that the status cache only contains entries that have been
requested through the socket API. In other words, the status cache
must be empty when each socket client connects to the socket API.
Otherwise the cached icon type will be shown to the user, and the
SocketAPI won't push new status for that file if it didn't receive
a RETRIEVE_FILE_STATUS.
Jocelyn Turcotte 9 年之前
父節點
當前提交
d3a0608bd5
共有 4 個文件被更改,包括 160 次插入89 次删除
  1. 2 2
      src/gui/folderman.cpp
  2. 146 76
      src/gui/socketapi.cpp
  3. 11 10
      src/gui/socketapi.h
  4. 1 1
      src/libsync/syncfilestatustracker.cpp

+ 2 - 2
src/gui/folderman.cpp

@@ -115,7 +115,7 @@ void FolderMan::unloadFolder( Folder *f )
     disconnect(f, SIGNAL(syncPausedChanged(Folder*,bool)),
                this, SLOT(slotFolderSyncPaused(Folder*,bool)));
     disconnect(&f->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
-               _socketApi.data(), SLOT(slotFileStatusChanged(const QString &, SyncFileStatus)));
+               _socketApi.data(), SLOT(broadcastStatusPushMessage(const QString &, SyncFileStatus)));
     disconnect(f, SIGNAL(watchedFileChangedExternally(QString)),
                &f->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
 }
@@ -938,7 +938,7 @@ Folder* FolderMan::addFolderInternal(FolderDefinition folderDefinition,
     connect(folder, SIGNAL(syncPausedChanged(Folder*,bool)), SLOT(slotFolderSyncPaused(Folder*,bool)));
     connect(folder, SIGNAL(canSyncChanged()), SLOT(slotFolderCanSyncChanged()));
     connect(&folder->syncEngine().syncFileStatusTracker(), SIGNAL(fileStatusChanged(const QString &, SyncFileStatus)),
-            _socketApi.data(), SLOT(slotFileStatusChanged(const QString &, SyncFileStatus)));
+            _socketApi.data(), SLOT(broadcastStatusPushMessage(const QString &, SyncFileStatus)));
     connect(folder, SIGNAL(watchedFileChangedExternally(QString)),
             &folder->syncEngine().syncFileStatusTracker(), SLOT(slotPathTouched(QString)));
 

+ 146 - 76
src/gui/socketapi.cpp

@@ -32,8 +32,10 @@
 #include "account.h"
 #include "capabilities.h"
 
+#include <QBitArray>
 #include <QDebug>
 #include <QUrl>
+#include <QMetaMethod>
 #include <QMetaObject>
 #include <QStringList>
 #include <QScopedPointer>
@@ -56,6 +58,11 @@
 // The second number should be changed when there are new features.
 #define MIRALL_SOCKET_API_VERSION "1.0"
 
+#define DEBUG qDebug() << "SocketApi: "
+
+Q_DECLARE_METATYPE(OCC::SocketListener)
+
+
 static inline QString removeTrailingSlash(QString path)
 {
     Q_ASSERT(path.endsWith(QLatin1Char('/')));
@@ -63,9 +70,89 @@ static inline QString removeTrailingSlash(QString path)
     return path;
 }
 
+static QString buildMessage(const QString& verb, const QString &path, const QString &status = QString::null )
+{
+    QString msg(verb);
+
+    if( !status.isEmpty() ) {
+        msg.append(QLatin1Char(':'));
+        msg.append(status);
+    }
+    if( !path.isEmpty() ) {
+        msg.append(QLatin1Char(':'));
+        QFileInfo fi(path);
+        msg.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
+    }
+    return msg;
+}
+
 namespace OCC {
 
-#define DEBUG qDebug() << "SocketApi: "
+class BloomFilter {
+    // Initialize with m=1024 bits and k=2 (high and low 16 bits of a qHash).
+    // For a client navigating in less than 100 directories, this gives us a probability less than (1-e^(-2*100/1024))^2 = 0.03147872136 false positives.
+    const static int NumBits = 1024;
+
+public:
+    BloomFilter() : hashBits(NumBits) { }
+
+    void storeHash(uint hash) {
+        hashBits.setBit((hash & 0xFFFF) % NumBits);
+        hashBits.setBit((hash >> 16) % NumBits);
+    }
+    bool isHashMaybeStored(uint hash) const {
+        return hashBits.testBit((hash & 0xFFFF) % NumBits)
+            && hashBits.testBit((hash >> 16) % NumBits);
+    }
+
+private:
+    QBitArray hashBits;
+};
+
+class SocketListener {
+public:
+    QIODevice* socket;
+
+    SocketListener(QIODevice* socket = nullptr) : socket(socket) { }
+
+    void sendMessage(const QString& message, bool doWait = false) const
+    {
+        DEBUG << "Sending message: " << message;
+        QString localMessage = message;
+        if( ! localMessage.endsWith(QLatin1Char('\n'))) {
+            localMessage.append(QLatin1Char('\n'));
+        }
+
+        QByteArray bytesToSend = localMessage.toUtf8();
+        qint64 sent = socket->write(bytesToSend);
+        if( doWait ) {
+            socket->waitForBytesWritten(1000);
+        }
+        if( sent != bytesToSend.length() ) {
+            qDebug() << "WARN: Could not send all data on socket for " << localMessage;
+        }
+
+    }
+
+    void sendMessageIfDirectoryMonitored(const QString& message, uint systemDirectoryHash) const
+    {
+        if (_monitoredDirectoriesBloomFilter.isHashMaybeStored(systemDirectoryHash))
+            sendMessage(message, false);
+    }
+
+    void registerMonitoredDirectory(uint systemDirectoryHash)
+    {
+        _monitoredDirectoriesBloomFilter.storeHash(systemDirectoryHash);
+    }
+private:
+    BloomFilter _monitoredDirectoriesBloomFilter;
+};
+
+struct ListenerHasSocketPred {
+    QIODevice *socket;
+    ListenerHasSocketPred(QIODevice *socket) : socket(socket) { }
+    bool operator()(const SocketListener &listener) const { return listener.socket == socket; }
+};
 
 SocketApi::SocketApi(QObject* parent)
     : QObject(parent)
@@ -129,7 +216,7 @@ SocketApi::~SocketApi()
     DEBUG << "dtor";
     _localServer.close();
     // All remaining sockets will be destroyed with _localServer, their parent
-    Q_ASSERT(_listeners.isEmpty() || _listeners.first()->parent() == &_localServer);
+    Q_ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
     _listeners.clear();
 }
 
@@ -143,14 +230,16 @@ void SocketApi::slotNewConnection()
     DEBUG << "New connection" << socket;
     connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
     connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
+    connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(slotSocketDestroyed(QObject*)));
     Q_ASSERT(socket->readAll().isEmpty());
 
-    _listeners.append(socket);
+    _listeners.append(SocketListener(socket));
+    SocketListener &listener = _listeners.last();
 
     foreach( Folder *f, FolderMan::instance()->map() ) {
         if (f->canSync()) {
             QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
-            sendMessage(socket, message);            
+            listener.sendMessage(message);
         }
     }
 }
@@ -158,17 +247,20 @@ void SocketApi::slotNewConnection()
 void SocketApi::onLostConnection()
 {
     DEBUG << "Lost connection " << sender();
-
-    QIODevice* socket = qobject_cast<QIODevice*>(sender());
-    _listeners.removeAll(socket);
-    socket->deleteLater();
+    sender()->deleteLater();
 }
 
+void SocketApi::slotSocketDestroyed(QObject* obj)
+{
+    QIODevice* socket = static_cast<QIODevice*>(obj);
+    _listeners.erase(std::remove_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket)), _listeners.end());
+}
 
 void SocketApi::slotReadSocket()
 {
     QIODevice* socket = qobject_cast<QIODevice*>(sender());
     Q_ASSERT(socket);
+    SocketListener *listener = &*std::find_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket));
 
     while(socket->canReadLine()) {
         // Make sure to normalize the input from the socket to
@@ -181,7 +273,7 @@ void SocketApi::slotReadSocket()
 
         QString argument = line.remove(0, command.length()+1);
         if(indexOfMethod != -1) {
-            staticMetaObject.method(indexOfMethod).invoke(this, Q_ARG(QString, argument), Q_ARG(QIODevice*, socket));
+            staticMetaObject.method(indexOfMethod).invoke(this, Q_ARG(QString, argument), Q_ARG(SocketListener*, listener));
         } else {
             DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
         }
@@ -197,8 +289,8 @@ void SocketApi::slotRegisterPath( const QString& alias )
     Folder *f = FolderMan::instance()->folder(alias);
     if (f) {
         QString message = buildRegisterPathMessage(removeTrailingSlash(f->path()));
-        foreach(QIODevice *socket, _listeners) {
-            sendMessage(socket, message);
+        foreach (auto &listener, _listeners) {
+            listener.sendMessage(message);
         }
     }
 
@@ -212,7 +304,7 @@ void SocketApi::slotUnregisterPath( const QString& alias )
 
     Folder *f = FolderMan::instance()->folder(alias);
     if (f)
-        broadcastMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null, true );
+        broadcastMessage(buildMessage(QLatin1String("UNREGISTER_PATH"), removeTrailingSlash(f->path()), QString::null), true);
 
     _registeredAliases.remove(alias);
 }
@@ -233,68 +325,41 @@ void SocketApi::slotUpdateFolderView(Folder *f)
                 f->syncResult().status() == SyncResult::SetupError ) {
 
             QString rootPath = removeTrailingSlash(f->path());
-            broadcastMessage(QLatin1String("STATUS"), rootPath,
-                             f->syncEngine().syncFileStatusTracker().fileStatus("").toSocketAPIString());
+            broadcastStatusPushMessage(rootPath, f->syncEngine().syncFileStatusTracker().fileStatus(""));
 
-            broadcastMessage(QLatin1String("UPDATE_VIEW"), rootPath);
+            broadcastMessage(buildMessage(QLatin1String("UPDATE_VIEW"), rootPath));
         } else {
             qDebug() << "Not sending UPDATE_VIEW for" << f->alias() << "because status() is" << f->syncResult().status();
         }
     }
 }
 
-void SocketApi::slotFileStatusChanged(const QString& systemFileName, SyncFileStatus fileStatus)
-{
-    broadcastMessage(QLatin1String("STATUS"), systemFileName, fileStatus.toSocketAPIString());
-}
-
-void SocketApi::sendMessage(QIODevice *socket, const QString& message, bool doWait)
+void SocketApi::broadcastMessage(const QString& msg, bool doWait)
 {
-    DEBUG << "Sending message: " << message;
-    QString localMessage = message;
-    if( ! localMessage.endsWith(QLatin1Char('\n'))) {
-        localMessage.append(QLatin1Char('\n'));
-    }
-
-    QByteArray bytesToSend = localMessage.toUtf8();
-    qint64 sent = socket->write(bytesToSend);
-    if( doWait ) {
-        socket->waitForBytesWritten(1000);
-    }
-    if( sent != bytesToSend.length() ) {
-        qDebug() << "WARN: Could not send all data on socket for " << localMessage;
+    foreach (auto &listener, _listeners) {
+        listener.sendMessage(msg, doWait);
     }
-
 }
 
-void SocketApi::broadcastMessage( const QString& verb, const QString& path, const QString& status, bool doWait )
+void SocketApi::broadcastStatusPushMessage(const QString& systemPath, SyncFileStatus fileStatus)
 {
-    QString msg(verb);
-
-    if( !status.isEmpty() ) {
-        msg.append(QLatin1Char(':'));
-        msg.append(status);
-    }
-    if( !path.isEmpty() ) {
-        msg.append(QLatin1Char(':'));
-        QFileInfo fi(path);
-        msg.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
-    }
-
-    foreach(QIODevice *socket, _listeners) {
-        sendMessage(socket, msg, doWait);
+    QString msg = buildMessage(QLatin1String("STATUS"), systemPath, fileStatus.toSocketAPIString());
+    Q_ASSERT(!systemPath.endsWith('/'));
+    uint directoryHash = qHash(systemPath.left(systemPath.lastIndexOf('/')));
+    foreach (auto &listener, _listeners) {
+        listener.sendMessageIfDirectoryMonitored(msg, directoryHash);
     }
 }
 
-void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QIODevice* socket)
+void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketListener* listener)
 {
     // This command is the same as RETRIEVE_FILE_STATUS
 
     //qDebug() << Q_FUNC_INFO << argument;
-    command_RETRIEVE_FILE_STATUS(argument, socket);
+    command_RETRIEVE_FILE_STATUS(argument, listener);
 }
 
-void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* socket)
+void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketListener* listener)
 {
     qDebug() << Q_FUNC_INFO << argument;
 
@@ -305,21 +370,26 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice*
         // this can happen in offline mode e.g.: nothing to worry about
         statusString = QLatin1String("NOP");
     } else {
-        QString relativePath = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1);
-        if( relativePath.endsWith(QLatin1Char('/')) ) {
-            relativePath.truncate(relativePath.length()-1);
-            qWarning() << "Removed trailing slash for directory: " << relativePath << "Status pushes won't have one.";
+        QString systemPath = QDir::cleanPath(argument);
+        if( systemPath.endsWith(QLatin1Char('/')) ) {
+            systemPath.truncate(systemPath.length()-1);
+            qWarning() << "Removed trailing slash for directory: " << systemPath << "Status pushes won't have one.";
         }
-        SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath);
+        // The user probably visited this directory in the file shell.
+        // Let the listener know that it should now send status pushes for sibblings of this file.
+        QString directory = systemPath.left(systemPath.lastIndexOf('/'));
+        listener->registerMonitoredDirectory(qHash(directory));
 
+        QString relativePath = systemPath.mid(syncFolder->cleanPath().length()+1);
+        SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(relativePath);
         statusString = fileStatus.toSocketAPIString();
     }
 
     const QString message = QLatin1String("STATUS:") % statusString % QLatin1Char(':') %  QDir::toNativeSeparators(argument);
-    sendMessage(socket, message);
+    listener->sendMessage(message);
 }
 
-void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
+void SocketApi::command_SHARE(const QString& localFile, SocketListener* listener)
 {
     qDebug() << Q_FUNC_INFO << localFile;
 
@@ -329,16 +399,16 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
     if (!shareFolder) {
         const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
         // files that are not within a sync folder are not synced.
-        sendMessage(socket, message);
+        listener->sendMessage(message);
     } else if (!shareFolder->accountState()->isConnected()) {
         const QString message = QLatin1String("SHARE:NOTCONNECTED:")+QDir::toNativeSeparators(localFile);
         // if the folder isn't connected, don't open the share dialog
-        sendMessage(socket, message);
+        listener->sendMessage(message);
     } else if (!theme->linkSharing() && (
                  !theme->userGroupSharing() ||
                  shareFolder->accountState()->account()->serverVersionInt() < ((8 << 16) + (2 << 8)))) {
         const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
-        sendMessage(socket, message);
+        listener->sendMessage(message);
     } else {
         const QString localFileClean = QDir::cleanPath(localFile);
         const QString file = localFileClean.mid(shareFolder->cleanPath().length()+1);
@@ -347,7 +417,7 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
         // Verify the file is on the server (to our knowledge of course)
         if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
             const QString message = QLatin1String("SHARE:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
-            sendMessage(socket, message);
+            listener->sendMessage(message);
             return;
         }
 
@@ -356,7 +426,7 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
         // Can't share root folder
         if (remotePath == "/") {
             const QString message = QLatin1String("SHARE:CANNOTSHAREROOT:")+QDir::toNativeSeparators(localFile);
-            sendMessage(socket, message);
+            listener->sendMessage(message);
             return;
         }
 
@@ -370,18 +440,18 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket)
             }
         }
         const QString message = QLatin1String("SHARE:OK:")+QDir::toNativeSeparators(localFile);
-        sendMessage(socket, message);
+        listener->sendMessage(message);
 
         emit shareCommandReceived(remotePath, localFileClean, allowReshare);
     }
 }
 
-void SocketApi::command_VERSION(const QString&, QIODevice* socket)
+void SocketApi::command_VERSION(const QString&, SocketListener* listener)
 {
-    sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
+    listener->sendMessage(QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
 }
 
-void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket)
+void SocketApi::command_SHARE_STATUS(const QString &localFile, SocketListener* listener)
 {
     qDebug() << Q_FUNC_INFO << localFile;
 
@@ -389,7 +459,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
 
     if (!shareFolder) {
         const QString message = QLatin1String("SHARE_STATUS:NOP:")+QDir::toNativeSeparators(localFile);
-        sendMessage(socket, message);
+        listener->sendMessage(message);
     } else {
         const QString file = QDir::cleanPath(localFile).mid(shareFolder->cleanPath().length()+1);
         SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file);
@@ -397,7 +467,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
         // Verify the file is on the server (to our knowledge of course)
         if (fileStatus.tag() != SyncFileStatus::StatusUpToDate) {
             const QString message = QLatin1String("SHARE_STATUS:NOTSYNCED:")+QDir::toNativeSeparators(localFile);
-            sendMessage(socket, message);
+            listener->sendMessage(message);
             return;
         }
 
@@ -405,7 +475,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
 
         if (!capabilities.shareAPI()) {
             const QString message = QLatin1String("SHARE_STATUS:DISABLED:")+QDir::toNativeSeparators(localFile);
-            sendMessage(socket, message);
+            listener->sendMessage(message);
         } else {
             auto theme = Theme::instance();
             QString available;
@@ -424,18 +494,18 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket
 
             if (available.isEmpty()) {
                 const QString message = QLatin1String("SHARE_STATUS:DISABLED") + ":" + QDir::toNativeSeparators(localFile);
-                sendMessage(socket, message);
+                listener->sendMessage(message);
             } else {
                 const QString message = QLatin1String("SHARE_STATUS:") + available + ":" + QDir::toNativeSeparators(localFile);
-                sendMessage(socket, message);
+                listener->sendMessage(message);
             }
         }
     }
 }
 
-void SocketApi::command_SHARE_MENU_TITLE(const QString &, QIODevice* socket)
+void SocketApi::command_SHARE_MENU_TITLE(const QString &, SocketListener* listener)
 {
-    sendMessage(socket, QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
+    listener->sendMessage(QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
 }
 
 QString SocketApi::buildRegisterPathMessage(const QString& path)

+ 11 - 10
src/gui/socketapi.h

@@ -35,6 +35,7 @@ namespace OCC {
 
 class SyncFileStatus;
 class Folder;
+class SocketListener;
 
 /**
  * @brief The SocketApi class
@@ -60,25 +61,25 @@ signals:
 private slots:
     void slotNewConnection();
     void onLostConnection();
+    void slotSocketDestroyed(QObject* obj);
     void slotReadSocket();
-    void slotFileStatusChanged(const QString& systemFileName, SyncFileStatus fileStatus);
+    void broadcastStatusPushMessage(const QString& systemPath, SyncFileStatus fileStatus);
 
 private:
-    void sendMessage(QIODevice* socket, const QString& message, bool doWait = false);
-    void broadcastMessage(const QString& verb, const QString &path, const QString &status = QString::null, bool doWait = false);
+    void broadcastMessage(const QString& msg, bool doWait = false);
 
-    Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, QIODevice* socket);
-    Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* socket);
-    Q_INVOKABLE void command_SHARE(const QString& localFile, QIODevice* socket);
+    Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketListener* listener);
+    Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, SocketListener* listener);
+    Q_INVOKABLE void command_SHARE(const QString& localFile, SocketListener* listener);
 
-    Q_INVOKABLE void command_VERSION(const QString& argument, QIODevice* socket);
+    Q_INVOKABLE void command_VERSION(const QString& argument, SocketListener* listener);
 
-    Q_INVOKABLE void command_SHARE_STATUS(const QString& localFile, QIODevice *socket);
-    Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QIODevice* socket);
+    Q_INVOKABLE void command_SHARE_STATUS(const QString& localFile, SocketListener* listener);
+    Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, SocketListener* listener);
     QString buildRegisterPathMessage(const QString& path);
 
     QSet<QString> _registeredAliases;
-    QList<QIODevice*> _listeners;
+    QList<SocketListener> _listeners;
     SocketApiServer _localServer;
 };
 

+ 1 - 1
src/libsync/syncfilestatustracker.cpp

@@ -254,7 +254,7 @@ void SyncFileStatusTracker::slotSyncFinished()
 
 void SyncFileStatusTracker::slotSyncEngineRunningChanged()
 {
-    emit fileStatusChanged(_syncEngine->localPath(), resolveSyncAndErrorStatus(QString(), NotShared));
+    emit fileStatusChanged(getSystemDestination(QString()), resolveSyncAndErrorStatus(QString(), NotShared));
 }
 
 SyncFileStatus SyncFileStatusTracker::resolveSyncAndErrorStatus(const QString &relativePath, SharedFlag isShared, PathKnownFlag isPathKnown)