connector: Update raw config after pausing/resuming

It seems like (cached) raw config is not automatically updated
via newConfig() after pausing/resuming a dir/dev. So this is
now done manually.

Additionally, pausing/resuming devs is now also implemented by
posting new config.
This commit is contained in:
Martchus 2017-07-02 21:47:23 +02:00
parent 5d05e9a5df
commit 04c9caf7d4
6 changed files with 142 additions and 76 deletions

View File

@ -291,12 +291,21 @@ void Application::requestPauseResume(bool pause)
++m_expectedResponse;
}
}
for (const SyncthingDev *dev : m_relevantDevs) {
if (pause) {
cerr << "Request pausing device ";
if (!m_relevantDevs.empty()) {
QStringList devIds;
devIds.reserve(m_relevantDirs.size());
for (const SyncthingDev *dev : m_relevantDevs) {
devIds << dev->id;
}
if (pause) {
cerr << "Request pausing devices ";
} else {
cerr << "Request resuming devices ";
}
cerr << devIds.join(QStringLiteral(", ")).toLocal8Bit().data() << " ...\n";
if (pause ? m_connection.pauseDirectories(devIds) : m_connection.resumeDirectories(devIds)) {
++m_expectedResponse;
}
cerr << dev->id.toLocal8Bit().data() << " ...\n";
pause ? m_connection.pauseDevice(dev->id) : m_connection.resumeDevice(dev->id);
}
cerr.flush();
}

View File

@ -243,18 +243,13 @@ void SyncthingConnection::autoReconnect()
}
/*!
* \brief Requests pausing the device with the specified ID.
* \brief Requests pausing the devices with the specified IDs.
*
* The signal error() is emitted when the request was not successful.
*/
void SyncthingConnection::pauseDevice(const QString &devId)
bool SyncthingConnection::pauseDevice(const QStringList &devIds)
{
QUrlQuery query;
query.addQueryItem(QStringLiteral("device"), devId);
QNetworkReply *reply = postData(QStringLiteral("system/pause"), query);
reply->setProperty("devId", devId);
reply->setProperty("resume", false);
QObject::connect(reply, &QNetworkReply::finished, this, &SyncthingConnection::readDevPauseResume);
return pauseResumeDevice(devIds, true);
}
/*!
@ -262,26 +257,19 @@ void SyncthingConnection::pauseDevice(const QString &devId)
*
* The signal error() is emitted when the request was not successful.
*/
void SyncthingConnection::pauseAllDevs()
bool SyncthingConnection::pauseAllDevs()
{
for (const SyncthingDev &dev : m_devs) {
pauseDevice(dev.id);
}
return pauseResumeDevice(deviceIds(), true);
}
/*!
* \brief Requests resuming the device with the specified ID.
* \brief Requests resuming the devices with the specified IDs.
*
* The signal error() is emitted when the request was not successful.
*/
void SyncthingConnection::resumeDevice(const QString &devId)
bool SyncthingConnection::resumeDevice(const QStringList &devIds)
{
QUrlQuery query;
query.addQueryItem(QStringLiteral("device"), devId);
QNetworkReply *reply = postData(QStringLiteral("system/resume"), query);
reply->setProperty("devId", devId);
reply->setProperty("resume", true);
QObject::connect(reply, &QNetworkReply::finished, this, &SyncthingConnection::readDevPauseResume);
return pauseResumeDevice(devIds, false);
}
/*!
@ -289,39 +277,9 @@ void SyncthingConnection::resumeDevice(const QString &devId)
*
* The signal error() is emitted when the request was not successful.
*/
void SyncthingConnection::resumeAllDevs()
bool SyncthingConnection::resumeAllDevs()
{
for (const SyncthingDev &dev : m_devs) {
resumeDevice(dev.id);
}
}
/*!
* \brief Alters the specified \a config so that the specified \a dirs are paused or not.
* \returns Returns whether the config has been altered (all dirs might have been already paused/unpaused).
*/
bool setPaused(QJsonObject &config, const QStringList &dirs, bool paused)
{
bool altered = false;
QJsonValueRef folders = config.find(QLatin1String("folders")).value();
if (folders.isArray()) {
QJsonArray foldersArray = folders.toArray();
for (QJsonValueRef folder : foldersArray) {
QJsonObject folderObj = folder.toObject();
if (dirs.isEmpty() || dirs.contains(folderObj.value(QLatin1String("id")).toString())) {
QJsonValueRef pausedValue = folderObj.find(QLatin1String("paused")).value();
if (pausedValue.toBool(false) != paused) {
pausedValue = paused;
folder = folderObj;
altered = true;
}
}
}
if (altered) {
folders = foldersArray;
}
}
return altered;
return pauseResumeDevice(deviceIds(), false);
}
/*!
@ -461,7 +419,37 @@ QNetworkReply *SyncthingConnection::postData(const QString &path, const QUrlQuer
* \brief Internally used to pause/resume directories.
* \returns Returns whether a request has been made.
* \remarks This might currently result in errors caused by Syncthing not
* handling E notation correctly:
* handling E notation correctly when using Qt < 5.9:
* https://github.com/syncthing/syncthing/issues/4001
*/
bool SyncthingConnection::pauseResumeDevice(const QStringList &devIds, bool paused)
{
if (devIds.isEmpty()) {
return false;
}
if (!isConnected()) {
emit error(tr("Unable to pause/resume a devices when not connected"), SyncthingErrorCategory::SpecificRequest, QNetworkReply::NoError);
return false;
}
QJsonObject config = m_rawConfig;
if (setDevicesPaused(config, devIds, paused)) {
QJsonDocument doc;
doc.setObject(config);
QNetworkReply *reply = postData(QStringLiteral("system/config"), QUrlQuery(), doc.toJson(QJsonDocument::Compact));
reply->setProperty("devIds", devIds);
reply->setProperty("resume", !paused);
QObject::connect(reply, &QNetworkReply::finished, this, &SyncthingConnection::readDevPauseResume);
return true;
}
return false;
}
/*!
* \brief Internally used to pause/resume directories.
* \returns Returns whether a request has been made.
* \remarks This might currently result in errors caused by Syncthing not
* handling E notation correctly when using Qt < 5.9:
* https://github.com/syncthing/syncthing/issues/4001
*/
bool SyncthingConnection::pauseResumeDirectory(const QStringList &dirIds, bool paused)
@ -475,7 +463,7 @@ bool SyncthingConnection::pauseResumeDirectory(const QStringList &dirIds, bool p
}
QJsonObject config = m_rawConfig;
if (setPaused(config, dirIds, paused)) {
if (setDirectoriesPaused(config, dirIds, paused)) {
QJsonDocument doc;
doc.setObject(config);
QNetworkReply *reply = postData(QStringLiteral("system/config"), QUrlQuery(), doc.toJson(QJsonDocument::Compact));
@ -1631,14 +1619,17 @@ void SyncthingConnection::readDevPauseResume()
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
switch (reply->error()) {
case QNetworkReply::NoError:
case QNetworkReply::NoError: {
const QStringList devIds(reply->property("devIds").toStringList());
const bool resume = reply->property("resume").toBool();
setDevicesPaused(m_rawConfig, devIds, !resume);
if (reply->property("resume").toBool()) {
emit deviceResumeTriggered(reply->property("devId").toString());
emit deviceResumeTriggered(devIds);
} else {
emit devicePauseTriggered(reply->property("devId").toString());
emit devicePauseTriggered(devIds);
}
break;
default:
} default:
emit error(tr("Unable to request device pause/resume: ") + reply->errorString(), SyncthingErrorCategory::SpecificRequest, reply->error());
}
}
@ -1648,14 +1639,17 @@ void SyncthingConnection::readDirPauseResume()
auto *reply = static_cast<QNetworkReply *>(sender());
reply->deleteLater();
switch (reply->error()) {
case QNetworkReply::NoError:
if (reply->property("resume").toBool()) {
emit directoryResumeTriggered(reply->property("dirIds").toStringList());
case QNetworkReply::NoError: {
const QStringList dirIds(reply->property("dirIds").toStringList());
const bool resume = reply->property("resume").toBool();
setDirectoriesPaused(m_rawConfig, dirIds, !resume);
if (resume) {
emit directoryResumeTriggered(dirIds);
} else {
emit directoryPauseTriggered(reply->property("dirIds").toStringList());
emit directoryPauseTriggered(dirIds);
}
break;
default:
} default:
emit error(tr("Unable to request directory pause/resume: ") + reply->errorString(), SyncthingErrorCategory::SpecificRequest, reply->error());
}
}

View File

@ -123,10 +123,10 @@ public Q_SLOTS:
void disconnect();
void reconnect();
void reconnect(SyncthingConnectionSettings &connectionSettings);
void pauseDevice(const QString &devId);
void pauseAllDevs();
void resumeDevice(const QString &devId);
void resumeAllDevs();
bool pauseDevice(const QStringList &devIds);
bool pauseAllDevs();
bool resumeDevice(const QStringList &devIds);
bool resumeAllDevs();
bool pauseDirectories(const QStringList &dirIds);
bool pauseAllDirs();
bool resumeDirectories(const QStringList &dirIds);
@ -152,8 +152,8 @@ Q_SIGNALS:
void myIdChanged(const QString &myNewId);
void trafficChanged(uint64 totalIncomingTraffic, uint64 totalOutgoingTraffic);
void rescanTriggered(const QString &dirId);
void devicePauseTriggered(const QString &devId);
void deviceResumeTriggered(const QString &devId);
void devicePauseTriggered(const QStringList &devIds);
void deviceResumeTriggered(const QStringList &devIds);
void directoryPauseTriggered(const QStringList &dirIds);
void directoryResumeTriggered(const QStringList &dirIds);
void restartTriggered();
@ -203,6 +203,7 @@ private:
QNetworkRequest prepareRequest(const QString &path, const QUrlQuery &query, bool rest = true);
QNetworkReply *requestData(const QString &path, const QUrlQuery &query, bool rest = true);
QNetworkReply *postData(const QString &path, const QUrlQuery &query, const QByteArray &data = QByteArray());
bool pauseResumeDevice(const QStringList &devIds, bool paused);
bool pauseResumeDirectory(const QStringList &dirIds, bool paused);
SyncthingDir *addDirInfo(std::vector<SyncthingDir> &dirs, const QString &dirId);
SyncthingDev *addDevInfo(std::vector<SyncthingDev> &devs, const QString &devId);

View File

@ -4,6 +4,9 @@
#include <QCoreApplication>
#include <QHostAddress>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonValue>
#include <QNetworkInterface>
#include <QString>
#include <QUrl>
@ -36,4 +39,60 @@ bool isLocal(const QUrl &url)
return host.compare(QLatin1String("localhost"), Qt::CaseInsensitive) == 0 || hostAddress.isLoopback()
|| QNetworkInterface::allAddresses().contains(hostAddress);
}
/*!
* \brief Alters the specified \a syncthingConfig so that the dirs with specified IDs are paused or not.
* \returns Returns whether the config has been altered (all dirs might have been already paused/unpaused).
*/
bool setDirectoriesPaused(QJsonObject &syncthingConfig, const QStringList &dirIds, bool paused)
{
bool altered = false;
QJsonValueRef folders = syncthingConfig.find(QLatin1String("folders")).value();
if (folders.isArray()) {
QJsonArray foldersArray = folders.toArray();
for (QJsonValueRef folder : foldersArray) {
QJsonObject folderObj = folder.toObject();
if (dirIds.isEmpty() || dirIds.contains(folderObj.value(QLatin1String("id")).toString())) {
QJsonValueRef pausedValue = folderObj.find(QLatin1String("paused")).value();
if (pausedValue.toBool(false) != paused) {
pausedValue = paused;
folder = folderObj;
altered = true;
}
}
}
if (altered) {
folders = foldersArray;
}
}
return altered;
}
/*!
* \brief Alters the specified \a syncthingConfig so that the devs with the specified IDs are paused or not.
* \returns Returns whether the config has been altered (all devs might have been already paused/unpaused).
*/
bool setDevicesPaused(QJsonObject &syncthingConfig, const QStringList &devIds, bool paused)
{
bool altered = false;
QJsonValueRef devices = syncthingConfig.find(QLatin1String("devices")).value();
if (devices.isArray()) {
QJsonArray devicesArray = devices.toArray();
for (QJsonValueRef device : devicesArray) {
QJsonObject deviceObj = device.toObject();
if (devIds.isEmpty() || devIds.contains(deviceObj.value(QLatin1String("deviceID")).toString())) {
QJsonValueRef pausedValue = deviceObj.find(QLatin1String("paused")).value();
if (pausedValue.toBool(false) != paused) {
pausedValue = paused;
device = deviceObj;
altered = true;
}
}
}
if (altered) {
devices = devicesArray;
}
}
return altered;
}
}

