Base libsyncthing on official library refactoring

This commit is contained in:
Martchus 2019-07-17 17:53:36 +02:00
parent fe332078f1
commit 038225936e
11 changed files with 128 additions and 120 deletions

View File

@ -78,7 +78,8 @@ endif ()
file(GLOB_RECURSE SRC_FILES_SYNCTHING
LIST_DIRECTORIES false
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"${SYNCTHING_PATH}/cmd/*.go" "${SYNCTHING_PATH}/cmd/*.h" "${SYNCTHING_PATH}/cmd/*.c")
"${SYNCTHING_PATH}/c-bindings/*.go" "${SYNCTHING_PATH}/c-bindings/*.h" "${SYNCTHING_PATH}/c-bindings/*.c"
"${SYNCTHING_PATH}/lib/*.go" "${SYNCTHING_PATH}/lib/*.h" "${SYNCTHING_PATH}/lib/*.c")
if (NOT SRC_FILES_SYNCTHING)
message(
FATAL_ERROR
@ -119,7 +120,7 @@ add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/libsyncthinginternal.a"
c-archive
-o
"${CMAKE_CURRENT_BINARY_DIR}/libsyncthinginternal.a"
./cmd/syncthing
./c-bindings
&&
"${CMAKE_RANLIB}"
"${CMAKE_CURRENT_BINARY_DIR}/libsyncthinginternal.a"
@ -136,8 +137,8 @@ elseif (UNIX)
list(APPEND PRIVATE_LIBRARIES -lpthread)
endif ()
# ensure we can find libsyncthing.h from Syncthing's source tree when building the interface
list(APPEND PRIVATE_INCLUDE_DIRS "${SYNCTHING_PATH}/cmd/syncthing")
# ensure we can find c_bindings.h from Syncthing's source tree when building the interface
list(APPEND PRIVATE_INCLUDE_DIRS "${SYNCTHING_PATH}/c-bindings")
# find c++utilities
find_package(c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.0.0 REQUIRED)

@ -1 +1 @@
Subproject commit 07ac034022b4d4811b23ff83c62959a79c965627
Subproject commit 51440c77d846bbca1de48d58d6fc5ad69758ca7a

View File

@ -73,20 +73,31 @@ public:
private:
bool m_invalid;
static bool s_loggingInitialized;
};
bool RunningState::s_loggingInitialized = false;
inline RunningState::RunningState()
{
// prevent running multiple Syncthing instances at the same time (for now)
if ((m_invalid = syncthingRunning.load())) {
return;
}
::libst_loggingCallbackFunction = handleLoggingCallback;
// initialize logging callback
if (!s_loggingInitialized) {
::libst_init_logging();
s_loggingInitialized = true;
}
::libst_logging_callback_function = handleLoggingCallback;
syncthingRunning.store(true);
}
inline RunningState::~RunningState()
{
::libst_loggingCallbackFunction = nullptr;
::libst_logging_callback_function = nullptr;
syncthingRunning.store(false);
}
@ -129,49 +140,8 @@ long long runSyncthing(const RuntimeOptions &options)
if (!runningState) {
return -1;
}
return ::libst_runSyncthingWithConfig(
gostr(options.configDir), gostr(options.guiAddress), gostr(options.guiApiKey), gostr(options.logFile), options.verbose);
}
/*!
* \brief Runs a Syncthing instance using the default options and the specified \a configDir.
* \return Returns the exit code (as usual, zero means no error).
* \remark
* - Does nothing if Syncthing is already running.
* - Blocks the current thread as long as the instance is running.
* Use eg. std::thread(runSyncthing, options) to run it in another thread.
*/
long long runSyncthing(const std::string &configDir)
{
const RunningState runningState;
if (!runningState) {
return -1;
}
const string empty;
return ::libst_runSyncthingWithConfig(gostr(configDir), gostr(empty), gostr(empty), gostr(empty), false);
}
/*!
* \brief Runs a Syncthing instance using the specified raw \a cliArguments.
* \return Returns the exit code (as usual, zero means no error).
* \remark
* - Does nothing if Syncthing is already running.
* - Blocks the current thread as long as the instance is running.
* Use eg. std::thread(runSyncthing, options) to run it in another thread.
*/
long long runSyncthing(const std::vector<string> &cliArguments)
{
const RunningState runningState;
if (!runningState) {
return -1;
}
vector<const char *> argsAsGoStrings;
argsAsGoStrings.reserve(cliArguments.size());
for (const auto &arg : cliArguments) {
argsAsGoStrings.emplace_back(arg.data());
}
const GoSlice slice{ argsAsGoStrings.data(), static_cast<GoInt>(argsAsGoStrings.size()), static_cast<GoInt>(argsAsGoStrings.capacity()) };
return ::libst_runSyncthingWithArgs(slice);
return ::libst_run_syncthing(
gostr(options.configDir), gostr(options.guiAddress), gostr(options.guiApiKey), options.verbose);
}
/*!
@ -194,37 +164,16 @@ void stopSyncthing()
if (!syncthingRunning.load()) {
return;
}
::libst_stopSyncthing();
::libst_stop_syncthing();
}
/*!
* \brief Restarts Syncthing if it is running; otherwise does nothing.
* \returns Might be called from any thread.
* \todo Make this actually work. Currently crashes happen after stopping Syncthing.
* \sa https://github.com/syncthing/syncthing/issues/4085
* \brief Returns the ID of the own device.
* \remarks The own device ID is initialized within runSyncthing().
*/
void restartSyncthing()
string ownDeviceId()
{
if (!syncthingRunning.load()) {
return;
}
::libst_restartSyncthing();
}
/*!
* \brief Generates certificated in the specified directory.
*/
void generateCertFiles(const std::string &generateDir)
{
::libst_generateCertFiles(gostr(generateDir));
}
/*!
* \brief Opens the Syncthing GUI.
*/
void openGUI()
{
::libst_openGUI();
return stdstr(::libst_own_device_id());
}
/*!
@ -232,7 +181,7 @@ void openGUI()
*/
string syncthingVersion()
{
return stdstr(::libst_syncthingVersion());
return stdstr(::libst_syncthing_version());
}
/*!
@ -240,7 +189,7 @@ string syncthingVersion()
*/
string longSyncthingVersion()
{
return stdstr(::libst_longSyncthingVersion());
return stdstr(::libst_long_syncthing_version());
}
} // namespace LibSyncthing

