feat: add basic tools for app real-time monitoring

Required by: https://github.com/status-im/status-desktop/issues/8786
This commit is contained in:
Michał Cieślak 2023-01-04 16:50:37 +01:00 committed by Michał
parent 4977b7aa2c
commit ce5561d3be
4 changed files with 135 additions and 6 deletions

View File

@ -2,18 +2,28 @@ project(DOtherSide)
include(GNUInstallDirs) include(GNUInstallDirs)
option(MONITORING "Tools for real-time inspection of the application." OFF)
set(MONITORING_QML_ENTRY_POINT "" CACHE STRING "QML file intended to start the monitoring tool UI.")
# Macro for merging common code between static and shared # Macro for merging common code between static and shared
macro(add_target name type) macro(add_target name type)
find_package(Qt5 COMPONENTS Core Qml Gui Quick QuickControls2 Widgets Network Multimedia REQUIRED) find_package(Qt5 COMPONENTS Core Qml Gui Quick QuickControls2 Widgets Network Multimedia REQUIRED)
file(GLOB_RECURSE HEADERS include/DOtherSide/*.h) file(GLOB HEADERS include/DOtherSide/*.h include/DOtherSide/Status/*.h)
if(APPLE)
file(GLOB_RECURSE SOURCES src/*.cpp src/*.mm) file(GLOB SOURCES src/*.cpp src/Status/*.cpp)
else()
file(GLOB_RECURSE SOURCES src/*.cpp) if(MONITORING)
file(GLOB MONITORING_HEADERS include/DOtherSide/Status/Monitoring/*.h)
file(GLOB MONITORING_SOURCES src/Status/Monitoring/*.cpp)
endif() endif()
add_library(${name} ${type} ${SOURCES} ${HEADERS}) if(APPLE)
file(GLOB MM_FILES src/*.mm src/Status/*.mm)
list(APPEND SOURCES ${MM_FILES})
endif()
add_library(${name} ${type} ${SOURCES} ${HEADERS} ${MONITORING_SOURCES} ${MONITORING_HEADERS})
if (WIN32) if (WIN32)
target_compile_definitions(${name} PRIVATE -DWIN32) target_compile_definitions(${name} PRIVATE -DWIN32)
@ -30,6 +40,11 @@ macro(add_target name type)
target_compile_definitions(${name} PRIVATE QML_DEBUG_PORT=${QML_DEBUG_PORT}) target_compile_definitions(${name} PRIVATE QML_DEBUG_PORT=${QML_DEBUG_PORT})
endif() endif()
if(MONITORING)
target_compile_definitions(${name} PRIVATE MONITORING)
target_compile_definitions(${name} PRIVATE MONITORING_QML_ENTRY_POINT="${MONITORING_QML_ENTRY_POINT}")
endif()
# for DOtherSide.pc # for DOtherSide.pc
set(PC_REQUIRES "Qt5Core, Qt5Gui, Qt5Widgets, Qt5Qml, Qt5Quick, Qt5Network, Qt5DBus, Qt5Multimedia, SortFilterProxyModel") set(PC_REQUIRES "Qt5Core, Qt5Gui, Qt5Widgets, Qt5Qml, Qt5Quick, Qt5Network, Qt5DBus, Qt5Multimedia, SortFilterProxyModel")
if (${Qt5QuickControls2_FOUND}) if (${Qt5QuickControls2_FOUND})

View File

@ -0,0 +1,29 @@
#pragma once
#include <QObject>
class QQmlApplicationEngine;
class QQmlEngine;
class QJSEngine;
class Monitor : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList contexPropertiesNames READ getContextPropertiesNames
NOTIFY contextPropertiesNamesChanged)
Monitor() = default;
public:
void initialize(QQmlApplicationEngine *engine);
QStringList getContextPropertiesNames() const;
void addContextPropertyName(const QString &contextPropertyName);
static Monitor& instance();
static QObject* qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine);
signals:
void contextPropertiesNamesChanged();
private:
QStringList m_contexPropertiesNames;
};

View File

@ -76,6 +76,11 @@
#include "DOtherSide/Status/QClipboardProxy.h" #include "DOtherSide/Status/QClipboardProxy.h"
#include "DOtherSide/Status/RXValidator.h" #include "DOtherSide/Status/RXValidator.h"
#ifdef MONITORING
#include <QProcessEnvironment>
#include "DOtherSide/Status/Monitoring/Monitor.h"
#endif
#include <qqmlsortfilterproxymodeltypes.h> #include <qqmlsortfilterproxymodeltypes.h>
namespace { namespace {
@ -87,6 +92,11 @@ void register_meta_types()
qmlRegisterType<StatusSyntaxHighlighter>("DotherSide", 0 , 1, "StatusSyntaxHighlighter"); qmlRegisterType<StatusSyntaxHighlighter>("DotherSide", 0 , 1, "StatusSyntaxHighlighter");
qmlRegisterSingletonType<QClipboardProxy>("DotherSide", 0 , 1, "QClipboardProxy", &QClipboardProxy::qmlInstance); qmlRegisterSingletonType<QClipboardProxy>("DotherSide", 0 , 1, "QClipboardProxy", &QClipboardProxy::qmlInstance);
qmlRegisterType<RXValidator>("DotherSide", 0, 1, "RXValidator"); qmlRegisterType<RXValidator>("DotherSide", 0, 1, "RXValidator");
#ifdef MONITORING
qmlRegisterSingletonType<Monitor>("Monitoring", 1 , 0, "Monitor", &Monitor::qmlInstance);
#endif
qqsfpm::registerTypes(); qqsfpm::registerTypes();
} }
@ -342,7 +352,18 @@ void dos_qguiapplication_installEventFilter(::DosEvent* vptr)
::DosQQmlApplicationEngine *dos_qqmlapplicationengine_create() ::DosQQmlApplicationEngine *dos_qqmlapplicationengine_create()
{ {
#ifdef MONITORING
auto engine = new QQmlApplicationEngine();
auto disabledValue = QStringLiteral("0");
if (QProcessEnvironment::systemEnvironment().value(
QStringLiteral("DISABLE_MONITORING_WINDOW"), disabledValue) == disabledValue)
Monitor::instance().initialize(engine);
return engine;
#else
return new QQmlApplicationEngine(); return new QQmlApplicationEngine();
#endif
} }
::DosQQmlNetworkAccessManagerFactory *dos_qqmlnetworkaccessmanagerfactory_create(const char* tmpPath) ::DosQQmlNetworkAccessManagerFactory *dos_qqmlnetworkaccessmanagerfactory_create(const char* tmpPath)
@ -601,6 +622,10 @@ void dos_qqmlcontext_setcontextproperty(::DosQQmlContext *vptr, const char *name
auto context = static_cast<QQmlContext *>(vptr); auto context = static_cast<QQmlContext *>(vptr);
auto variant = static_cast<QVariant *>(value); auto variant = static_cast<QVariant *>(value);
context->setContextProperty(QString::fromUtf8(name), *variant); context->setContextProperty(QString::fromUtf8(name), *variant);
#ifdef MONITORING
Monitor::instance().addContextPropertyName(QString::fromUtf8(name));
#endif
} }
::DosQVariant *dos_qvariant_create() ::DosQVariant *dos_qvariant_create()

View File

@ -0,0 +1,60 @@
#include "DOtherSide/Status/Monitoring/Monitor.h"
#include <QCoreApplication>
#include <QDebug>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
#include <QQuickWindow>
void Monitor::initialize(QQmlApplicationEngine* engine) {
QObject::connect(engine, &QQmlApplicationEngine::objectCreated, this,
[engine](QObject *obj, const QUrl &objUrl) {
if (!obj) {
qWarning() << "Error while loading QML:" << objUrl << "."
<< "Monitor initialization failed.";
return;
}
QQuickWindow* window = qobject_cast<QQuickWindow*>(obj);
QQmlComponent cmp(engine, QCoreApplication::applicationDirPath()
+ QStringLiteral(MONITORING_QML_ENTRY_POINT), window);
cmp.create(qmlContext(window));
if (cmp.isError()) {
qWarning() << "Failed to instantiate monitoring utilities:";
qWarning() << cmp.errors();
}
}, Qt::QueuedConnection);
}
QStringList Monitor::getContextPropertiesNames() const
{
return m_contexPropertiesNames;
}
void Monitor::addContextPropertyName(const QString &contextPropertyName)
{
if (m_contexPropertiesNames.contains(contextPropertyName))
return;
m_contexPropertiesNames << contextPropertyName;
emit contextPropertiesNamesChanged();
}
Monitor& Monitor::instance()
{
static Monitor monitor;
return monitor;
}
QObject* Monitor::qmlInstance(QQmlEngine *engine, QJSEngine *scriptEngine)
{
Q_UNUSED(engine);
Q_UNUSED(scriptEngine);
auto& inst = instance();
engine->setObjectOwnership(&inst, QQmlEngine::CppOwnership);
return &inst;
}