summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/CMakeLists.txt28
-rw-r--r--core/callmessage.cpp55
-rw-r--r--core/callmessage.h52
-rw-r--r--core/eventmessage.cpp67
-rw-r--r--core/eventmessage.h61
-rw-r--r--core/message.cpp79
-rw-r--r--core/message.h71
-rw-r--r--core/messageengine.cpp90
-rw-r--r--core/messageengine.h55
-rw-r--r--core/messageenginefactory.cpp39
-rw-r--r--core/messageenginefactory.h41
-rw-r--r--core/messagefactory.cpp39
-rw-r--r--core/messagefactory.h42
-rw-r--r--core/qtappfw-core.pc.in12
-rw-r--r--core/responsemessage.cpp101
-rw-r--r--core/responsemessage.h88
16 files changed, 920 insertions, 0 deletions
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
new file mode 100644
index 0000000..3102f3b
--- /dev/null
+++ b/core/CMakeLists.txt
@@ -0,0 +1,28 @@
+
+CONFIGURE_FILE("qtappfw-core.pc.in" "qtappfw-core.pc" @ONLY)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qtappfw-core.pc
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
+
+add_library(qtappfw-core SHARED message.cpp
+ messagefactory.cpp
+ messageengine.cpp
+ messageenginefactory.cpp
+ responsemessage.cpp
+ callmessage.cpp
+ eventmessage.cpp)
+
+target_include_directories(qtappfw-core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
+target_include_directories(qtappfw-core PUBLIC "${CMAKE_INSTALL_INCLUDEDIR}")
+
+target_link_libraries(qtappfw-core Qt5::WebSockets)
+
+set_target_properties(qtappfw-core PROPERTIES
+ VERSION ${PROJECT_VERSION}
+ SOVERSION 1
+ PUBLIC_HEADER "message.h;messagefactory.h;messageengine.h;messageenginefactory.h;responsemessage.h;callmessage.h;eventmessage.h")
+
+
+install(TARGETS qtappfw-core
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qtappfw-core)
+
diff --git a/core/callmessage.cpp b/core/callmessage.cpp
new file mode 100644
index 0000000..1dfa72e
--- /dev/null
+++ b/core/callmessage.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonValue>
+
+#include "callmessage.h"
+#include "message.h"
+
+
+bool CallMessage::createRequest(QString api, QString verb, QJsonValue parameter)
+{
+ if (!m_request.isEmpty()){
+ qWarning("Message instance has already been used. Cannot send another request.");
+ return false;
+ }
+
+ m_request["msgid"] = static_cast<unsigned int>(MessageId::Call);
+ m_request["callid"] = 0;
+ m_request["api"] = api;
+ m_request["verb"] = verb;
+ m_request["parameter"] = parameter;
+
+ m_init = true;
+
+ return m_init;
+}
+
+QByteArray CallMessage::serialize(QJsonDocument::JsonFormat format)
+{
+ QJsonArray array;
+ array.append(m_request["msgid"].toInt());
+ array.append(m_request["callid"].toInt());
+ array.append(m_request["api"].toString() + "/" + m_request["verb"].toString());
+ array.append(m_request["parameter"].toJsonValue());
+
+ m_jdoc.setArray(array);
+
+ return m_jdoc.toJson(format).data();
+}
diff --git a/core/callmessage.h b/core/callmessage.h
new file mode 100644
index 0000000..d08024e
--- /dev/null
+++ b/core/callmessage.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef CALLMESSAGE_H
+#define CALLMESSAGE_H
+
+#include "message.h"
+
+
+class CallMessage : public Message
+{
+ public:
+ bool createRequest(QString api, QString verb, QJsonValue parameter = "None");
+
+ bool isEvent() override
+ {
+ return false;
+ }
+
+ bool isReply() override
+ {
+ return false;
+ }
+
+ void updateCallId(unsigned int id) override
+ {
+ m_request["callid"] = qint32(id);
+ }
+
+ QByteArray serialize(QJsonDocument::JsonFormat format = QJsonDocument::Compact) override;
+
+ private:
+ QMap<QString, QVariant> m_request;
+
+ CallMessage() = default;
+ friend class MessageFactory;
+};
+
+#endif // CALLMESSAGE_H
diff --git a/core/eventmessage.cpp b/core/eventmessage.cpp
new file mode 100644
index 0000000..818830f
--- /dev/null
+++ b/core/eventmessage.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+#include "eventmessage.h"
+
+EventMessage::EventMessage(QJsonDocument content): Message()
+{
+ QJsonArray msg = content.array();
+ if (!msg[2].isObject()) {
+ qWarning("Invalid appfw payload: no JSON object");
+ return;
+ }
+
+ //deserialize:
+ QJsonObject payload = msg[2].toObject();
+
+ auto data_iter = payload.find("data");
+ m_event_data = data_iter.value().toObject();
+
+ auto event_iter = payload.find("event");
+ auto event_string = event_iter.value().toString();
+ if (event_string.isEmpty()) {
+ qWarning("Invalid appfw event message: empty event name");
+ return;
+ }
+ QStringList event_strings = event_string.split(QRegExp("/"));
+ if (event_strings.size() != 2) {
+ qWarning("Invalid appfw event message: malformed event name");
+ return;
+ }
+ m_event_api = event_strings[0];
+ m_event_name = event_strings[1];
+ m_init = true;
+}
+
+QByteArray EventMessage::serialize(QJsonDocument::JsonFormat format)
+{
+ QJsonArray array;
+ array.append(static_cast<int>(MessageId::Event));
+ array.append(0); //unused field
+ array.append(m_event_api + "/" + m_event_name);
+ array.append(m_event_data);
+
+ QJsonDocument jdoc;
+ jdoc.setArray(array);
+
+ return jdoc.toJson(format).data();
+}
diff --git a/core/eventmessage.h b/core/eventmessage.h
new file mode 100644
index 0000000..133574c
--- /dev/null
+++ b/core/eventmessage.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EVENTMESSAGE_H
+#define EVENTMESSAGE_H
+
+#include "message.h"
+
+
+class EventMessage : public Message
+{
+ public:
+ inline QString eventApi() const
+ {
+ return m_event_api;
+ }
+
+ inline QString eventName() const
+ {
+ return m_event_name;
+ }
+
+ inline QJsonObject eventData() const
+ {
+ return m_event_data;
+ }
+
+ bool isEvent() override
+ {
+ return true;
+ }
+
+ bool isReply() override
+ {
+ return false;
+ }
+
+ QByteArray serialize(QJsonDocument::JsonFormat format = QJsonDocument::Compact) override;
+
+ private:
+ QString m_event_api, m_event_name;
+ QJsonObject m_event_data;
+
+ explicit EventMessage(QJsonDocument data);
+ friend class MessageFactory;
+};
+
+#endif // EVENTMESSAGE_H
diff --git a/core/message.cpp b/core/message.cpp
new file mode 100644
index 0000000..1865f14
--- /dev/null
+++ b/core/message.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017-2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QWebSocket>
+
+#include "message.h"
+
+MessageId Message::isValid(QJsonDocument candidate)
+{
+ MessageId id = MessageId::Invalid;
+
+ // Validate message is array
+ if (!candidate.isArray()) {
+ qWarning("Invalid appfw message: not an array");
+ return id;
+ }
+ QJsonArray msg = candidate.array();
+
+ // Validate array is proper length
+ if ((msg.size() < 3) || (msg.size() > 4)) {
+ qWarning("Invalid appfw message: invalid array size");
+ return id;
+ }
+
+ // Validate msgid type
+ double msgid;
+ if (msg[0].isDouble()) {
+ msgid = msg[0].toDouble();
+ } else {
+ qWarning("Invalid appfw message: invalid msgid type");
+ return id;
+ }
+
+ // Validate msgid element
+ if ((msgid >= static_cast<double>(MessageId::Call)) && (msgid <= static_cast<double>(MessageId::Event)))
+ id = static_cast<MessageId>(msgid);
+
+ return id;
+}
+
+Message::Message()
+ : m_init(false)
+{
+}
+
+QByteArray Message::serialize(QJsonDocument::JsonFormat format)
+{
+ QByteArray dummy;
+ return dummy;
+ }
+
+QByteArray Message::send(QWebSocket& transport, unsigned int id)
+{
+ QByteArray blob;
+ qint64 size = 0;
+ updateCallId(id);
+ if (m_init)
+ blob = serialize().data();
+ if (!blob.isEmpty())
+ size = transport.sendTextMessage(blob);
+
+ return blob;
+}
diff --git a/core/message.h b/core/message.h
new file mode 100644
index 0000000..acbbefd
--- /dev/null
+++ b/core/message.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017-2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MESSAGE_H
+#define MESSAGE_H
+
+#include <memory>
+#include <QObject>
+#include <QMap>
+#include <QVariant>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+enum class MessageId {
+ Invalid = 0,
+ Call = 2,
+ RetOk = 3,
+ RetErr = 4,
+ Event = 5,
+};
+
+class QWebSocket;
+
+class Message
+{
+ public:
+ Message();
+ virtual bool setAdditionalData(QByteArray data)
+ {
+ return false;
+ }
+ QByteArray send(QWebSocket& transport, unsigned int callid);
+
+ inline bool isComplete() const
+ {
+ return m_init;
+ }
+
+ virtual bool getCallId(unsigned int *id) const
+ {
+ return false;
+ }
+
+ static MessageId isValid(QJsonDocument );
+
+ virtual bool isEvent() = 0;
+ virtual bool isReply() = 0;
+
+ protected:
+ virtual void updateCallId(unsigned int id) {};
+ virtual QByteArray serialize(QJsonDocument::JsonFormat format = QJsonDocument::Compact);
+
+ bool m_init;
+ QJsonDocument m_jdoc;
+};
+Q_DECLARE_METATYPE(std::shared_ptr<Message>)
+
+#endif // MESSAGE_H
diff --git a/core/messageengine.cpp b/core/messageengine.cpp
new file mode 100644
index 0000000..42fe95b
--- /dev/null
+++ b/core/messageengine.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017-2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QJsonArray>
+#include <QDebug>
+
+#include "message.h"
+#include "messagefactory.h"
+#include "messageengine.h"
+
+
+MessageEngine::MessageEngine(const QUrl &url) :
+ QObject(Q_NULLPTR),
+ m_callid(0),
+ m_url(url)
+{
+ connect(&m_websocket, &QWebSocket::connected, this, &MessageEngine::onConnected);
+ connect(&m_websocket, &QWebSocket::disconnected, this, &MessageEngine::onDisconnected);
+
+ m_websocket.open(url);
+}
+
+bool MessageEngine::sendMessage(std::unique_ptr<Message> msg)
+{
+ if (!msg)
+ return false;
+
+ unsigned int callid = m_callid++;
+ QByteArray forkeeps = msg->send(m_websocket, callid);
+ if (forkeeps.isEmpty())
+ return false;
+
+ std::lock_guard<std::mutex> localguard(m_mutex);
+ m_calls.insert(callid, forkeeps);
+
+ return true;
+}
+
+void MessageEngine::onConnected()
+{
+ connect(&m_websocket, &QWebSocket::textMessageReceived, this, &MessageEngine::onTextMessageReceived);
+ emit connected();
+}
+
+void MessageEngine::onDisconnected()
+{
+ disconnect(&m_websocket, &QWebSocket::textMessageReceived, this, &MessageEngine::onTextMessageReceived);
+ emit disconnected();
+}
+
+void MessageEngine::onTextMessageReceived(QString jsonStr)
+{
+ jsonStr = jsonStr.simplified();
+ QJsonDocument jdoc(QJsonDocument::fromJson(jsonStr.toUtf8()));
+ if (jdoc.isEmpty()) {
+ qWarning() << "Received invalid JSON: empty appfw message";
+ return;
+ }
+
+ MessageId id = Message::isValid(jdoc);
+ if (id == MessageId::Invalid) {
+ qWarning() << "Received unknown message, discarding";
+ return;
+ }
+
+ std::shared_ptr<Message> message = MessageFactory::getInstance().createInboundMessage(id, jdoc);
+
+ unsigned int callid;
+ if (message->isReply() && message->getCallId(&callid)) {
+ message->setAdditionalData(m_calls[callid]);
+ std::lock_guard<std::mutex> localguard(m_mutex);
+ m_calls.remove(callid);
+ }
+
+ if (message->isComplete())
+ emit messageReceived(message);
+}
diff --git a/core/messageengine.h b/core/messageengine.h
new file mode 100644
index 0000000..12aa5e9
--- /dev/null
+++ b/core/messageengine.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2017-2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MESSAGEENGINE_H
+#define MESSAGEENGINE_H
+
+#include <memory>
+#include <atomic>
+#include <mutex>
+#include <QUrl>
+#include <QWebSocket>
+
+#include "message.h"
+
+class MessageEngine : public QObject
+{
+ Q_OBJECT
+ public:
+ bool sendMessage(std::unique_ptr<Message> message);
+
+ Q_SIGNALS:
+ void disconnected();
+ void connected();
+ void messageReceived(std::shared_ptr<Message> message);
+
+ private Q_SLOTS:
+ void onConnected();
+ void onDisconnected();
+ void onTextMessageReceived(QString message);
+
+ private:
+ QWebSocket m_websocket;
+ std::mutex m_mutex;
+ QMap<qint32, QByteArray> m_calls;
+ QUrl m_url;
+ std::atomic<unsigned int> m_callid;
+
+ explicit MessageEngine(const QUrl &url);
+ friend class MessageEngineFactory;
+};
+
+#endif // MESSAGEENGINE_H
diff --git a/core/messageenginefactory.cpp b/core/messageenginefactory.cpp
new file mode 100644
index 0000000..04fb741
--- /dev/null
+++ b/core/messageenginefactory.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <unordered_map>
+#include <mutex>
+#include <QDebug>
+#include <QUrl>
+#include "messageenginefactory.h"
+#include "messageengine.h"
+
+std::shared_ptr<MessageEngine> MessageEngineFactory::getMessageEngine(const QUrl& url)
+{
+ static std::unordered_map<QString, std::shared_ptr<MessageEngine>> lut;
+ static std::mutex m;
+
+ std::lock_guard<std::mutex> localguard(m);
+ auto urlstr = url.toString();
+ auto pme = lut[urlstr];
+ if (!pme){
+ pme = std::shared_ptr<MessageEngine>{new MessageEngine(url)};
+ lut[urlstr] = pme;
+ }
+
+ return pme;
+}
diff --git a/core/messageenginefactory.h b/core/messageenginefactory.h
new file mode 100644
index 0000000..1ce107b
--- /dev/null
+++ b/core/messageenginefactory.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MESSAGEENGINEFACTORY_H
+#define MESSAGEENGINEFACTORY_H
+
+#include <memory>
+
+class MessageEngine;
+class QUrl;
+
+
+class MessageEngineFactory {
+ public:
+ static MessageEngineFactory& getInstance() {
+ static MessageEngineFactory instance;
+ return instance;
+ }
+ std::shared_ptr<MessageEngine> getMessageEngine(const QUrl &ur);
+ MessageEngineFactory(MessageEngineFactory const&) = delete;
+ void operator=(MessageEngineFactory const&) = delete;
+
+ private:
+ MessageEngineFactory() = default;
+ ~MessageEngineFactory() = default;
+};
+
+#endif // MESSAGENGINEEFACTORY_H
diff --git a/core/messagefactory.cpp b/core/messagefactory.cpp
new file mode 100644
index 0000000..6740e25
--- /dev/null
+++ b/core/messagefactory.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "messagefactory.h"
+#include "message.h"
+#include "responsemessage.h"
+#include "eventmessage.h"
+#include "callmessage.h"
+
+std::unique_ptr<Message> MessageFactory::createInboundMessage(MessageId id, QJsonDocument data)
+{
+ std::unique_ptr<Message> msg(nullptr);
+ if ((id == MessageId::RetOk) || (id == MessageId::RetErr))
+ msg.reset(new ResponseMessage(data));
+ else if (id == MessageId::Event)
+ msg.reset(new EventMessage(data));
+ return msg;
+}
+
+std::unique_ptr<Message> MessageFactory::createOutboundMessage(MessageId id)
+{
+ std::unique_ptr<Message> msg(nullptr);
+ if (id == MessageId::Call)
+ msg.reset(new CallMessage());
+ return msg;
+}
diff --git a/core/messagefactory.h b/core/messagefactory.h
new file mode 100644
index 0000000..f826483
--- /dev/null
+++ b/core/messagefactory.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MESSAGEFACTORY_H
+#define MESSAGEFACTORY_H
+
+#include <memory>
+#include <QJsonDocument>
+
+class Message;
+enum class MessageId;
+
+class MessageFactory {
+ public:
+ static MessageFactory& getInstance() {
+ static MessageFactory instance;
+ return instance;
+ }
+ std::unique_ptr<Message> createInboundMessage(MessageId id, QJsonDocument content);
+ std::unique_ptr<Message> createOutboundMessage(MessageId);
+ MessageFactory(MessageFactory const&) = delete;
+ void operator=(MessageFactory const&) = delete;
+
+ private:
+ MessageFactory() = default;
+ ~MessageFactory() = default;
+};
+
+#endif // MESSAGEFACTORY_H
diff --git a/core/qtappfw-core.pc.in b/core/qtappfw-core.pc.in
new file mode 100644
index 0000000..bfef2e0
--- /dev/null
+++ b/core/qtappfw-core.pc.in
@@ -0,0 +1,12 @@
+prefix=@DEST_DIR@
+exec_prefix=${prefix}
+libdir=${prefix}/lib
+includedir=${prefix}/include
+
+Name: qtappfw-core
+Description: Library wrapping AGL AppFW messages and bindings in Qt objects
+Version: 1.0.0
+
+Requires: Qt5WebSockets
+Libs: -L${libdir} -lqtappfw-core
+Cflags: -I${includedir}/qtappfw-core
diff --git a/core/responsemessage.cpp b/core/responsemessage.cpp
new file mode 100644
index 0000000..9f8e6f2
--- /dev/null
+++ b/core/responsemessage.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018-2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <QDebug>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+
+#include "responsemessage.h"
+
+
+ResponseMessage::ResponseMessage(QJsonDocument content)
+{
+ m_jdoc = content;
+ QJsonArray msg = content.array();
+ if (!msg[2].isObject()) {
+ qWarning("Invalid appfw payload: no JSON object");
+ return;
+ }
+
+ //deserialize:
+ auto callid = msg[1].toString().toInt();
+ QJsonObject payload = msg[2].toObject();
+
+ auto request_iter = payload.find("request");
+ auto request = request_iter.value().toObject();
+ if (request.empty()) {
+ qWarning("Invalid appfw reply message: empty request data");
+ return;
+ }
+
+ auto status_iter = request.find("status");
+ auto info_iter = request.find("info");
+ auto response_iter = payload.find("response");
+ auto response = response_iter.value().toObject();
+ m_reply_status = status_iter.value().toString();
+ m_reply_info = info_iter.value().toString();
+ m_reply_data = response;
+ m_reply_callid = callid;
+ m_init = false; //not complete yet, missing matching request data
+}
+
+bool ResponseMessage::setAdditionalData(QByteArray data)
+{
+ QJsonDocument jdoc(QJsonDocument::fromJson(data));
+ if (!jdoc.isArray()) {
+ qWarning("Invalid data: not an array");
+ return false;
+ }
+
+ QJsonArray content = jdoc.array();
+ if (content.size() != 4) {
+ qWarning("Invalid data: invalid array size");
+ return false;
+ }
+
+ QStringList api_str_list = content[2].toString().split(QRegExp("/"));
+ m_request["msgid"] = content.at(0);
+ m_request["callid"] = content.at(1);
+ m_request["api"] = api_str_list[0];
+ m_request["verb"] = api_str_list[1];
+ m_request["parameter"] = content.at(3);
+ m_init = true;
+ return true;
+}
+
+bool ResponseMessage::copyCallId(unsigned int *id)
+{
+ *id = m_reply_callid;
+ return true;
+}
+
+QByteArray ResponseMessage::serialize(QJsonDocument::JsonFormat format)
+{
+ QJsonArray array;
+ (m_reply_status == "failed")?
+ array.append(static_cast<int>(MessageId::RetErr)) :
+ array.append(static_cast<int>(MessageId::RetOk));
+ array.append(static_cast<int>(m_reply_callid));
+ array.append(m_request["api"].toString() + "/" + m_request["verb"].toString());
+ array.append(m_reply_data);
+
+ QJsonDocument jdoc;
+ jdoc.setArray(array);
+
+ return jdoc.toJson(format).data();
+}
diff --git a/core/responsemessage.h b/core/responsemessage.h
new file mode 100644
index 0000000..af6bda5
--- /dev/null
+++ b/core/responsemessage.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018-2020 Konsulko Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RESPONSEMESSAGE_H
+#define RESPONSEMESSAGE_H
+
+
+#include "message.h"
+
+class ResponseMessage : public Message
+{
+
+
+ public:
+ inline QString requestApi() const
+ {
+ return m_request["api"].toString();
+ }
+
+ inline QString requestVerb() const
+ {
+ return m_request["verb"].toString();
+ }
+
+ inline QVariantMap requestParameters() const
+ {
+ return m_request["parameter"].toMap();
+ }
+
+ inline QString replyStatus() const
+ {
+ return m_reply_status;
+ }
+
+ inline QString replyInfo() const
+ {
+ return m_reply_info;
+ }
+
+ inline QJsonObject replyData() const
+ {
+ return m_reply_data;
+ }
+
+ bool getCallId(unsigned int *id) const override
+ {
+ *id = m_reply_callid;
+ return true;
+ }
+ bool isEvent() override
+ {
+ return false;
+ }
+
+ bool isReply() override
+ {
+ return true;
+ }
+
+ bool setAdditionalData(QByteArray data) override;
+ bool copyCallId(unsigned int *id);
+
+ QByteArray serialize(QJsonDocument::JsonFormat format = QJsonDocument::Compact) override;
+
+ private:
+ QString m_reply_info, m_reply_status, m_reply_uuid;
+ unsigned int m_reply_callid;
+ QJsonObject m_reply_data;
+ QMap<QString, QVariant> m_request;
+
+ explicit ResponseMessage(QJsonDocument data);
+ friend class MessageFactory;
+};
+
+#endif // RESPONSEMESSAGE_H