View File

@ -13,7 +13,6 @@ struct RuntimeOptions {
std::string configDir;
std::string guiAddress;
std::string guiApiKey;
std::string logFile;
bool verbose = false;
};
@ -31,14 +30,10 @@ using LoggingCallback = std::function<void(LogLevel, const char *message, std::s
void LIB_SYNCTHING_EXPORT setLoggingCallback(const LoggingCallback &callback);
void LIB_SYNCTHING_EXPORT setLoggingCallback(LoggingCallback &&callback);
long long LIB_SYNCTHING_EXPORT runSyncthing(const RuntimeOptions &options);
long long LIB_SYNCTHING_EXPORT runSyncthing(const std::string &configDir);
long long LIB_SYNCTHING_EXPORT runSyncthing(const std::vector<std::string> &cliArguments);
long long LIB_SYNCTHING_EXPORT runSyncthing(const RuntimeOptions &options = RuntimeOptions{});
bool LIB_SYNCTHING_EXPORT isSyncthingRunning();
void LIB_SYNCTHING_EXPORT stopSyncthing();
void LIB_SYNCTHING_EXPORT restartSyncthing();
void LIB_SYNCTHING_EXPORT generateCertFiles(const std::string &generateDir);
void LIB_SYNCTHING_EXPORT openGUI();
std::string LIB_SYNCTHING_EXPORT ownDeviceId();
std::string LIB_SYNCTHING_EXPORT syncthingVersion();
std::string LIB_SYNCTHING_EXPORT longSyncthingVersion();

View File

@ -28,7 +28,6 @@ using namespace CPPUNIT_NS;
class InterfaceTests : public TestFixture {
CPPUNIT_TEST_SUITE(InterfaceTests);
CPPUNIT_TEST(testRunWidthConfig);
CPPUNIT_TEST(testRunWithArgs);
CPPUNIT_TEST(testVersion);
CPPUNIT_TEST_SUITE_END();
@ -37,7 +36,6 @@ public:
void testInitialState();
void testRunWidthConfig();
void testRunWithArgs();
void testVersion();
void setUp();
@ -107,9 +105,8 @@ void InterfaceTests::testInitialState()
{
CPPUNIT_ASSERT_MESSAGE("initially not running", !isSyncthingRunning());
// stopping and restarting Syncthing when not running should not cause any trouble
// stopping Syncthing when not running should not cause any trouble
stopSyncthing();
restartSyncthing();
}
/*!
@ -190,17 +187,6 @@ void InterfaceTests::testRunWidthConfig()
testRun(bind(static_cast<long long (*)(const RuntimeOptions &)>(&runSyncthing), cref(options)));
}
void InterfaceTests::testRunWithArgs()
{
const std::vector<std::string> args{
"-no-restart",
"-no-browser",
"-home",
setupConfigDir(),
};
testRun(bind(static_cast<long long (*)(const decltype(args) &)>(&runSyncthing), cref(args)));
}
/*!
* \brief Tests whether the version() functions at least return something.
*/

View File

@ -71,14 +71,7 @@ void SyncthingLauncher::launch(const QString &program, const QStringList &argume
}
// use libsyncthing
vector<string> utf8Arguments{ "-no-restart", "-no-browser" };
utf8Arguments.reserve(utf8Arguments.size() + static_cast<size_t>(arguments.size()));
for (const auto &arg : arguments) {
const auto utf8Data(arg.toUtf8());
utf8Arguments.emplace_back(utf8Data.data(), utf8Data.size());
}
m_future = QtConcurrent::run(
this, static_cast<void (SyncthingLauncher::*)(const std::vector<std::string> &)>(&SyncthingLauncher::runLibSyncthing), utf8Arguments);
m_future = QtConcurrent::run(this, static_cast<void (SyncthingLauncher::*)()>(&SyncthingLauncher::runLibSyncthing));
}
/*!
@ -94,8 +87,13 @@ void SyncthingLauncher::launch(const Settings::Launcher &launcherSettings)
emit errorOccurred(QProcess::FailedToStart);
return;
}
launch(launcherSettings.useLibSyncthing ? QString() : launcherSettings.syncthingPath,
SyncthingProcess::splitArguments(launcherSettings.syncthingArgs));
if (launcherSettings.useLibSyncthing) {
LibSyncthing::RuntimeOptions options;
options.configDir = launcherSettings.libSyncthing.configDir.toStdString();
launch(options);
} else {
launch(launcherSettings.syncthingPath, SyncthingProcess::splitArguments(launcherSettings.syncthingArgs));
}
}
/*!
@ -208,12 +206,12 @@ void SyncthingLauncher::runLibSyncthing(const LibSyncthing::RuntimeOptions &runt
#endif
}
void SyncthingLauncher::runLibSyncthing(const std::vector<string> &arguments)
void SyncthingLauncher::runLibSyncthing()
{
#ifdef SYNCTHINGWIDGETS_USE_LIBSYNCTHING
LibSyncthing::setLoggingCallback(bind(&SyncthingLauncher::handleLoggingCallback, this, _1, _2, _3));
emit runningChanged(true);
const auto exitCode = LibSyncthing::runSyncthing(arguments);
const auto exitCode = LibSyncthing::runSyncthing();
emit exited(static_cast<int>(exitCode), exitCode == 0 ? QProcess::NormalExit : QProcess::CrashExit);
emit runningChanged(false);
#else

View File

@ -55,7 +55,7 @@ private Q_SLOTS:
void handleProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void handleLoggingCallback(LibSyncthing::LogLevel, const char *message, std::size_t messageSize);
void runLibSyncthing(const LibSyncthing::RuntimeOptions &runtimeOptions);
void runLibSyncthing(const std::vector<std::string> &arguments);
void runLibSyncthing();
private:
SyncthingProcess m_process;

View File

@ -61,6 +61,16 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="configDirLabel">
<property name="text">
<string>Config directory</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QtUtilities::PathSelection" name="configDirPathSelection" native="true"/>
</item>
</layout>
</widget>
</item>
@ -110,9 +120,6 @@
</item>
<item>
<widget class="QPushButton" name="launchNowPushButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -210,5 +217,69 @@
</hint>
</hints>
</connection>
<connection>
<sender>useBuiltInVersionCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>argumentsLineEdit</receiver>
<slot>setHidden(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>319</x>
<y>68</y>
</hint>
<hint type="destinationlabel">
<x>394</x>
<y>101</y>
</hint>
</hints>
</connection>
<connection>
<sender>useBuiltInVersionCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>configDirPathSelection</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>319</x>
<y>68</y>
</hint>
<hint type="destinationlabel">
<x>171</x>
<y>132</y>
</hint>
</hints>
</connection>
<connection>
<sender>useBuiltInVersionCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>configDirLabel</receiver>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>319</x>
<y>68</y>
</hint>
<hint type="destinationlabel">
<x>116</x>
<y>132</y>
</hint>
</hints>
</connection>
<connection>
<sender>useBuiltInVersionCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>argumentsLabel</receiver>
<slot>setHidden(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>319</x>
<y>68</y>
</hint>
<hint type="destinationlabel">
<x>131</x>
<y>101</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -251,6 +251,7 @@ void restore()
auto &launcher = v.launcher;
launcher.autostartEnabled = settings.value(QStringLiteral("syncthingAutostart"), launcher.autostartEnabled).toBool();
launcher.useLibSyncthing = settings.value(QStringLiteral("useLibSyncthing"), launcher.useLibSyncthing).toBool();
launcher.libSyncthing.configDir = settings.value(QStringLiteral("libSyncthingConfigDir"), launcher.libSyncthing.configDir).toString();
launcher.syncthingPath = settings.value(QStringLiteral("syncthingPath"), launcher.syncthingPath).toString();
launcher.syncthingArgs = settings.value(QStringLiteral("syncthingArgs"), launcher.syncthingArgs).toString();
launcher.considerForReconnect = settings.value(QStringLiteral("considerLauncherForReconnect"), launcher.considerForReconnect).toBool();
@ -341,6 +342,7 @@ void save()
const auto &launcher = v.launcher;
settings.setValue(QStringLiteral("syncthingAutostart"), launcher.autostartEnabled);
settings.setValue(QStringLiteral("useLibSyncthing"), launcher.useLibSyncthing);
settings.setValue(QStringLiteral("libSyncthingConfigDir"), launcher.libSyncthing.configDir);
settings.setValue(QStringLiteral("syncthingPath"), launcher.syncthingPath);
settings.setValue(QStringLiteral("syncthingArgs"), launcher.syncthingArgs);
settings.setValue(QStringLiteral("considerLauncherForReconnect"), launcher.considerForReconnect);

View File

@ -73,6 +73,10 @@ struct SYNCTHINGWIDGETS_EXPORT Launcher {
bool considerForReconnect = false;
bool showButton = false;
struct LibSyncthing {
QString configDir;
} libSyncthing;
static Data::SyncthingProcess &toolProcess(const QString &tool);
static std::vector<Data::SyncthingProcess *> allProcesses();
void autostart() const;

View File

@ -779,15 +779,16 @@ QWidget *LauncherOptionPage::setupWidget()
m_restoreArgsButton->setToolTip(tr("Restore default"));
connect(m_restoreArgsButton, &IconButton::clicked, this, &LauncherOptionPage::restoreDefaultArguments);
ui()->argumentsLineEdit->insertCustomButton(0, m_restoreArgsButton);
ui()->configDirPathSelection->provideCustomFileMode(QFileDialog::Directory);
}
// setup other widgets
ui()->syncthingPathSelection->provideCustomFileMode(QFileDialog::ExistingFile);
ui()->logTextEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
const auto running(isRunning());
const auto running = isRunning();
ui()->launchNowPushButton->setHidden(running);
ui()->stopPushButton->setHidden(!running);
ui()->useBuiltInVersionCheckBox->setHidden(!SyncthingLauncher::isLibSyncthingAvailable());
ui()->useBuiltInVersionCheckBox->setVisible(isSyncthing && SyncthingLauncher::isLibSyncthingAvailable());
// connect signals & slots
if (m_process) {
@ -813,6 +814,7 @@ bool LauncherOptionPage::apply()
if (m_tool.isEmpty()) {
settings.autostartEnabled = ui()->enabledCheckBox->isChecked();
settings.useLibSyncthing = ui()->useBuiltInVersionCheckBox->isChecked();
settings.libSyncthing.configDir = ui()->configDirPathSelection->lineEdit()->text();
settings.syncthingPath = ui()->syncthingPathSelection->lineEdit()->text();
settings.syncthingArgs = ui()->argumentsLineEdit->text();
settings.considerForReconnect = ui()->considerForReconnectCheckBox->isChecked();
@ -833,6 +835,7 @@ void LauncherOptionPage::reset()
ui()->enabledCheckBox->setChecked(settings.autostartEnabled);
ui()->useBuiltInVersionCheckBox->setChecked(settings.useLibSyncthing);
ui()->useBuiltInVersionCheckBox->setVisible(settings.useLibSyncthing || SyncthingLauncher::isLibSyncthingAvailable());
ui()->configDirPathSelection->lineEdit()->setText(settings.libSyncthing.configDir);
ui()->syncthingPathSelection->lineEdit()->setText(settings.syncthingPath);
ui()->argumentsLineEdit->setText(settings.syncthingArgs);
ui()->considerForReconnectCheckBox->setChecked(settings.considerForReconnect);
@ -961,8 +964,7 @@ void LauncherOptionPage::launch()
}
const auto launcherSettings(values().launcher);
if (m_tool.isEmpty()) {
m_launcher->launch(launcherSettings.useLibSyncthing ? QString() : launcherSettings.syncthingPath,
SyncthingProcess::splitArguments(launcherSettings.syncthingArgs));
m_launcher->launch(launcherSettings);
} else {
const auto toolParams(launcherSettings.tools.value(m_tool));
m_process->startSyncthing(toolParams.path, SyncthingProcess::splitArguments(toolParams.args));