2016-09-29 21:19:54 +02:00
|
|
|
#include "./utils.h"
|
2017-08-29 23:50:34 +02:00
|
|
|
#include "./syncthingconnection.h"
|
2016-09-01 16:34:30 +02:00
|
|
|
|
|
|
|
#include <c++utilities/chrono/datetime.h>
|
2017-08-29 23:50:34 +02:00
|
|
|
#include <c++utilities/conversion/stringconversion.h>
|
2016-09-01 16:34:30 +02:00
|
|
|
|
2017-05-01 03:34:43 +02:00
|
|
|
#include <QCoreApplication>
|
2016-12-18 16:50:35 +01:00
|
|
|
#include <QHostAddress>
|
2017-07-02 21:47:23 +02:00
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QJsonValue>
|
2016-12-18 16:50:35 +01:00
|
|
|
#include <QNetworkInterface>
|
2017-05-01 03:34:43 +02:00
|
|
|
#include <QString>
|
2017-08-30 00:36:49 +02:00
|
|
|
#include <QStringBuilder>
|
2017-05-01 03:34:43 +02:00
|
|
|
#include <QUrl>
|
2016-09-01 16:34:30 +02:00
|
|
|
|
|
|
|
using namespace ChronoUtilities;
|
2017-08-29 23:50:34 +02:00
|
|
|
using namespace ConversionUtilities;
|
2016-09-01 16:34:30 +02:00
|
|
|
|
|
|
|
namespace Data {
|
|
|
|
|
2016-12-18 16:50:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns a string like "2 min 45 s ago" for the specified \a dateTime.
|
|
|
|
*/
|
2016-09-01 16:34:30 +02:00
|
|
|
QString agoString(DateTime dateTime)
|
|
|
|
{
|
|
|
|
const TimeSpan delta(DateTime::now() - dateTime);
|
2017-05-01 03:34:43 +02:00
|
|
|
if (!delta.isNegative() && static_cast<uint64>(delta.totalTicks()) > (TimeSpan::ticksPerMinute / 4uL)) {
|
|
|
|
return QCoreApplication::translate("Data::Utils", "%1 ago")
|
|
|
|
.arg(QString::fromUtf8(delta.toString(TimeSpanOutputFormat::WithMeasures, true).data()));
|
2016-09-01 16:34:30 +02:00
|
|
|
} else {
|
|
|
|
return QCoreApplication::translate("Data::Utils", "right now");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-29 23:50:34 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the "traffic string" for the specified \a total bytes and the specified \a rate.
|
|
|
|
*
|
|
|
|
* Eg. "10.2 GiB (45 kib/s)" or only "10.2 GiB" if rate is unknown or "unknown" if both values are unknown.
|
|
|
|
*/
|
|
|
|
QString trafficString(uint64 total, double rate)
|
|
|
|
{
|
|
|
|
static const QString unknownStr(QCoreApplication::translate("Data::Utils", "unknown"));
|
|
|
|
if (rate != 0.0) {
|
|
|
|
return total != SyncthingConnection::unknownTraffic
|
|
|
|
? QStringLiteral("%1 (%2)").arg(QString::fromUtf8(bitrateToString(rate, true).data()), QString::fromUtf8(dataSizeToString(total).data()))
|
|
|
|
: QString::fromUtf8(bitrateToString(rate, true).data());
|
|
|
|
} else if (total != SyncthingConnection::unknownTraffic) {
|
|
|
|
return QString::fromUtf8(dataSizeToString(total).data());
|
|
|
|
}
|
|
|
|
return unknownStr;
|
|
|
|
}
|
|
|
|
|
2017-08-30 00:36:49 +02:00
|
|
|
/*!
|
|
|
|
* \brief Returns the string for global/local directory status, eg. "5 files, 1 directory, 23.7 MiB".
|
|
|
|
*/
|
2018-01-27 23:27:50 +01:00
|
|
|
QString directoryStatusString(const SyncthingStatistics &stats)
|
2017-08-30 00:36:49 +02:00
|
|
|
{
|
2018-01-27 23:27:50 +01:00
|
|
|
return QCoreApplication::translate("Data::Utils", "%1 file(s)", nullptr, trQuandity(stats.files)).arg(stats.files) % QChar(',') % QChar(' ')
|
|
|
|
% QCoreApplication::translate("Data::Utils", "%1 dir(s)", nullptr, trQuandity(stats.dirs)).arg(stats.dirs) % QChar(',') % QChar(' ')
|
|
|
|
% QString::fromUtf8(dataSizeToString(stats.bytes).data());
|
2017-08-30 00:36:49 +02:00
|
|
|
}
|
|
|
|
|
2017-12-30 00:57:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns the "sync complete" notication message for the specified directories.
|
|
|
|
*/
|
2018-03-29 00:38:21 +02:00
|
|
|
QString syncCompleteString(const std::vector<const SyncthingDir *> &completedDirs, const SyncthingDev *remoteDevice)
|
2017-12-30 00:57:35 +01:00
|
|
|
{
|
2018-03-29 00:38:21 +02:00
|
|
|
const auto devName(remoteDevice ? remoteDevice->displayName() : QString());
|
2017-12-30 00:57:35 +01:00
|
|
|
switch (completedDirs.size()) {
|
|
|
|
case 0:
|
|
|
|
return QString();
|
|
|
|
case 1:
|
2018-03-29 00:38:21 +02:00
|
|
|
if (devName.isEmpty()) {
|
2018-03-31 22:31:28 +02:00
|
|
|
return QCoreApplication::translate("Data::Utils", "Synchronization of local directory %1 complete")
|
|
|
|
.arg(completedDirs.front()->displayName());
|
2018-03-29 00:38:21 +02:00
|
|
|
}
|
|
|
|
return QCoreApplication::translate("Data::Utils", "Synchronization of %1 on %2 complete").arg(completedDirs.front()->displayName(), devName);
|
2017-12-30 00:57:35 +01:00
|
|
|
default:;
|
|
|
|
}
|
2018-03-29 00:38:21 +02:00
|
|
|
const auto names(things(completedDirs, [](const auto *dir) { return dir->displayName(); }));
|
|
|
|
if (devName.isEmpty()) {
|
2018-03-31 22:31:28 +02:00
|
|
|
return QCoreApplication::translate("Data::Utils", "Synchronization of the following local directories complete:\n")
|
2018-03-29 00:38:21 +02:00
|
|
|
+ names.join(QStringLiteral(", "));
|
2017-12-30 00:57:35 +01:00
|
|
|
}
|
2018-03-29 00:38:21 +02:00
|
|
|
return QCoreApplication::translate("Data::Utils", "Synchronization of the following directories on %1 complete:\n").arg(devName)
|
|
|
|
+ names.join(QStringLiteral(", "));
|
2017-12-30 00:57:35 +01:00
|
|
|
}
|
|
|
|
|
2016-12-18 16:50:35 +01:00
|
|
|
/*!
|
|
|
|
* \brief Returns whether the host specified by the given \a url is the local machine.
|
|
|
|
*/
|
|
|
|
bool isLocal(const QUrl &url)
|
|
|
|
{
|
|
|
|
const QString host(url.host());
|
|
|
|
const QHostAddress hostAddress(host);
|
2017-05-01 03:34:43 +02:00
|
|
|
return host.compare(QLatin1String("localhost"), Qt::CaseInsensitive) == 0 || hostAddress.isLoopback()
|
|
|
|
|| QNetworkInterface::allAddresses().contains(hostAddress);
|
2016-12-18 16:50:35 +01:00
|
|
|
}
|
2017-07-02 21:47:23 +02:00
|
|
|
|
2017-10-01 21:19:41 +02:00
|
|
|
/*!
|
|
|
|
* \brief Sets the key "paused" of the specified \a object to \a paused.
|
|
|
|
* \returns Returns whether object has been altered.
|
|
|
|
*/
|
|
|
|
bool setPausedValue(QJsonObject &object, bool paused)
|
|
|
|
{
|
|
|
|
const QJsonObject::Iterator pausedIterator(object.find(QLatin1String("paused")));
|
|
|
|
if (pausedIterator == object.end()) {
|
|
|
|
object.insert(QLatin1String("paused"), paused);
|
|
|
|
} else {
|
|
|
|
QJsonValueRef pausedValue = pausedIterator.value();
|
|
|
|
if (pausedValue.toBool(false) == paused) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pausedValue = paused;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-02 21:47:23 +02:00
|
|
|
/*!
|
|
|
|
* \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)
|
|
|
|
{
|
2017-10-01 21:19:41 +02:00
|
|
|
// get reference to folders array
|
|
|
|
const QJsonObject::Iterator foldersIterator(syncthingConfig.find(QLatin1String("folders")));
|
|
|
|
if (foldersIterator == syncthingConfig.end()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QJsonValueRef folders = foldersIterator.value();
|
|
|
|
if (!folders.isArray()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// alter folders
|
2017-07-02 21:47:23 +02:00
|
|
|
bool altered = false;
|
2017-10-01 21:19:41 +02:00
|
|
|
QJsonArray foldersArray = folders.toArray();
|
|
|
|
for (QJsonValueRef folder : foldersArray) {
|
|
|
|
QJsonObject folderObj = folder.toObject();
|
|
|
|
|
|
|
|
// skip devices not matching the specified IDs or are already paused/unpaused
|
|
|
|
if (!dirIds.isEmpty() && !dirIds.contains(folderObj.value(QLatin1String("id")).toString())) {
|
|
|
|
continue;
|
2017-07-02 21:47:23 +02:00
|
|
|
}
|
2017-10-01 21:19:41 +02:00
|
|
|
|
|
|
|
// alter paused value
|
|
|
|
if (setPausedValue(folderObj, paused)) {
|
|
|
|
folder = folderObj;
|
|
|
|
altered = true;
|
2017-07-02 21:47:23 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-01 21:19:41 +02:00
|
|
|
|
|
|
|
// re-assign altered folders to array reference
|
|
|
|
if (altered) {
|
|
|
|
folders = foldersArray;
|
|
|
|
}
|
|
|
|
|
2017-07-02 21:47:23 +02:00
|
|
|
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)
|
|
|
|
{
|
2017-10-01 21:19:41 +02:00
|
|
|
// get reference to devices array
|
|
|
|
const QJsonObject::Iterator devicesIterator(syncthingConfig.find(QLatin1String("devices")));
|
|
|
|
if (devicesIterator == syncthingConfig.end()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QJsonValueRef devices = devicesIterator.value();
|
|
|
|
if (!devices.isArray()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// alter devices
|
2017-07-02 21:47:23 +02:00
|
|
|
bool altered = false;
|
2017-10-01 21:19:41 +02:00
|
|
|
QJsonArray devicesArray = devices.toArray();
|
|
|
|
for (QJsonValueRef device : devicesArray) {
|
|
|
|
QJsonObject deviceObj = device.toObject();
|
|
|
|
|
|
|
|
// skip devices not matching the specified IDs
|
|
|
|
if (!devIds.isEmpty() && !devIds.contains(deviceObj.value(QLatin1String("deviceID")).toString())) {
|
|
|
|
continue;
|
2017-07-02 21:47:23 +02:00
|
|
|
}
|
2017-10-01 21:19:41 +02:00
|
|
|
|
|
|
|
// alter paused value
|
|
|
|
if (setPausedValue(deviceObj, paused)) {
|
|
|
|
device = deviceObj;
|
|
|
|
altered = true;
|
2017-07-02 21:47:23 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-01 21:19:41 +02:00
|
|
|
|
|
|
|
// re-assign altered devices to array reference
|
|
|
|
if (altered) {
|
|
|
|
devices = devicesArray;
|
|
|
|
}
|
|
|
|
|
2017-07-02 21:47:23 +02:00
|
|
|
return altered;
|
|
|
|
}
|
2017-12-30 00:57:35 +01:00
|
|
|
|
2017-09-17 21:48:15 +02:00
|
|
|
} // namespace Data
|