aboutsummaryrefslogtreecommitdiffstats
path: root/src/AppLauncherImpl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/AppLauncherImpl.cc')
-rw-r--r--src/AppLauncherImpl.cc137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/AppLauncherImpl.cc b/src/AppLauncherImpl.cc
new file mode 100644
index 0000000..d691120
--- /dev/null
+++ b/src/AppLauncherImpl.cc
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright (C) 2022 Konsulko Group
+ */
+
+#include <AppLauncherImpl.h>
+#include <systemd_manager.h>
+
+using grpc::StatusCode;
+using automotivegradelinux::AppStatus;
+
+
+AppLauncherImpl::AppLauncherImpl(SystemdManager *manager) :
+ m_manager(manager)
+{
+ systemd_manager_connect_callbacks(m_manager,
+ G_CALLBACK(started_cb),
+ G_CALLBACK(terminated_cb),
+ this);
+}
+
+Status AppLauncherImpl::StartApplication(ServerContext* context,
+ const StartRequest* request,
+ StartResponse* response)
+{
+ if (!m_manager)
+ return Status(StatusCode::INTERNAL, "Initialization failed");
+
+ // Search the apps list for the given app-id
+ std::string app_id = request->id();
+ auto dbus_launcher_info = systemd_manager_get_app_info(m_manager, app_id.c_str());
+ if (!dbus_launcher_info) {
+ std::string error("Unknown application '");
+ error += app_id;
+ error += "'";
+ return Status(StatusCode::INVALID_ARGUMENT, error);
+ }
+
+ gboolean status = systemd_manager_start_app(m_manager, dbus_launcher_info);
+ response->set_status(status);
+ if (!status) {
+ // Maybe just return StatusCode::NOT_FOUND instead?
+ std::string error("Failed to start application '");
+ error += app_id;
+ error += "'";
+ response->set_message(error);
+ }
+
+ return Status::OK;
+}
+
+Status AppLauncherImpl::ListApplications(ServerContext* context,
+ const ListRequest* request,
+ ListResponse* response)
+{
+ if (!m_manager)
+ return Status(StatusCode::INTERNAL, "Initialization failed");
+
+ GList *apps = systemd_manager_get_app_list(m_manager);
+ if (!apps)
+ return Status::OK; // Perhaps return failure here?
+
+ guint len = g_list_length(apps);
+ for (guint i = 0; i < len; i++) {
+ struct _AppInfo *app_info = (struct _AppInfo*) g_list_nth_data(apps, i);
+ auto info = response->add_apps();
+ info->set_id(app_info_get_app_id(app_info));
+ info->set_name(app_info_get_name(app_info));
+ info->set_icon_path(app_info_get_icon_path(app_info));
+ }
+
+ return Status::OK;
+}
+
+Status AppLauncherImpl::GetStatusEvents(ServerContext* context,
+ const StatusRequest* request,
+ ServerWriter<StatusResponse>* writer)
+{
+
+ // Save client information
+ m_clients_mutex.lock();
+ m_clients.push_back(std::pair(context, writer));
+ m_clients_mutex.unlock();
+
+ // For now block until client disconnect / server shutdown
+ // A switch to the async or callback server APIs might be more elegant than
+ // holding the thread like this, and may be worth investigating at some point.
+ std::unique_lock lock(m_done_mutex);
+ m_done_cv.wait(lock, [context, this]{ return (context->IsCancelled() || m_done); });
+
+ return Status::OK;
+}
+
+
+void AppLauncherImpl::SendStatus(std::string id, std::string status)
+{
+ const std::lock_guard<std::mutex> lock(m_clients_mutex);
+
+ if (m_clients.empty())
+ return;
+
+ StatusResponse response;
+ auto app_status = response.mutable_app();
+ app_status->set_id(id);
+ app_status->set_status(status);
+
+ auto it = m_clients.begin();
+ while (it != m_clients.end()) {
+ if (it->first->IsCancelled()) {
+ // Client has gone away, remove from list
+ std::cout << "Removing cancelled RPC client!" << std::endl;
+ it = m_clients.erase(it);
+
+ // We're not exiting, but wake up blocked client RPC handlers so
+ // the canceled one will clean exit.
+ // Note that in practice this means the client RPC handler thread
+ // sticks around until the next status event is sent.
+ m_done_cv.notify_all();
+
+ continue;
+ } else {
+ it->second->Write(response);
+ ++it;
+ }
+ }
+}
+
+void AppLauncherImpl::HandleAppStarted(std::string id)
+{
+ SendStatus(id, "started");
+}
+
+void AppLauncherImpl::HandleAppTerminated(std::string id)
+{
+ SendStatus(id, "terminated");
+}
+