View File

@ -6,6 +6,7 @@
#include <QStringList>
QT_FORWARD_DECLARE_CLASS(QUrl)
QT_FORWARD_DECLARE_CLASS(QJsonObject)
namespace ChronoUtilities {
class DateTime;
@ -15,6 +16,8 @@ namespace Data {
QString LIB_SYNCTHING_CONNECTOR_EXPORT agoString(ChronoUtilities::DateTime dateTime);
bool LIB_SYNCTHING_CONNECTOR_EXPORT isLocal(const QUrl &url);
bool LIB_SYNCTHING_CONNECTOR_EXPORT setDirectoriesPaused(QJsonObject &syncthingConfig, const QStringList &dirIds, bool paused);
bool LIB_SYNCTHING_CONNECTOR_EXPORT setDevicesPaused(QJsonObject &syncthingConfig, const QStringList &dirs, bool paused);
template <class Objects> QStringList LIB_SYNCTHING_CONNECTOR_EXPORT ids(const Objects &objects)
{

View File

@ -464,9 +464,9 @@ void TrayWidget::scanDir(const SyncthingDir &dir)
void TrayWidget::pauseResumeDev(const SyncthingDev &dev)
{
if (dev.paused) {
m_connection.resumeDevice(dev.id);
m_connection.resumeDevice(QStringList(dev.id));
} else {
m_connection.pauseDevice(dev.id);
m_connection.pauseDevice(QStringList(dev.id));
}
}