summaryrefslogtreecommitdiffstats
path: root/applauncher
diff options
context:
space:
mode:
Diffstat (limited to 'applauncher')
-rw-r--r--applauncher/AppLauncherClient.cpp41
-rw-r--r--applauncher/AppLauncherClient.h36
-rw-r--r--applauncher/AppLauncherGrpcClient.cpp113
-rw-r--r--applauncher/AppLauncherGrpcClient.h55
-rw-r--r--applauncher/meson.build56
-rw-r--r--applauncher/protos/applauncher.proto50
6 files changed, 351 insertions, 0 deletions
diff --git a/applauncher/AppLauncherClient.cpp b/applauncher/AppLauncherClient.cpp
new file mode 100644
index 0000000..bbbcef3
--- /dev/null
+++ b/applauncher/AppLauncherClient.cpp
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright (C) 2022 Konsulko Group
+ */
+
+#include <QDebug>
+
+#include "AppLauncherClient.h"
+#include "AppLauncherGrpcClient.h"
+
+AppLauncherClient::AppLauncherClient(QObject *parent) : QObject(parent)
+{
+ m_launcher = new AppLauncherGrpcClient(this);
+}
+
+AppLauncherClient::~AppLauncherClient()
+{
+ delete m_launcher;
+}
+
+bool AppLauncherClient::startApplication(const QString &id)
+{
+ if (m_launcher)
+ return m_launcher->StartApplication(id);
+
+ return false;
+}
+
+bool AppLauncherClient::listApplications(QList<QMap<QString, QString>> &list)
+{
+ if (!m_launcher) {
+ return false;
+ }
+
+ return m_launcher->ListApplications(list);
+}
+
+void AppLauncherClient::sendStatusEvent(const QString &id, const QString &status)
+{
+ emit appStatusEvent(id, status);
+}
diff --git a/applauncher/AppLauncherClient.h b/applauncher/AppLauncherClient.h
new file mode 100644
index 0000000..91723ab
--- /dev/null
+++ b/applauncher/AppLauncherClient.h
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright (C) 2022 Konsulko Group
+ */
+
+#ifndef APPLAUNCHER_CLIENT_H
+#define APPLAUNCHER_CLIENT_H
+
+#include <QObject>
+#include <QList>
+#include <QMap>
+
+class AppLauncherGrpcClient;
+
+class AppLauncherClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit AppLauncherClient(QObject *parent = Q_NULLPTR);
+ virtual ~AppLauncherClient();
+
+ Q_INVOKABLE bool startApplication(const QString &id);
+ Q_INVOKABLE bool listApplications(QList<QMap<QString, QString>> &list);
+
+public slots:
+ void sendStatusEvent(const QString &id, const QString &status);
+
+signals:
+ void appStatusEvent(const QString &id, const QString &status);
+
+private:
+ AppLauncherGrpcClient *m_launcher;
+};
+
+#endif // APPLAUNCHER_CLIENT_H
diff --git a/applauncher/AppLauncherGrpcClient.cpp b/applauncher/AppLauncherGrpcClient.cpp
new file mode 100644
index 0000000..a25b148
--- /dev/null
+++ b/applauncher/AppLauncherGrpcClient.cpp
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright (C) 2022 Konsulko Group
+ */
+
+#include <QDebug>
+#include "AppLauncherGrpcClient.h"
+#include "AppLauncherClient.h"
+
+using grpc::Channel;
+using grpc::ClientContext;
+using grpc::ClientReader;
+using grpc::Status;
+
+using automotivegradelinux::AppLauncher;
+using automotivegradelinux::StartRequest;
+using automotivegradelinux::StartResponse;
+using automotivegradelinux::ListRequest;
+using automotivegradelinux::ListResponse;
+using automotivegradelinux::AppInfo;
+using automotivegradelinux::StatusRequest;
+using automotivegradelinux::StatusResponse;
+using automotivegradelinux::AppStatus;
+
+
+void AppStatusEventReader::GetStatusEvents()
+{
+ ClientContext context;
+ StatusRequest request;
+ StatusResponse response;
+
+ std::unique_ptr<ClientReader<StatusResponse> > reader(stub_->GetStatusEvents(&context, request));
+ while (reader->Read(&response)) {
+ if (response.has_app()) {
+ AppStatus app_status = response.app();
+ emit statusUpdate(QString::fromStdString(app_status.id()),
+ QString::fromStdString(app_status.status()));
+ }
+ }
+ Status status = reader->Finish();
+ if (!status.ok()) {
+ qWarning() << "GetStatusEvents RPC failed";
+ }
+
+ emit finished();
+}
+
+AppLauncherGrpcClient::AppLauncherGrpcClient(QObject *parent) : QObject(parent)
+{
+ stub_ = AppLauncher::NewStub(grpc::CreateChannel("localhost:50052", grpc::InsecureChannelCredentials()));
+
+ // Create thread to read status events
+ AppStatusEventReader *reader = new AppStatusEventReader(stub_);
+ reader->moveToThread(&m_event_thread);
+ connect(&m_event_thread, &QThread::started, reader, &AppStatusEventReader::GetStatusEvents);
+ connect(reader, &AppStatusEventReader::finished, &m_event_thread, &QThread::quit);
+ // FIXME: Normally the thread finishing would be connected per the below
+ // to trigger cleaning up the object. That seems to trigger a crash
+ // for not entirely obvious reasons. It seems unrelated to the signal
+ // connection to AppLauncherClient, as not connecting does not prevent
+ // the crash; further investigation is required.
+ //connect(reader, &AppStatusEventReader::finished, reader, &AppStatusEventReader::deleteLater);
+ //connect(&m_event_thread, &QThread::finished, &m_event_thread, &QThread::deleteLater);
+
+ // To avoid having an intermediary slot+signal in this class, try
+ // casting parent to AppLauncherClient and connect directly to its
+ // slot. Callers should set parent to ensure this works as required.
+ if (parent) {
+ AppLauncherClient *launcher = qobject_cast<AppLauncherClient*>(parent);
+ if (launcher)
+ connect(reader,
+ &AppStatusEventReader::statusUpdate,
+ launcher,
+ &AppLauncherClient::sendStatusEvent);
+ }
+
+ // Start status event handling
+ m_event_thread.start();
+}
+
+bool AppLauncherGrpcClient::StartApplication(const QString &id)
+{
+ StartRequest request;
+ request.set_id(id.toStdString());
+
+ ClientContext context;
+ StartResponse response;
+ Status status = stub_->StartApplication(&context, request, &response);
+
+ return status.ok();
+}
+
+bool AppLauncherGrpcClient::ListApplications(QList<QMap<QString, QString>> &list)
+{
+ ListRequest request; // empty
+ ClientContext context;
+ ListResponse response;
+
+ Status status = stub_->ListApplications(&context, request, &response);
+ if (!status.ok())
+ return false;
+
+ for (int i = 0; i < response.apps_size(); i++) {
+ QMap<QString, QString> appinfo_map;
+ AppInfo appinfo = response.apps(i);
+ appinfo_map["id"] = QString::fromStdString(appinfo.id());
+ appinfo_map["name"] = QString::fromStdString(appinfo.name());
+ appinfo_map["icon_path"] = QString::fromStdString(appinfo.icon_path());
+ list.append(appinfo_map);
+ }
+
+ return true;
+}
diff --git a/applauncher/AppLauncherGrpcClient.h b/applauncher/AppLauncherGrpcClient.h
new file mode 100644
index 0000000..f9e1d0f
--- /dev/null
+++ b/applauncher/AppLauncherGrpcClient.h
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright (C) 2022 Konsulko Group
+ */
+
+#ifndef APPLAUNCHER_GRPC_CLIENT_H
+#define APPLAUNCHER_GRPC_CLIENT_H
+
+#include <QObject>
+#include <QList>
+#include <QMap>
+#include <QThread>
+#include <grpcpp/grpcpp.h>
+
+#include "applauncher.grpc.pb.h"
+
+using grpc::Channel;
+
+class AppStatusEventReader : public QObject
+{
+ Q_OBJECT
+public:
+ AppStatusEventReader(std::shared_ptr<automotivegradelinux::AppLauncher::Stub> &stub,
+ QObject *parent = Q_NULLPTR) : QObject(parent), stub_(stub) {}
+
+public slots:
+ void GetStatusEvents();
+
+signals:
+ void statusUpdate(const QString &id, const QString &status);
+ void finished();
+
+private:
+ std::shared_ptr<automotivegradelinux::AppLauncher::Stub> stub_;
+};
+
+class AppLauncherGrpcClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ AppLauncherGrpcClient(QObject *parent = Q_NULLPTR);
+
+ bool StartApplication(const QString &id);
+
+ bool ListApplications(QList<QMap<QString, QString>> &list);
+
+private:
+ std::shared_ptr<automotivegradelinux::AppLauncher::Stub> stub_;
+
+ QThread m_event_thread;
+
+};
+
+#endif // APPLAUNCHER_GRPC_CLIENT_H
diff --git a/applauncher/meson.build b/applauncher/meson.build
new file mode 100644
index 0000000..b36184a
--- /dev/null
+++ b/applauncher/meson.build
@@ -0,0 +1,56 @@
+cpp = meson.get_compiler('cpp')
+grpcpp_reflection_dep = cpp.find_library('grpc++_reflection')
+
+qt5_dep = dependency('qt5', modules: ['Qml'])
+applauncher_dep = [
+ qt5_dep,
+ dependency('protobuf'),
+ dependency('grpc'),
+ dependency('grpc++'),
+ grpcpp_reflection_dep,
+]
+
+protoc = find_program('protoc')
+grpc_cpp = find_program('grpc_cpp_plugin')
+
+protoc_gen = generator(protoc, \
+ output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'],
+ arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/protos',
+ '--cpp_out=@BUILD_DIR@',
+ '@INPUT@'])
+generated_protoc_sources = protoc_gen.process('protos/applauncher.proto')
+
+grpc_gen = generator(protoc, \
+ output : ['@BASENAME@.grpc.pb.cc', '@BASENAME@.grpc.pb.h'],
+ arguments : ['--proto_path=@CURRENT_SOURCE_DIR@/protos',
+ '--grpc_out=@BUILD_DIR@',
+ '--plugin=protoc-gen-grpc=' + grpc_cpp.path(),
+ '@INPUT@'])
+generated_grpc_sources = grpc_gen.process('protos/applauncher.proto')
+
+moc_files = qt5.compile_moc(headers : ['AppLauncherClient.h', 'AppLauncherGrpcClient.h'],
+ dependencies: qt5_dep)
+
+src = [
+ 'AppLauncherClient.cpp',
+ 'AppLauncherGrpcClient.cpp',
+ generated_protoc_sources,
+ generated_grpc_sources,
+ moc_files
+]
+lib = shared_library('qtappfw-applauncher',
+ sources: src,
+ version: '1.0.0',
+ soversion: '0',
+ dependencies: applauncher_dep,
+ install: true)
+
+install_headers('AppLauncherClient.h')
+
+pkg_mod = import('pkgconfig')
+pkg_mod.generate(libraries : lib,
+ version : '1.0',
+ name : 'libqtappfw-applauncher',
+ filebase : 'qtappfw-applauncher',
+ requires: 'Qt5Qml',
+ description : 'Library wrapping AGL AppLauncher API in Qt objects')
diff --git a/applauncher/protos/applauncher.proto b/applauncher/protos/applauncher.proto
new file mode 100644
index 0000000..0b8e0fc
--- /dev/null
+++ b/applauncher/protos/applauncher.proto
@@ -0,0 +1,50 @@
+syntax = "proto3";
+
+package automotivegradelinux;
+
+service AppLauncher {
+ rpc StartApplication(StartRequest) returns (StartResponse) {}
+ rpc ListApplications(ListRequest) returns (ListResponse) {}
+ rpc GetStatusEvents(StatusRequest) returns (stream StatusResponse) {}
+}
+
+message StartRequest {
+ string id = 1;
+}
+
+message StartResponse {
+ bool status = 1;
+ string message = 2;
+}
+
+message ListRequest {
+}
+
+message ListResponse {
+ repeated AppInfo apps = 1;
+}
+
+message AppInfo {
+ string id = 1;
+ string name = 2;
+ string icon_path = 3;
+}
+
+message StatusRequest {
+}
+
+message AppStatus {
+ string id = 1;
+ string status = 2;
+}
+
+// Future-proofing for e.g. potentially signaling a list refresh
+message LauncherStatus {
+}
+
+message StatusResponse {
+ oneof status {
+ AppStatus app = 1;
+ LauncherStatus launcher = 2;
+ }
+}