syncthingtray/cli/application.cpp

642 lines
24 KiB
C++
Raw Normal View History

2016-10-02 21:59:28 +02:00
#include "./application.h"
#include "./helper.h"
#include "../connector/syncthingconfig.h"
2017-09-17 20:33:01 +02:00
#include "../connector/utils.h"
2016-10-02 21:59:28 +02:00
#include <c++utilities/application/failure.h>
#include <c++utilities/chrono/timespan.h>
#include <c++utilities/conversion/stringconversion.h>
2017-05-01 03:34:43 +02:00
#include <c++utilities/io/ansiescapecodes.h>
2016-10-02 21:59:28 +02:00
2017-01-02 23:25:58 +01:00
#include <qtutilities/misc/conversion.h>
2016-10-02 21:59:28 +02:00
#include <QCoreApplication>
#include <QDir>
2017-05-01 03:34:43 +02:00
#include <QNetworkAccessManager>
2016-10-02 21:59:28 +02:00
#include <functional>
#include <iostream>
using namespace std;
using namespace std::placeholders;
using namespace ApplicationUtilities;
using namespace EscapeCodes;
using namespace ChronoUtilities;
using namespace ConversionUtilities;
using namespace Data;
namespace Cli {
2017-01-03 00:29:55 +01:00
static bool terminated = false;
static int statusCode = 0;
void exitApplication(int statusCode)
{
statusCode = ::Cli::statusCode;
terminated = true;
}
2017-03-22 21:22:30 +01:00
inline QString argToQString(const char *arg, int size = -1)
2017-01-02 23:25:58 +01:00
{
#if !defined(PLATFORM_WINDOWS)
2017-03-22 21:22:30 +01:00
return QString::fromLocal8Bit(arg, size);
2017-01-02 23:25:58 +01:00
#else
// under Windows args are converted to UTF-8
2017-03-22 21:22:30 +01:00
return QString::fromUtf8(arg, size);
2017-01-02 23:25:58 +01:00
#endif
}
2017-05-01 03:34:43 +02:00
Application::Application()
: m_expectedResponse(0)
, m_preventDisconnect(false)
, m_callbacksInvoked(false)
2016-10-02 21:59:28 +02:00
{
// take ownership over the global QNetworkAccessManager
networkAccessManager().setParent(this);
exitFunction = &exitApplication;
2016-10-02 21:59:28 +02:00
// setup argument callbacks
m_args.status.setCallback(bind(&Application::printStatus, this, _1));
m_args.log.setCallback(bind(&Application::requestLog, this, _1));
2016-10-02 22:16:43 +02:00
m_args.stop.setCallback(bind(&Application::requestShutdown, this, _1));
2016-10-02 21:59:28 +02:00
m_args.restart.setCallback(bind(&Application::requestRestart, this, _1));
m_args.rescan.setCallback(bind(&Application::requestRescan, this, _1));
m_args.rescanAll.setCallback(bind(&Application::requestRescanAll, this, _1));
m_args.pause.setCallback(bind(&Application::requestPauseResume, this, true));
m_args.resume.setCallback(bind(&Application::requestPauseResume, this, false));
m_args.pauseAllDevs.setCallback(bind(&Application::requestPauseAllDevs, this, _1));
m_args.pauseAllDirs.setCallback(bind(&Application::requestPauseAllDirs, this, _1));
m_args.resumeAllDevs.setCallback(bind(&Application::requestResumeAllDevs, this, _1));
m_args.resumeAllDirs.setCallback(bind(&Application::requestResumeAllDirs, this, _1));
m_args.waitForIdle.setCallback(bind(&Application::initWaitForIdle, this, _1));
2017-04-06 00:08:24 +02:00
m_args.pwd.setCallback(bind(&Application::checkPwdOperationPresent, this, _1));
m_args.statusPwd.setCallback(bind(&Application::printPwdStatus, this, _1));
m_args.rescanPwd.setCallback(bind(&Application::requestRescanPwd, this, _1));
m_args.pausePwd.setCallback(bind(&Application::requestPausePwd, this, _1));
m_args.resumePwd.setCallback(bind(&Application::requestResumePwd, this, _1));
2016-10-02 21:59:28 +02:00
// connect signals and slots
connect(&m_connection, &SyncthingConnection::statusChanged, this, &Application::handleStatusChanged);
connect(&m_connection, &SyncthingConnection::error, this, &Application::handleError);
}
Application::~Application()
2017-05-01 03:34:43 +02:00
{
}
2016-10-02 21:59:28 +02:00
2017-05-01 03:34:43 +02:00
int Application::exec(int argc, const char *const *argv)
2016-10-02 21:59:28 +02:00
{
try {
// parse arguments
m_args.parser.readArgs(argc, argv);
// check whether application needs to be terminated due to --bash-completion argument
2017-05-01 03:34:43 +02:00
if (terminated) {
return statusCode;
}
2016-10-02 21:59:28 +02:00
m_args.parser.checkConstraints();
// handle help argument
2017-05-01 03:34:43 +02:00
if (m_args.help.isPresent()) {
2016-10-02 21:59:28 +02:00
m_args.parser.printHelp(cout);
return 0;
}
// locate and read Syncthing config file
QString configFile;
const char *configFileArgValue = m_args.configFile.firstValue();
2017-05-01 03:34:43 +02:00
if (configFileArgValue) {
2017-01-02 23:25:58 +01:00
configFile = fromNativeFileName(configFileArgValue);
2016-10-02 21:59:28 +02:00
} else {
configFile = SyncthingConfig::locateConfigFile();
}
SyncthingConfig config;
const char *apiKeyArgValue = m_args.apiKey.firstValue();
2017-05-01 03:34:43 +02:00
if (!config.restore(configFile)) {
if (configFileArgValue) {
cerr << Phrases::Error << "Unable to locate specified Syncthing config file \"" << configFileArgValue << "\"" << Phrases::End
<< flush;
2016-10-02 21:59:28 +02:00
return -1;
2017-05-01 03:34:43 +02:00
} else if (!apiKeyArgValue) {
cerr << Phrases::Error << "Unable to locate Syncthing config file and no API key specified" << Phrases::End << flush;
2016-10-02 21:59:28 +02:00
return -2;
}
}
// apply settings for connection
2017-05-01 03:34:43 +02:00
if (const char *urlArgValue = m_args.url.firstValue()) {
2017-01-02 23:25:58 +01:00
m_settings.syncthingUrl = argToQString(urlArgValue);
2017-05-01 03:34:43 +02:00
} else if (!config.guiAddress.isEmpty()) {
m_settings.syncthingUrl = config.syncthingUrl();
2016-10-02 21:59:28 +02:00
} else {
m_settings.syncthingUrl = QStringLiteral("http://localhost:8080");
}
2017-05-01 03:34:43 +02:00
if (m_args.credentials.isPresent()) {
2016-10-02 21:59:28 +02:00
m_settings.authEnabled = true;
2017-01-02 23:25:58 +01:00
m_settings.userName = argToQString(m_args.credentials.values(0)[0]);
m_settings.password = argToQString(m_args.credentials.values(0)[1]);
2016-10-02 21:59:28 +02:00
}
2017-05-01 03:34:43 +02:00
if (apiKeyArgValue) {
2016-10-02 21:59:28 +02:00
m_settings.apiKey.append(apiKeyArgValue);
} else {
m_settings.apiKey.append(config.guiApiKey);
}
2017-05-01 03:34:43 +02:00
if (const char *certArgValue = m_args.certificate.firstValue()) {
2017-01-02 23:25:58 +01:00
m_settings.httpsCertPath = argToQString(certArgValue);
2017-05-01 03:34:43 +02:00
if (m_settings.httpsCertPath.isEmpty() || !m_settings.loadHttpsCert()) {
cerr << Phrases::Error << "Unable to load specified certificate \"" << m_args.certificate.firstValue() << '\"' << Phrases::End
<< flush;
2016-10-02 21:59:28 +02:00
return -3;
}
}
2017-09-17 20:33:01 +02:00
// finally do the request or establish connection
2017-05-01 03:34:43 +02:00
if (m_args.status.isPresent() || m_args.rescanAll.isPresent() || m_args.pauseAllDirs.isPresent() || m_args.pauseAllDevs.isPresent()
|| m_args.resumeAllDirs.isPresent() || m_args.resumeAllDevs.isPresent() || m_args.pause.isPresent() || m_args.resume.isPresent()
|| m_args.waitForIdle.isPresent() || m_args.pwd.isPresent()) {
2016-10-02 21:59:28 +02:00
// those arguments rquire establishing a connection first, the actual handler is called by handleStatusChanged() when
// the connection has been established
m_connection.reconnect(m_settings);
cerr << "Connecting to " << m_settings.syncthingUrl.toLocal8Bit().data() << " ...";
cerr.flush();
} else {
// call handler for any other arguments directly
m_connection.applySettings(m_settings);
m_args.parser.invokeCallbacks();
}
// enter event loop
return QCoreApplication::exec();
2017-05-01 03:34:43 +02:00
} catch (const Failure &ex) {
2016-10-02 21:59:28 +02:00
cerr << "Unable to parse arguments. " << ex.what() << "\nSee --help for available commands." << endl;
return 1;
}
}
void Application::handleStatusChanged(SyncthingStatus newStatus)
{
Q_UNUSED(newStatus)
2017-05-01 03:34:43 +02:00
if (m_callbacksInvoked) {
return;
}
2017-05-01 03:34:43 +02:00
if (m_connection.isConnected()) {
2016-10-02 21:59:28 +02:00
eraseLine(cout);
cout << '\r';
m_callbacksInvoked = true;
2016-10-02 21:59:28 +02:00
m_args.parser.invokeCallbacks();
2017-05-01 03:34:43 +02:00
if (!m_preventDisconnect) {
m_connection.disconnect();
}
2016-10-02 21:59:28 +02:00
}
}
void Application::handleResponse()
{
2017-05-01 03:34:43 +02:00
if (m_expectedResponse) {
if (!--m_expectedResponse) {
2016-10-02 21:59:28 +02:00
QCoreApplication::quit();
}
} else {
cerr << Phrases::Error << "Unexpected response" << Phrases::End << flush;
2016-10-02 21:59:28 +02:00
QCoreApplication::exit(-4);
}
}
void Application::handleError(
const QString &message, SyncthingErrorCategory category, int networkError, const QNetworkRequest &request, const QByteArray &response)
2016-10-02 21:59:28 +02:00
{
VAR_UNUSED(category)
VAR_UNUSED(networkError)
2016-10-02 21:59:28 +02:00
eraseLine(cout);
cerr << '\n' << '\r' << Phrases::Error;
cerr << message.toLocal8Bit().data() << Phrases::End;
const QUrl url(request.url());
if (!url.isEmpty()) {
cerr << "\nRequest: " << url.toString(QUrl::PrettyDecoded).toLocal8Bit().data() << '\n';
}
if (!response.isEmpty()) {
cerr << "\nResponse:\n" << response.data() << '\n';
}
cerr << flush;
2016-10-02 21:59:28 +02:00
QCoreApplication::exit(-3);
}
void Application::findRelevantDirsAndDevs()
{
findRelevantDirsAndDevs(OperationType::Status);
}
2016-10-02 21:59:28 +02:00
void Application::requestLog(const ArgumentOccurrence &)
{
m_connection.requestLog(&Application::printLog);
2016-10-02 21:59:28 +02:00
cerr << "Request log from " << m_settings.syncthingUrl.toLocal8Bit().data() << " ...";
cerr.flush();
}
2016-10-02 22:16:43 +02:00
void Application::requestShutdown(const ArgumentOccurrence &)
{
connect(&m_connection, &SyncthingConnection::shutdownTriggered, &QCoreApplication::quit);
m_connection.shutdown();
cerr << "Request shutdown " << m_settings.syncthingUrl.toLocal8Bit().data() << " ...";
cerr.flush();
}
2016-10-02 21:59:28 +02:00
void Application::requestRestart(const ArgumentOccurrence &)
{
connect(&m_connection, &SyncthingConnection::restartTriggered, &QCoreApplication::quit);
m_connection.restart();
cerr << "Request restart " << m_settings.syncthingUrl.toLocal8Bit().data() << " ...";
cerr.flush();
}
void Application::requestRescan(const ArgumentOccurrence &occurrence)
{
m_expectedResponse = occurrence.values.size();
connect(&m_connection, &SyncthingConnection::rescanTriggered, this, &Application::handleResponse);
2017-05-01 03:34:43 +02:00
for (const char *value : occurrence.values) {
2016-10-02 21:59:28 +02:00
cerr << "Request rescanning " << value << " ...\n";
2017-03-22 21:22:30 +01:00
// split into directory name and relpath
const char *firstSlash = value;
2017-05-01 03:34:43 +02:00
for (; *firstSlash && *firstSlash != '/'; ++firstSlash)
;
if (*firstSlash) {
2017-03-22 21:22:30 +01:00
m_connection.rescan(argToQString(value, static_cast<int>(firstSlash - value)), argToQString(firstSlash + 1));
} else {
m_connection.rescan(argToQString(value));
}
2016-10-02 21:59:28 +02:00
}
cerr.flush();
}
void Application::requestRescanAll(const ArgumentOccurrence &)
{
m_expectedResponse = m_connection.dirInfo().size();
connect(&m_connection, &SyncthingConnection::rescanTriggered, this, &Application::handleResponse);
cerr << "Request rescanning all directories ..." << endl;
m_connection.rescanAllDirs();
}
void Application::requestPauseResume(bool pause)
2016-10-02 21:59:28 +02:00
{
findRelevantDirsAndDevs(OperationType::PauseResume);
m_expectedResponse = m_relevantDevs.size();
2017-05-01 03:34:43 +02:00
if (pause) {
connect(&m_connection, &SyncthingConnection::devicePauseTriggered, this, &Application::handleResponse);
connect(&m_connection, &SyncthingConnection::directoryPauseTriggered, this, &Application::handleResponse);
} else {
connect(&m_connection, &SyncthingConnection::deviceResumeTriggered, this, &Application::handleResponse);
connect(&m_connection, &SyncthingConnection::directoryResumeTriggered, this, &Application::handleResponse);
}
2017-05-01 03:34:43 +02:00
if (!m_relevantDirs.empty()) {
QStringList dirIds;
dirIds.reserve(m_relevantDirs.size());
2017-05-01 03:34:43 +02:00
for (const SyncthingDir *dir : m_relevantDirs) {
dirIds << dir->id;
}
2017-05-01 03:34:43 +02:00
if (pause) {
cerr << "Request pausing directories ";
} else {
cerr << "Request resuming directories ";
}
cerr << dirIds.join(QStringLiteral(", ")).toLocal8Bit().data() << " ...\n";
2017-05-01 03:34:43 +02:00
if (pause ? m_connection.pauseDirectories(dirIds) : m_connection.resumeDirectories(dirIds)) {
++m_expectedResponse;
}
}
if (!m_relevantDevs.empty()) {
QStringList devIds;
devIds.reserve(m_relevantDirs.size());
for (const SyncthingDev *dev : m_relevantDevs) {
devIds << dev->id;
}
2017-05-01 03:34:43 +02:00
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;
}
2016-10-02 21:59:28 +02:00
}
cerr.flush();
}
void Application::requestPauseAllDevs(const ArgumentOccurrence &)
2016-10-02 21:59:28 +02:00
{
findRelevantDirsAndDevs(OperationType::PauseResume);
2016-10-02 21:59:28 +02:00
m_expectedResponse = m_connection.devInfo().size();
connect(&m_connection, &SyncthingConnection::devicePauseTriggered, this, &Application::handleResponse);
2016-10-02 21:59:28 +02:00
cerr << "Request pausing all devices ..." << endl;
m_connection.pauseAllDevs();
}
void Application::requestPauseAllDirs(const ArgumentOccurrence &)
2016-10-02 21:59:28 +02:00
{
m_expectedResponse = m_connection.dirInfo().size();
connect(&m_connection, &SyncthingConnection::directoryPauseTriggered, this, &Application::handleResponse);
cerr << "Request pausing all directories ..." << endl;
m_connection.pauseAllDirs();
2016-10-02 21:59:28 +02:00
}
void Application::requestResumeAllDevs(const ArgumentOccurrence &)
2016-10-02 21:59:28 +02:00
{
m_expectedResponse = m_connection.devInfo().size();
connect(&m_connection, &SyncthingConnection::deviceResumeTriggered, this, &Application::handleResponse);
2016-10-02 21:59:28 +02:00
cerr << "Request resuming all devices ..." << endl;
m_connection.resumeAllDevs();
}
void Application::requestResumeAllDirs(const ArgumentOccurrence &)
{
m_expectedResponse = m_connection.dirInfo().size();
connect(&m_connection, &SyncthingConnection::deviceResumeTriggered, this, &Application::handleResponse);
cerr << "Request resuming all directories ..." << endl;
m_connection.resumeAllDevs();
}
void Application::findRelevantDirsAndDevs(OperationType operationType)
2016-10-02 21:59:28 +02:00
{
int dummy;
Argument *dirArg, *devArg;
2017-05-01 03:34:43 +02:00
switch (operationType) {
case OperationType::Status:
dirArg = &m_args.statusDir;
devArg = &m_args.statusDev;
break;
case OperationType::PauseResume:
dirArg = &m_args.pauseDir;
devArg = &m_args.pauseDev;
}
2017-05-01 03:34:43 +02:00
if (dirArg->isPresent()) {
m_relevantDirs.reserve(dirArg->occurrences());
2017-05-01 03:34:43 +02:00
for (size_t i = 0; i != dirArg->occurrences(); ++i) {
if (const SyncthingDir *dir = m_connection.findDirInfo(argToQString(dirArg->values(i).front()), dummy)) {
m_relevantDirs.emplace_back(dir);
2016-10-02 21:59:28 +02:00
} else {
cerr << Phrases::Warning << "Specified directory \"" << dirArg->values(i).front() << "\" does not exist and will be ignored"
<< Phrases::End;
2016-10-02 21:59:28 +02:00
}
}
}
2017-05-01 03:34:43 +02:00
if (devArg->isPresent()) {
m_relevantDevs.reserve(devArg->occurrences());
2017-05-01 03:34:43 +02:00
for (size_t i = 0; i != devArg->occurrences(); ++i) {
const SyncthingDev *dev = m_connection.findDevInfo(argToQString(devArg->values(i).front()), dummy);
2017-05-01 03:34:43 +02:00
if (!dev) {
dev = m_connection.findDevInfoByName(argToQString(devArg->values(i).front()), dummy);
2016-10-02 21:59:28 +02:00
}
2017-05-01 03:34:43 +02:00
if (dev) {
m_relevantDevs.emplace_back(dev);
2016-10-02 21:59:28 +02:00
} else {
cerr << Phrases::Warning << "Specified device \"" << devArg->values(i).front() << "\" does not exist and will be ignored"
<< Phrases::End;
2016-10-02 21:59:28 +02:00
}
}
}
2017-05-01 03:34:43 +02:00
if (operationType == OperationType::Status) {
// when displaying status information and no dirs/devs have been specified, just print information for all
2017-05-01 03:34:43 +02:00
if (m_relevantDirs.empty() && m_relevantDevs.empty()) {
m_relevantDirs.reserve(m_connection.dirInfo().size());
2017-05-01 03:34:43 +02:00
for (const SyncthingDir &dir : m_connection.dirInfo()) {
m_relevantDirs.emplace_back(&dir);
}
m_relevantDevs.reserve(m_connection.devInfo().size());
2017-05-01 03:34:43 +02:00
for (const SyncthingDev &dev : m_connection.devInfo()) {
m_relevantDevs.emplace_back(&dev);
}
2016-10-02 21:59:28 +02:00
}
}
}
2017-04-06 00:08:24 +02:00
bool Application::findPwd()
{
const QString pwd(QDir::currentPath());
2017-05-01 03:34:43 +02:00
for (const SyncthingDir &dir : m_connection.dirInfo()) {
if (pwd == dir.pathWithoutTrailingSlash()) {
2017-04-06 00:08:24 +02:00
m_pwd = &dir;
return true;
2017-05-01 03:34:43 +02:00
} else if (pwd.startsWith(dir.path)) {
2017-04-06 00:08:24 +02:00
m_pwd = &dir;
m_relativePath = pwd.mid(dir.path.size());
return true;
}
}
cerr << Phrases::Error << "The current working directory \"" << pwd.toLocal8Bit().data() << "\" is not (part of) a Syncthing directory.";
cerr << Phrases::End << flush;
2017-04-06 00:08:24 +02:00
QCoreApplication::exit(2);
return false;
}
void Application::printDir(const SyncthingDir *dir)
{
cout << " - ";
setStyle(cout, TextAttribute::Bold);
cout << dir->id.toLocal8Bit().data() << '\n';
setStyle(cout);
printProperty("Label", dir->label);
printProperty("Path", dir->path);
printProperty("Status", dir->statusString());
2017-09-17 20:33:01 +02:00
printProperty("Global", directoryStatusString(dir->globalFiles, dir->globalDirs, dir->globalBytes), nullptr, 6);
printProperty("Local", directoryStatusString(dir->localFiles, dir->localDirs, dir->localBytes), nullptr, 6);
printProperty("Last scan time", dir->lastScanTime);
printProperty("Last file time", dir->lastFileTime);
printProperty("Last file name", dir->lastFileName);
printProperty("Download progress", dir->downloadLabel);
printProperty("Shared with", dir->deviceNames.isEmpty() ? dir->deviceIds : dir->deviceNames);
printProperty("Read-only", dir->readOnly);
printProperty("Ignore permissions", dir->ignorePermissions);
printProperty("Auto-normalize", dir->autoNormalize);
printProperty("Rescan interval", TimeSpan::fromSeconds(dir->rescanInterval));
printProperty("Min. free disk percentage", dir->minDiskFreePercentage);
printProperty("Error", dir->globalError);
if (!dir->itemErrors.empty()) {
cout << " Failed items\n";
for (const SyncthingItemError &error : dir->itemErrors) {
printProperty(" - Message", error.message);
printProperty(" File", error.path);
}
}
cout << '\n';
}
void Application::printDev(const SyncthingDev *dev)
{
cout << " - ";
setStyle(cout, TextAttribute::Bold);
cout << dev->name.toLocal8Bit().data() << '\n';
setStyle(cout);
printProperty("ID", dev->id);
printProperty("Status", dev->statusString());
printProperty("Addresses", dev->addresses);
printProperty("Compression", dev->compression);
printProperty("Cert name", dev->certName);
printProperty("Connection address", dev->connectionAddress);
printProperty("Connection type", dev->connectionType);
printProperty("Client version", dev->clientVersion);
printProperty("Last seen", dev->lastSeen);
2017-05-01 03:34:43 +02:00
if (dev->totalIncomingTraffic > 0) {
printProperty("Incoming traffic", dataSizeToString(static_cast<uint64>(dev->totalIncomingTraffic)).data());
}
2017-05-01 03:34:43 +02:00
if (dev->totalOutgoingTraffic > 0) {
printProperty("Outgoing traffic", dataSizeToString(static_cast<uint64>(dev->totalOutgoingTraffic)).data());
}
cout << '\n';
}
void Application::printStatus(const ArgumentOccurrence &)
{
findRelevantDirsAndDevs();
2016-10-02 21:59:28 +02:00
// display dirs
2017-05-01 03:34:43 +02:00
if (!m_relevantDirs.empty()) {
2016-10-02 21:59:28 +02:00
setStyle(cout, TextAttribute::Bold);
cout << "Directories\n";
setStyle(cout);
for_each(m_relevantDirs.cbegin(), m_relevantDirs.cend(), &Application::printDir);
2016-10-02 21:59:28 +02:00
}
// display devs
2017-05-01 03:34:43 +02:00
if (!m_relevantDevs.empty()) {
2016-10-02 21:59:28 +02:00
setStyle(cout, TextAttribute::Bold);
cout << "Devices\n";
setStyle(cout);
for_each(m_relevantDevs.cbegin(), m_relevantDevs.cend(), &Application::printDev);
2016-10-02 21:59:28 +02:00
}
cout.flush();
QCoreApplication::exit();
}
void Application::printLog(const std::vector<SyncthingLogEntry> &logEntries)
{
eraseLine(cout);
cout << '\r';
2017-05-01 03:34:43 +02:00
for (const SyncthingLogEntry &entry : logEntries) {
cout << DateTime::fromIsoStringLocal(entry.when.toLocal8Bit().data()).toString(DateTimeOutputFormat::DateAndTime, true).data() << ':' << ' '
<< entry.message.toLocal8Bit().data() << '\n';
2016-10-02 21:59:28 +02:00
}
cout.flush();
QCoreApplication::exit();
}
void Application::initWaitForIdle(const ArgumentOccurrence &)
{
m_preventDisconnect = true;
findRelevantDirsAndDevs();
// might idle already
waitForIdle();
// currently not idling
// -> relevant dirs/devs might be invalidated so findRelevantDirsAndDevs() must invoked again
2017-05-01 03:34:43 +02:00
connect(&m_connection, &SyncthingConnection::newDirs, this, static_cast<void (Application::*)(void)>(&Application::findRelevantDirsAndDevs));
connect(&m_connection, &SyncthingConnection::newDevices, this, static_cast<void (Application::*)(void)>(&Application::findRelevantDirsAndDevs));
// -> check for idle again when dir/dev status changed
connect(&m_connection, &SyncthingConnection::dirStatusChanged, this, &Application::waitForIdle);
connect(&m_connection, &SyncthingConnection::devStatusChanged, this, &Application::waitForIdle);
}
void Application::waitForIdle()
{
2017-05-01 03:34:43 +02:00
for (const SyncthingDir *dir : m_relevantDirs) {
switch (dir->status) {
case SyncthingDirStatus::Unknown:
case SyncthingDirStatus::Idle:
2016-11-01 16:59:58 +01:00
case SyncthingDirStatus::Unshared:
break;
default:
return;
}
}
2017-05-01 03:34:43 +02:00
for (const SyncthingDev *dev : m_relevantDevs) {
switch (dev->status) {
case SyncthingDevStatus::Unknown:
case SyncthingDevStatus::Disconnected:
case SyncthingDevStatus::OwnDevice:
case SyncthingDevStatus::Idle:
break;
default:
return;
}
}
QCoreApplication::exit();
}
2017-04-06 00:08:24 +02:00
void Application::checkPwdOperationPresent(const ArgumentOccurrence &occurrence)
{
// FIXME: implement default operation in argument parser
if (m_args.pwd.specifiedOperation()) {
return;
}
2017-04-06 00:08:24 +02:00
// print status when no operation specified
printPwdStatus(occurrence);
}
void Application::printPwdStatus(const ArgumentOccurrence &)
{
2017-05-01 03:34:43 +02:00
if (!findPwd()) {
return;
}
2017-04-06 00:08:24 +02:00
printDir(m_pwd);
QCoreApplication::quit();
}
2017-04-06 00:08:24 +02:00
void Application::requestRescanPwd(const ArgumentOccurrence &)
{
2017-05-01 03:34:43 +02:00
if (!findPwd()) {
return;
2017-04-06 00:08:24 +02:00
}
2017-05-01 03:34:43 +02:00
if (m_relativePath.isEmpty()) {
2017-04-06 00:08:24 +02:00
cerr << "Request rescanning directory \"" << m_pwd->path.toLocal8Bit().data() << "\" ..." << endl;
} else {
2017-05-01 03:34:43 +02:00
cerr << "Request rescanning item \"" << m_relativePath.toLocal8Bit().data() << "\" in directory \"" << m_pwd->path.toLocal8Bit().data()
<< "\" ..." << endl;
2017-04-06 00:08:24 +02:00
}
m_connection.rescan(m_pwd->id, m_relativePath);
connect(&m_connection, &SyncthingConnection::rescanTriggered, this, &Application::handleResponse);
m_expectedResponse = 1;
}
void Application::requestPausePwd(const ArgumentOccurrence &)
{
2017-05-01 03:34:43 +02:00
if (!findPwd()) {
return;
}
2017-05-01 03:34:43 +02:00
if (m_connection.pauseDirectories(QStringList(m_pwd->id))) {
2017-04-06 00:08:24 +02:00
cerr << "Request pausing directory \"" << m_pwd->path.toLocal8Bit().data() << "\" ..." << endl;
connect(&m_connection, &SyncthingConnection::directoryPauseTriggered, this, &Application::handleResponse);
m_preventDisconnect = true;
m_expectedResponse = 1;
} else {
cerr << "Directory \"" << m_pwd->path.toLocal8Bit().data() << " already paused" << endl;
QCoreApplication::quit();
}
}
2017-04-06 00:08:24 +02:00
void Application::requestResumePwd(const ArgumentOccurrence &)
{
2017-05-01 03:34:43 +02:00
if (!findPwd()) {
2017-04-06 00:08:24 +02:00
return;
}
2017-05-01 03:34:43 +02:00
if (m_connection.resumeDirectories(QStringList(m_pwd->id))) {
2017-04-06 00:08:24 +02:00
cerr << "Request resuming directory \"" << m_pwd->path.toLocal8Bit().data() << "\" ..." << endl;
connect(&m_connection, &SyncthingConnection::directoryResumeTriggered, this, &Application::handleResponse);
m_preventDisconnect = true;
m_expectedResponse = 1;
return;
} else {
cerr << "Directory \"" << m_pwd->path.toLocal8Bit().data() << " not paused" << endl;
QCoreApplication::quit();
}
}
2016-10-02 21:59:28 +02:00
} // namespace Cli