Merge pull request #2772 from csoler/v0.6-BugFixing_30

Improved JsonApi / WebUI interaction
This commit is contained in:
csoler 2023-09-22 22:55:41 +02:00 committed by GitHub
commit 7c90a2365c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 222 additions and 87 deletions

View File

@ -23,11 +23,14 @@
#include "rsharesettings.h" #include "rsharesettings.h"
#include "jsonapi/jsonapi.h" #include "jsonapi/jsonapi.h"
#include "util/misc.h" #include "util/misc.h"
#include "util/qtthreadsutils.h"
#include <QTimer> #include <QTimer>
#include <QStringListModel> #include <QStringListModel>
#include <QProgressDialog> #include <QProgressDialog>
#define IMAGE_LEDOFF ":/images/ledoff1.png"
#define IMAGE_LEDON ":/images/ledon1.png"
JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/) JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
{ {
@ -57,9 +60,27 @@ JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this); QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this);
ui.listenAddressLineEdit->setValidator(ipValidator); ui.listenAddressLineEdit->setValidator(ipValidator);
ui.providersListView->setSelectionMode(QAbstractItemView::NoSelection); // prevents edition.
mEventHandlerId = 0;
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> /* event */)
{
std::cerr << "Caught JSONAPI event!" << std::endl;
RsQThreadUtils::postToObject([=]() { load(); }, this );
},
mEventHandlerId, RsEventType::JSON_API );
} }
QString JsonApiPage::helpText() const
{
return tr("<h1><img width=\"24\" src=\":/icons/help_64.png\">&nbsp;&nbsp;Webinterface</h1> \
<p>Retroshare provides a JSON API allowing other softwares to communicate with its core using token-controlled HTTP requests to http://localhost:[port]. \
Please refer to the Retroshare documentation for how to use this feature. </p>\
<p>Unless you know what you're doing, you shouldn't need to change anything in this page. \
The web interface for instance will automatically register its own token to the JSON API which will be visible \
in the list of authenticated tokens after you enable it.</p>");
}
void JsonApiPage::enableJsonApi(bool checked) void JsonApiPage::enableJsonApi(bool checked)
{ {
ui.addTokenPushButton->setEnabled(checked); ui.addTokenPushButton->setEnabled(checked);
@ -93,9 +114,9 @@ bool JsonApiPage::updateParams()
void JsonApiPage::load() void JsonApiPage::load()
{ {
whileBlocking(ui.portSpinBox)->setValue(Settings->getJsonApiPort()); whileBlocking(ui.portSpinBox)->setValue(rsJsonApi->listeningPort());
whileBlocking(ui.listenAddressLineEdit)->setText(Settings->getJsonApiListenAddress()); whileBlocking(ui.listenAddressLineEdit)->setText(QString::fromStdString(rsJsonApi->getBindingAddress()));
whileBlocking(ui.enableCheckBox)->setChecked(Settings->getJsonApiEnabled()); whileBlocking(ui.enableCheckBox)->setChecked(rsJsonApi->isRunning());
QStringList newTk; QStringList newTk;
@ -105,9 +126,19 @@ void JsonApiPage::load()
QString::fromStdString(it.second) ); QString::fromStdString(it.second) );
whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk)); whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk));
}
QString JsonApiPage::helpText() const { return ""; } QStringList newTk2;
for(const auto& it : rsJsonApi->getResourceProviders())
newTk2.push_back( QString::fromStdString(it.get().getName())) ;
whileBlocking(ui.providersListView)->setModel(new QStringListModel(newTk2));
if(rsJsonApi->isRunning())
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDON)) ;
else
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDOFF)) ;
}
bool JsonApiPage::checkStartJsonApi() bool JsonApiPage::checkStartJsonApi()
{ {

View File

@ -20,6 +20,8 @@
#pragma once #pragma once
#include "retroshare/rsevents.h"
#include "retroshare-gui/configpage.h" #include "retroshare-gui/configpage.h"
#include "gui/common/FilesDefs.h" #include "gui/common/FilesDefs.h"
#include "ui_JsonApiPage.h" #include "ui_JsonApiPage.h"
@ -63,4 +65,6 @@ public slots:
private: private:
Ui::JsonApiPage ui; /// Qt Designer generated object Ui::JsonApiPage ui; /// Qt Designer generated object
RsEventsHandlerId_t mEventHandlerId;
}; };

