Purpose

purposeprocess_main.cpp
1/*
2 SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include <KPluginMetaData>
8#include <QApplication>
9#include <QCborMap>
10#include <QCborValue>
11#include <QCommandLineParser>
12#include <QFileInfo>
13#include <QJsonDocument>
14#include <QLocalSocket>
15#include <QMetaMethod>
16
17#include "helper.h"
18#include "purpose_external_process_debug.h"
19#include <purpose/configuration.h>
20#include <purpose/job.h>
21
22static QString pluginType;
23static KPluginMetaData md;
24
25class Communication : public QObject
26{
28public:
29 Communication(const QString &serverName)
30 {
31 int pcIdx = metaObject()->indexOfSlot("propertyChanged()");
32 Q_ASSERT(pcIdx >= 0);
33 const QMetaMethod propertyChangedMethod = metaObject()->method(pcIdx);
34
35 m_socket.setServerName(serverName);
37 connect(&m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(error()));
38
39 bool b = m_socket.waitForConnected();
40 Q_ASSERT(b);
41
42 b = m_socket.waitForReadyRead();
43 Q_ASSERT(b);
44
45 Q_ASSERT(m_socket.canReadLine());
46 QByteArray byteLine = m_socket.readLine();
47 byteLine.chop(1); // Drop \n
48 const qint64 bytes = byteLine.toLongLong();
49 // QByteArray and QJsonDocument::from* can only handle int size.
50 // If the payload is bigger we are screwed.
51 Q_ASSERT(bytes <= std::numeric_limits<int>::max());
52
53 QByteArray dataArray;
54 dataArray.resize(bytes);
55 int pos = 0;
56 bool couldRead = false;
57 while ((pos < bytes) && (couldRead = (m_socket.bytesAvailable() || m_socket.waitForReadyRead()))) {
58 pos += m_socket.read(dataArray.data() + pos, qMin(m_socket.bytesAvailable(), bytes - pos));
59 }
60 Q_ASSERT(couldRead); // false if we hit a timeout before read-end.
61 Q_ASSERT(pos == bytes);
62
63 Purpose::Configuration config(QCborValue::fromCbor(dataArray).toMap().toJsonObject(), pluginType, md);
64 config.setUseSeparateProcess(false);
65
66 Q_ASSERT(config.isReady());
67
68 m_job = config.createJob();
69 m_job->start();
70
71 const QMetaObject *m = m_job->metaObject();
72 for (int i = 0, c = m->propertyCount(); i < c; ++i) {
73 QMetaProperty prop = m->property(i);
74 if (prop.hasNotifySignal() && prop.isReadable()) {
75 connect(m_job, prop.notifySignal(), this, propertyChangedMethod, Qt::UniqueConnection);
76 }
77 }
78 }
79
80private Q_SLOTS:
81 void error()
82 {
83 qCWarning(PURPOSE_EXTERNAL_PROCESS_LOG) << "socket error:" << m_socket.error();
84 }
85
86 void propertyChanged()
87 {
88 const int idx = senderSignalIndex();
89
90 const QMetaObject *m = m_job->metaObject();
91 QJsonObject toSend;
92 for (int i = 0, c = m->propertyCount(); i < c; ++i) {
93 QMetaProperty prop = m->property(i);
94 if (prop.notifySignalIndex() == idx) {
95 toSend[QString::fromLatin1(prop.name())] = fromVariant(prop.read(m_job));
96 }
97 }
98 send(toSend);
99 }
100
101 static QJsonValue fromVariant(const QVariant &var)
102 {
103 if (var.canConvert<QJsonObject>()) {
104 return var.toJsonObject();
105 } else {
106 return QJsonValue::fromVariant(var);
107 }
108 }
109
110private:
111 void send(const QJsonObject &object)
112 {
113 const QByteArray data = QJsonDocument(object).toJson(QJsonDocument::Compact) + '\n';
114 // qCDebug(PURPOSE_EXTERNAL_PROCESS_LOG) << "sending..." << data;
115 m_socket.write(data);
116 }
117
118 Purpose::Job *m_job = nullptr;
119 QLocalSocket m_socket;
120};
121
122int main(int argc, char **argv)
123{
124#pragma message("warning: make QGuiApplication, consider QCoreApplication?")
125 QApplication app(argc, argv);
126
127 QString serverName;
128
129 {
130 QCommandLineParser parser;
131 parser.addOption(QCommandLineOption(QStringLiteral("server"), QStringLiteral("Named socket to connect to"), QStringLiteral("name")));
132 parser.addOption(QCommandLineOption(QStringLiteral("pluginPath"), QStringLiteral("Chosen plugin"), QStringLiteral("path")));
133 parser.addOption(QCommandLineOption(QStringLiteral("pluginType"), QStringLiteral("Plugin type name "), QStringLiteral("path")));
134 parser.addHelpOption();
135
136 parser.process(app);
137
138 serverName = parser.value(QStringLiteral("server"));
139 pluginType = parser.value(QStringLiteral("pluginType"));
140
141 const QString path = parser.value(QStringLiteral("pluginPath"));
142 if (path.endsWith(QLatin1String("/metadata.json"))) {
143 QFileInfo fi(path);
144 md = Purpose::createMetaData(path);
145 } else {
146 md = KPluginMetaData(path);
147 Q_ASSERT(md.isValid());
148 }
149 }
150
151 Communication c(serverName);
152
153 return app.exec();
154}
155
156#include "purposeprocess_main.moc"
virtual Q_SCRIPTABLE void start()=0
bool isValid() const
This class will be in charge of figuring out the job configuration.
Job that will actually perform the sharing.
Definition job.h:34
const QVariantMap toMap(const MODEL &model)
QString path(const QString &relativePath)
void chop(qsizetype n)
char * data()
void resize(qsizetype newSize, char c)
qlonglong toLongLong(bool *ok, int base) const const
QCborValue fromCbor(QCborStreamReader &reader)
QCommandLineOption addHelpOption()
bool addOption(const QCommandLineOption &option)
void process(const QCoreApplication &app)
QString value(const QCommandLineOption &option) const const
QByteArray read(qint64 maxSize)
QByteArray readLine(qint64 maxSize)
qint64 write(const QByteArray &data)
QByteArray toJson(JsonFormat format) const const
QJsonValue fromVariant(const QVariant &variant)
virtual qint64 bytesAvailable() const const override
virtual bool canReadLine() const const override
void connectToServer(OpenMode openMode)
LocalSocketError error() const const
void setServerName(const QString &name)
bool waitForConnected(int msecs)
virtual bool waitForReadyRead(int msecs) override
int indexOfSlot(const char *slot) const const
QMetaMethod method(int index) const const
QMetaProperty property(int index) const const
int propertyCount() const const
bool hasNotifySignal() const const
bool isReadable() const const
const char * name() const const
QMetaMethod notifySignal() const const
int notifySignalIndex() const const
QVariant read(const QObject *object) const const
Q_OBJECTQ_OBJECT
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual const QMetaObject * metaObject() const const
int senderSignalIndex() const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromLatin1(QByteArrayView str)
UniqueConnection
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:19:52 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.