From aee2ff16cc87a939e68aa2900e23d6705dda5408 Mon Sep 17 00:00:00 2001 From: Dmitry Yudenich Date: Fri, 10 Jul 2020 14:40:15 +0300 Subject: Add client proxy for cloudproxy service Library with client proxy which hides communication with cloud proxy service has been added. It allows users to integrate cloudproxy service in their applications faster. Simple test applications have been added to demonstrate how to use libcloudproxy library. Bug-AGL: SPEC-3472 Signed-off-by: Dmitry Yudenich Change-Id: I84ab5e61ce09326e3dc49c927d402e6ec12ea1b0 --- sample/test-cloud-app/app/app.pri | 3 + sample/test-cloud-app/app/app.pro | 31 +++++ .../images/AGL_HMI_Blue_Background_NoCar-01.png | Bin 0 -> 698586 bytes sample/test-cloud-app/app/images/images.qrc | 5 + sample/test-cloud-app/app/main.cpp | 119 +++++++++++++++++ sample/test-cloud-app/app/main.cpp.save | 148 +++++++++++++++++++++ sample/test-cloud-app/app/mainwindow.cpp | 83 ++++++++++++ sample/test-cloud-app/app/mainwindow.h | 55 ++++++++ sample/test-cloud-app/app/ui_mainwindow.h | 94 +++++++++++++ 9 files changed, 538 insertions(+) create mode 100755 sample/test-cloud-app/app/app.pri create mode 100755 sample/test-cloud-app/app/app.pro create mode 100755 sample/test-cloud-app/app/images/AGL_HMI_Blue_Background_NoCar-01.png create mode 100755 sample/test-cloud-app/app/images/images.qrc create mode 100755 sample/test-cloud-app/app/main.cpp create mode 100755 sample/test-cloud-app/app/main.cpp.save create mode 100755 sample/test-cloud-app/app/mainwindow.cpp create mode 100755 sample/test-cloud-app/app/mainwindow.h create mode 100755 sample/test-cloud-app/app/ui_mainwindow.h (limited to 'sample/test-cloud-app/app') diff --git a/sample/test-cloud-app/app/app.pri b/sample/test-cloud-app/app/app.pri new file mode 100755 index 0000000..6d710e4 --- /dev/null +++ b/sample/test-cloud-app/app/app.pri @@ -0,0 +1,3 @@ +TEMPLATE = app +QMAKE_LFLAGS += "-Wl,--hash-style=gnu -Wl,--as-needed" +DESTDIR = $${OUT_PWD}/../package/root/bin diff --git a/sample/test-cloud-app/app/app.pro b/sample/test-cloud-app/app/app.pro new file mode 100755 index 0000000..9b72850 --- /dev/null +++ b/sample/test-cloud-app/app/app.pro @@ -0,0 +1,31 @@ +TARGET = testcloudapp +QT += core gui gui-private + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +DEFINES += QT_DEPRECATED_WARNINGS +DEFINES += APP_INSTANCE_NUM='\\"1\\"' + +SOURCES = main.cpp \ + mainwindow.cpp \ + +HEADERS += mainwindow.h \ + ui_mainwindow.h \ + +CONFIG += link_pkgconfig +PKGCONFIG += libcloudproxy qtappfw-core + +CONFIG(release, debug|release) { + QMAKE_POST_LINK = $(STRIP) --strip-unneeded $(TARGET) +} + +LIBS += -ljson-c -lafbwsc -lsystemd + +RESOURCES += \ + images/images.qrc + +include(app.pri) + +DISTFILES += \ + images/AGL_HMI_Blue_Background_NoCar-01.png + diff --git a/sample/test-cloud-app/app/images/AGL_HMI_Blue_Background_NoCar-01.png b/sample/test-cloud-app/app/images/AGL_HMI_Blue_Background_NoCar-01.png new file mode 100755 index 0000000..a76b140 Binary files /dev/null and b/sample/test-cloud-app/app/images/AGL_HMI_Blue_Background_NoCar-01.png differ diff --git a/sample/test-cloud-app/app/images/images.qrc b/sample/test-cloud-app/app/images/images.qrc new file mode 100755 index 0000000..78d9b77 --- /dev/null +++ b/sample/test-cloud-app/app/images/images.qrc @@ -0,0 +1,5 @@ + + + AGL_HMI_Blue_Background_NoCar-01.png + + diff --git a/sample/test-cloud-app/app/main.cpp b/sample/test-cloud-app/app/main.cpp new file mode 100755 index 0000000..6918e97 --- /dev/null +++ b/sample/test-cloud-app/app/main.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2020 MERA + * + * 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 +#include +#include +#include + +#include "mainwindow.h" +#include +#include + +#include "libcloudproxy.h" + +CloudProxyClient* g_cloudproxyclient{nullptr}; + + +int main(int argc, char *argv[]) +{ + QString graphic_role = QString("cloudapp") + QString(APP_INSTANCE_NUM); + + QApplication app(argc, argv); + app.setDesktopFileName(graphic_role); + QScopedPointer window; + + QCommandLineParser parser; + parser.addPositionalArgument("port", app.translate("main", "port for binding")); + parser.addPositionalArgument("secret", app.translate("main", "secret for binding")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + QStringList positionalArguments = parser.positionalArguments(); + + if (positionalArguments.length() == 2) + { + int port = positionalArguments.takeFirst().toInt(); + QString secret = positionalArguments.takeFirst(); + QUrl bindingAddress; + bindingAddress.setScheme(QStringLiteral("ws")); + bindingAddress.setHost(QStringLiteral("localhost")); + bindingAddress.setPort(port); + bindingAddress.setPath(QStringLiteral("/api")); + QUrlQuery query; + query.addQueryItem(QStringLiteral("token"), secret); + bindingAddress.setQuery(query); + + std::string token = secret.toStdString(); + window.reset(new MainWindow(1)); + + g_cloudproxyclient = new CloudProxyClient(); + g_cloudproxyclient->init(port, token.c_str()); + + static int i_confirm_good{0}, i_confirm_bad{0}, i_recv{0}; + g_cloudproxyclient->set_event_handler(CloudProxyClient::Event_SendMessageConfirmation, [&window](json_object* object){ + qDebug("CloudProxyClient::Event_SendMessageConfirmation: object ptr %p", object); + + const char* str = object ? json_object_to_json_string_ext(object, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY) : ""; + if (!str) + str = ""; + qDebug("Event_SendMessageConfirmation: %s", str); + + json_object *j_result; + if(!json_object_object_get_ex(object, "result", &j_result)) + { + qDebug("Can't read confirmation result"); + return; + } + + int result = (int)json_object_get_boolean(j_result); + + if (result) + ++i_confirm_good; + else + ++i_confirm_bad; + + window->updateStat(i_confirm_good, i_confirm_bad, i_recv, QVariant()); + qDebug("Application received confirmation result [good: %d, bad: %d]: %d", i_confirm_good, i_confirm_bad, result); + }); + g_cloudproxyclient->set_event_handler(CloudProxyClient::Event_ReceivedMessage, [&window](json_object* object){ + qDebug("CloudProxyClient::Event_ReceivedMessage: object ptr %p", object); + + const char* str = object ? json_object_to_json_string_ext(object, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY) : ""; + if (!str) + str = ""; + qDebug("Event_SendMessageConfirmation: %s", str); + + json_object *event_data; + const char* data_str{nullptr}; + if(!json_object_object_get_ex(object, "data", &event_data) || + (data_str = json_object_get_string(event_data)) == nullptr) + { + qDebug("Can't read event data"); + return; + } + + ++i_recv; + window->updateStat(i_confirm_good, i_confirm_bad, i_recv, QString(data_str)); + qDebug("Application received data [count: %d, good: %d, bad %d]: %s", i_recv, i_confirm_good, i_confirm_bad, data_str); + }); + + + window->show(); + } + + return app.exec(); +} diff --git a/sample/test-cloud-app/app/main.cpp.save b/sample/test-cloud-app/app/main.cpp.save new file mode 100755 index 0000000..8236ada --- /dev/null +++ b/sample/test-cloud-app/app/main.cpp.save @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2020 MERA + * + * 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 +#include +#include +#include + +#include "mainwindow.h" +#include +#include + +#include "cloudproxy-client/cloudproxyclient.h" + + +CloudProxyClient* g_cloudproxyclient{nullptr}; + + +int main(int argc, char *argv[]) +{ + QString graphic_role = QString("cloudapp") + QString(APP_INSTANCE_NUM); + + QApplication app(argc, argv); + app.setDesktopFileName(graphic_role); + QScopedPointer window; + + QCommandLineParser parser; + parser.addPositionalArgument("port", app.translate("main", "port for binding")); + parser.addPositionalArgument("secret", app.translate("main", "secret for binding")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + QStringList positionalArguments = parser.positionalArguments(); + + if (positionalArguments.length() == 2) + { + int port = positionalArguments.takeFirst().toInt(); + QString secret = positionalArguments.takeFirst(); + QUrl bindingAddress; + bindingAddress.setScheme(QStringLiteral("ws")); + bindingAddress.setHost(QStringLiteral("localhost")); + bindingAddress.setPort(port); + bindingAddress.setPath(QStringLiteral("/api")); + QUrlQuery query; + query.addQueryItem(QStringLiteral("token"), secret); + bindingAddress.setQuery(query); + std::string token = secret.toStdString(); + LibHomeScreen* hs = new LibHomeScreen(); + QLibWindowmanager* qwm = new QLibWindowmanager(); + + // WindowManager + if(qwm->init(port,secret) != 0){ + exit(EXIT_FAILURE); + } + AGLScreenInfo screenInfo(qwm->get_scale_factor()); + window.reset(new MainWindow(screenInfo.scale_factor())); + + // Request a surface as described in layers.json windowmanager’s file + if (qwm->requestSurface(graphic_role) != 0) { + exit(EXIT_FAILURE); + } + // Create an event callback against an event type. Here a lambda is called when SyncDraw event occurs + qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, &graphic_role](json_object *object) { + (void)object; + qDebug() << "Surface got syncDraw!"; + qwm->endDraw(graphic_role); + }); + + // HomeScreen + hs->init(port, token.c_str()); + // Set the event handler for Event_ShowWindow which will activate the surface for windowmanager + hs->set_event_handler(LibHomeScreen::Event_ShowWindow, [qwm, &graphic_role](json_object *object){ + (void)object; + qDebug("Surface %s got showWindow\n", graphic_role.toStdString().c_str()); + qwm->activateWindow(graphic_role); + }); + + g_cloudproxyclient = new CloudProxyClient(); + g_cloudproxyclient->init(port, token.c_str()); + + static int i_confirm_good{0}, i_confirm_bad{0}, i_recv{0}; + g_cloudproxyclient->set_event_handler(CloudProxyClient::Event_SendMessageConfirmation, [&window](json_object* object){ + qDebug("CloudProxyClient::Event_SendMessageConfirmation: object ptr %p", object); + + const char* str = object ? json_object_to_json_string_ext(object, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY) : ""; + if (!str) + str = ""; + qDebug("Event_SendMessageConfirmation: %s", str); + + json_object *j_result; + if(!json_object_object_get_ex(object, "result", &j_result)) + { + qDebug("Can't read confirmation result"); + return; + } + + int result = (int)json_object_get_boolean(j_result); + + if (result) + ++i_confirm_good; + else + ++i_confirm_bad; + + window->updateStat(i_confirm_good, i_confirm_bad, i_recv, QVariant()); + qDebug("Application received confirmation result [good: %d, bad: %d]: %d", i_confirm_good, i_confirm_bad, result); + }); + g_cloudproxyclient->set_event_handler(CloudProxyClient::Event_ReceivedMessage, [&window](json_object* object){ + qDebug("CloudProxyClient::Event_ReceivedMessage: object ptr %p", object); + + const char* str = object ? json_object_to_json_string_ext(object, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY) : ""; + if (!str) + str = ""; + qDebug("Event_SendMessageConfirmation: %s", str); + + json_object *event_data; + const char* data_str{nullptr}; + if(!json_object_object_get_ex(object, "data", &event_data) || + (data_str = json_object_get_string(event_data)) == nullptr) + { + qDebug("Can't read event data"); + return; + } + + ++i_recv; + window->updateStat(i_confirm_good, i_confirm_bad, i_recv, QString(data_str)); + qDebug("Application received data [count: %d, good: %d, bad %d]: %s", i_recv, i_confirm_good, i_confirm_bad, data_str); + }); + + + window->show(); + qwm->slotActivateWindow(); + } + + return app.exec(); +} diff --git a/sample/test-cloud-app/app/mainwindow.cpp b/sample/test-cloud-app/app/mainwindow.cpp new file mode 100755 index 0000000..355847c --- /dev/null +++ b/sample/test-cloud-app/app/mainwindow.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 MERA + * + * 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 "mainwindow.h" +#include "ui_mainwindow.h" +#include + +#include +#include + + +#include "libcloudproxy.h" +extern CloudProxyClient* g_cloudproxyclient; + +MainWindow::MainWindow(double scale_factor, QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(scale_factor, this); + + //AGL style + setWindowFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint); + this->setStyleSheet( + "background-image:url(:/images/AGL_HMI_Blue_Background_NoCar-01.png) 0 0 0 0 stretch stretch; background: transparent;" ); +} + +void MainWindow::updateStat(int confirm_good, int confirm_bad, int received, QVariant recvMsg) +{ + confirmGood = confirm_good; + confirmBad = confirm_bad; + receivedCount = received; + + if (recvMsg.isValid()) + lastReceivedMsg = recvMsg.toString(); + + updateStat(); +} + +void MainWindow::updateStat() +{ + QString str = QString::asprintf("Sent: OK=%d, NOK=%d\nConfirmed: OK=%d, NOK=%d\nReceived=%d\n\n", + sendCount, sendErrorCount, confirmGood, confirmBad, receivedCount); + str.append("Last sent message:\n"); + str.append(lastSentMsg); + str.append("\n\nLast received message:\n"); + str.append(lastReceivedMsg); + ui->statLabel->setText(str); + //QApplication::processEvents(); +} + +void MainWindow::sendMsgButtonClick() +{ + qDebug() << "MainWindow::sendMegButtonClick()"; + + std::string msg = std::string{"{\"app_key\": \"app_value_"} + std::to_string(sendCount + sendErrorCount) + "\"}"; + int res = g_cloudproxyclient->sendMessage(msg); + if (res == 0) + ++sendCount; + else + ++sendErrorCount; + + lastSentMsg = msg.c_str(); + qDebug() << "cloud sendMessage result: " << res; +} + + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/sample/test-cloud-app/app/mainwindow.h b/sample/test-cloud-app/app/mainwindow.h new file mode 100755 index 0000000..ae66729 --- /dev/null +++ b/sample/test-cloud-app/app/mainwindow.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 MERA + * + * 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 MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(double scale_factor, QWidget *parent = 0); + ~MainWindow(); + +public slots: + void updateStat(int confirm_good, int confirm_bad, int received, QVariant recvMsg); + +private slots: + void sendMsgButtonClick(); + void updateStat(); + +private: + Ui::MainWindow *ui; + int sendCount{0}; + int sendErrorCount{0}; + int confirmGood{0}; + int confirmBad{0}; + int receivedCount{0}; + QString lastSentMsg; + QString lastReceivedMsg; +}; + +#endif // MAINWINDOW_H diff --git a/sample/test-cloud-app/app/ui_mainwindow.h b/sample/test-cloud-app/app/ui_mainwindow.h new file mode 100755 index 0000000..3dac77e --- /dev/null +++ b/sample/test-cloud-app/app/ui_mainwindow.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 MERA + * + * 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 UI_MAINWINDOW_H +#define UI_MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Ui_MainWindow +{ +public: + QWidget *centralWidget{nullptr}; + QPushButton *sendMsgButton{nullptr}; + QLabel *appNameLabel{nullptr}; + QLabel *statLabel{nullptr}; + + void setupUi(double scale_factor, QMainWindow *MainWindow) + { + if (MainWindow->objectName().isEmpty()) + MainWindow->setObjectName(QString::fromUtf8("MainWindow")); + MainWindow->resize(1080*scale_factor, 1400*scale_factor); + centralWidget = new QWidget(MainWindow); + centralWidget->setObjectName(QString::fromUtf8("centralWidget")); + + //QString style("color: white; font-size: 24px"); + QString style("color: white"); + + sendMsgButton = new QPushButton(centralWidget); + sendMsgButton->setObjectName(QString::fromUtf8("sendMsgButton")); + sendMsgButton->setGeometry(QRect((540-242/2)*scale_factor, 100*scale_factor, 242*scale_factor, 64*scale_factor)); + sendMsgButton->setStyleSheet(style); + + appNameLabel = new QLabel(centralWidget); + appNameLabel->setObjectName(QString::fromUtf8("label")); + appNameLabel->setGeometry(QRect(40*scale_factor, 20*scale_factor, 1000*scale_factor, 32*scale_factor)); + appNameLabel->setStyleSheet(style); + + statLabel = new QLabel(centralWidget); + statLabel->setObjectName(QString::fromUtf8("label")); + statLabel->setGeometry(QRect(40*scale_factor, 180*scale_factor, 1000*scale_factor, 420*scale_factor)); + statLabel->setWordWrap(true); + statLabel->setAlignment(Qt::AlignTop); + statLabel->setStyleSheet(style); + + MainWindow->setCentralWidget(centralWidget); + + QObject::connect(sendMsgButton, SIGNAL(clicked()), MainWindow, SLOT(sendMsgButtonClick())); + + retranslateUi(MainWindow); + + QMetaObject::connectSlotsByName(MainWindow); + } // setupUi + + void retranslateUi(QMainWindow *MainWindow) + { + MainWindow->setWindowTitle(QApplication::translate("MainWindow", "MainWindow", nullptr)); + sendMsgButton->setText(QApplication::translate("MainWindow", "Send message", nullptr)); + QString name = QString("Test application ") + APP_INSTANCE_NUM; + appNameLabel->setText(QApplication::translate("MainWindow", name.toUtf8().constData(), nullptr)); + } // retranslateUi +}; + +namespace Ui { + class MainWindow: public Ui_MainWindow {}; +} // namespace Ui + +QT_END_NAMESPACE + +#endif // UI_MAINWINDOW_H -- cgit 1.2.3-korg