View File

@ -13,7 +13,7 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="WebuiPageVLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QGroupBox" name="jsonApiGroupBox"> <widget class="QGroupBox" name="jsonApiGroupBox">
<property name="minimumSize"> <property name="minimumSize">
@ -25,7 +25,9 @@
<property name="title"> <property name="title">
<string>JSON API Server</string> <string>JSON API Server</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
<widget class="QCheckBox" name="enableCheckBox"> <widget class="QCheckBox" name="enableCheckBox">
<property name="text"> <property name="text">
@ -33,6 +35,56 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabelLED">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../images.qrc">:/images/ledoff1.png</pixmap>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Listen Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="listenAddressLineEdit">
<property name="text">
<string>127.0.0.1</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
@ -57,24 +109,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Listen Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="listenAddressLineEdit">
<property name="text">
<string>127.0.0.1</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
@ -110,13 +144,23 @@
<item> <item>
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Authenticated Tokens</string> <string>Authenticated Tokens:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QListView" name="tokensListView"/> <widget class="QListView" name="tokensListView"/>
</item> </item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Registered services:</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="providersListView"/>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -142,6 +186,8 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<resources/> <resources>
<include location="../images.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -27,6 +27,7 @@
#include <QSpinBox> #include <QSpinBox>
#include "util/misc.h" #include "util/misc.h"
#include "util/qtthreadsutils.h"
#include "retroshare/rswebui.h" #include "retroshare/rswebui.h"
#include "retroshare/rsjsonapi.h" #include "retroshare/rsjsonapi.h"
@ -40,6 +41,8 @@ resource_api::ApiServerLocal* WebuiPage::apiServerLocal = 0;
#endif #endif
resource_api::RsControlModule* WebuiPage::controlModule = 0; resource_api::RsControlModule* WebuiPage::controlModule = 0;
#define IMAGE_LEDOFF ":/images/ledoff1.png"
#define IMAGE_LEDON ":/images/ledon1.png"
WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/) WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
{ {
@ -50,6 +53,15 @@ WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
connect(ui.password_LE, SIGNAL(textChanged(QString)), this, SLOT(onPasswordValueChanged(QString))); connect(ui.password_LE, SIGNAL(textChanged(QString)), this, SLOT(onPasswordValueChanged(QString)));
connect(ui.startWebBrowser_PB, SIGNAL(clicked()), this, SLOT(onStartWebBrowserClicked())); connect(ui.startWebBrowser_PB, SIGNAL(clicked()), this, SLOT(onStartWebBrowserClicked()));
connect(ui.webInterfaceFilesDirectory_PB, SIGNAL(clicked()), this, SLOT(selectWebInterfaceDirectory())); connect(ui.webInterfaceFilesDirectory_PB, SIGNAL(clicked()), this, SLOT(selectWebInterfaceDirectory()));
mEventsHandlerId = 0;
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> /* event */)
{
std::cerr << "Caught JSONAPI event in webui!" << std::endl;
RsQThreadUtils::postToObject([=]() { load(); }, this );
},
mEventsHandlerId, RsEventType::JSON_API );
} }
WebuiPage::~WebuiPage() WebuiPage::~WebuiPage()
@ -73,22 +85,12 @@ void WebuiPage::selectWebInterfaceDirectory()
bool WebuiPage::updateParams(QString &errmsg) bool WebuiPage::updateParams(QString &errmsg)
{ {
std::cerr << "WebuiPage::save()" << std::endl; std::cerr << "WebuiPage::save()" << std::endl;
bool ok = true;
bool changed = false;
if(ui.enableWebUI_CB->isChecked() != Settings->getWebinterfaceEnabled())
changed = true;
if(ui.webInterfaceFiles_LE->text() != Settings->getWebinterfaceFilesDirectory())
changed = true;
if(changed)
{
// store config // store config
Settings->setWebinterfaceEnabled(ui.enableWebUI_CB->isChecked()); Settings->setWebinterfaceEnabled(ui.enableWebUI_CB->isChecked());
Settings->setWebinterfaceFilesDirectory(ui.webInterfaceFiles_LE->text()); Settings->setWebinterfaceFilesDirectory(ui.webInterfaceFiles_LE->text());
rsWebUi->setHtmlFilesDirectory(ui.webInterfaceFiles_LE->text().toStdString()); return true;
}
return ok;
} }
void WebuiPage::onPasswordValueChanged(QString password) void WebuiPage::onPasswordValueChanged(QString password)
@ -112,10 +114,23 @@ void WebuiPage::onPasswordValueChanged(QString password)
bool WebuiPage::restart() bool WebuiPage::restart()
{ {
return checkStartWebui(); if(ui.password_LE->text().isNull())
{
QMessageBox::critical(nullptr,tr("Missing passphrase"),tr("Please set a passphrase to proect the access to the WEB interface."));
return false;
}
rsWebUi->setUserPassword(ui.password_LE->text().toStdString());
rsWebUi->setHtmlFilesDirectory(ui.webInterfaceFiles_LE->text().toStdString());
setCursor(Qt::WaitCursor) ;
rsWebUi->restart();
setCursor(Qt::ArrowCursor) ;
return true;
} }
void WebuiPage::load() void WebuiPage::loadParams()
{ {
std::cerr << "WebuiPage::load()" << std::endl; std::cerr << "WebuiPage::load()" << std::endl;
whileBlocking(ui.enableWebUI_CB)->setChecked(Settings->getWebinterfaceEnabled()); whileBlocking(ui.enableWebUI_CB)->setChecked(Settings->getWebinterfaceEnabled());
@ -127,6 +142,13 @@ void WebuiPage::load()
if(it != smap.end()) if(it != smap.end())
whileBlocking(ui.password_LE)->setText(QString::fromStdString(it->second)); whileBlocking(ui.password_LE)->setText(QString::fromStdString(it->second));
if(rsWebUi->isRunning())
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDON)) ;
else
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDOFF)) ;
#else
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDOFF)) ;
#endif #endif
} }
@ -138,11 +160,9 @@ QString WebuiPage::helpText() const
<p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p>"); <p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p>");
} }
/*static*/ bool WebuiPage::checkStartWebui() /*static*/ bool WebuiPage::checkStartWebui() // This is supposed to be called from main(). But normally the parameters below (including the paswd
// for the webUI should be saved in p3webui instead.
{ {
if(!Settings->getWebinterfaceEnabled())
return false;
rsWebUi->setHtmlFilesDirectory(Settings->getWebinterfaceFilesDirectory().toStdString()); rsWebUi->setHtmlFilesDirectory(Settings->getWebinterfaceFilesDirectory().toStdString());
rsWebUi->restart(); rsWebUi->restart();
@ -173,15 +193,21 @@ QString WebuiPage::helpText() const
void WebuiPage::onEnableCBClicked(bool checked) void WebuiPage::onEnableCBClicked(bool checked)
{ {
ui.params_GB->setEnabled(checked); QString errmsg;
ui.apply_PB->setEnabled(checked); updateParams(errmsg);
ui.startWebBrowser_PB->setEnabled(checked);
QString S;
Settings->setWebinterfaceEnabled(checked); ui.params_GB->setEnabled(checked);
ui.startWebBrowser_PB->setEnabled(checked);
ui.apply_PB->setEnabled(checked);
if(checked) if(checked)
checkStartWebui(); {
if(!restart())
{
QMessageBox::warning(0, tr("failed to start Webinterface"), "Failed to start the webinterface.");
return;
}
}
else else
checkShutdownWebui(); checkShutdownWebui();
} }
@ -199,18 +225,12 @@ void WebuiPage::onAllIPCBClicked(bool /*checked*/)
} }
void WebuiPage::onApplyClicked() void WebuiPage::onApplyClicked()
{ {
rsWebUi->setUserPassword(ui.password_LE->text().toStdString());
QString errmsg; QString errmsg;
updateParams(errmsg); updateParams(errmsg);
if(!restart()) restart();
{
QMessageBox::warning(0, tr("failed to start Webinterface"), "Failed to start the webinterface.");
return;
}
emit passwordChanged(); load();
} }
void WebuiPage::onStartWebBrowserClicked() { showWebui(); } void WebuiPage::onStartWebBrowserClicked() { showWebui(); }

View File

@ -20,6 +20,8 @@
#pragma once #pragma once
#include "retroshare/rsevents.h"
#include "retroshare-gui/configpage.h" #include "retroshare-gui/configpage.h"
#include "gui/common/FilesDefs.h" #include "gui/common/FilesDefs.h"
#include "ui_WebuiPage.h" #include "ui_WebuiPage.h"
@ -42,11 +44,11 @@ public:
~WebuiPage(); ~WebuiPage();
/** Loads the settings for this page */ /** Loads the settings for this page */
virtual void load(); virtual void load() override { loadParams() ; }
virtual QPixmap iconPixmap() const { return FilesDefs::getPixmapFromQtResourcePath(":/icons/settings/webinterface.svg") ; } virtual QPixmap iconPixmap() const override { return FilesDefs::getPixmapFromQtResourcePath(":/icons/settings/webinterface.svg") ; }
virtual QString pageName() const { return tr("Webinterface") ; } virtual QString pageName() const override { return tr("Webinterface") ; }
virtual QString helpText() const; virtual QString helpText() const override ;
// call this after start of libretroshare/Retroshare // call this after start of libretroshare/Retroshare
// checks the settings and starts the webinterface if required // checks the settings and starts the webinterface if required
@ -67,10 +69,9 @@ public slots:
void onApplyClicked(); void onApplyClicked();
void onStartWebBrowserClicked(); void onStartWebBrowserClicked();
signals:
void passwordChanged();
private: private:
virtual void loadParams();
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::WebuiPage ui; Ui::WebuiPage ui;
@ -83,4 +84,6 @@ private:
static resource_api::ApiServerLocal* apiServerLocal; static resource_api::ApiServerLocal* apiServerLocal;
#endif #endif
static resource_api::RsControlModule* controlModule; static resource_api::RsControlModule* controlModule;
RsEventsHandlerId_t mEventsHandlerId;
}; };

View File

@ -6,14 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>960</width> <width>570</width>
<height>717</height> <height>646</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
<widget class="QCheckBox" name="enableWebUI_CB"> <widget class="QCheckBox" name="enableWebUI_CB">
<property name="text"> <property name="text">
@ -21,6 +23,38 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabelLED">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../images.qrc">:/images/ledoff1.png</pixmap>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QGroupBox" name="params_GB"> <widget class="QGroupBox" name="params_GB">
<property name="enabled"> <property name="enabled">

View File

@ -178,10 +178,7 @@ SettingsPage::initStackedWidget()
JsonApiPage *jsonapi_p = new JsonApiPage() ; JsonApiPage *jsonapi_p = new JsonApiPage() ;
addPage(jsonapi_p); addPage(jsonapi_p);
#ifdef RS_WEBUI #ifdef RS_WEBUI
WebuiPage *webui_p = new WebuiPage() ; addPage(new WebuiPage());
addPage(new WebuiPage() );
QObject::connect(webui_p,SIGNAL(passwordChanged()),jsonapi_p,SLOT(load()));
#endif #endif
#endif #endif