Skip to content

Commit 51ba753

Browse files
authored
Merge pull request #209 from toyota-connected/flatpak/sync-installation
flatpak: Track transactions operations and serialize to flutter channels
2 parents 6580228 + ee27f6a commit 51ba753

5 files changed

Lines changed: 349 additions & 32 deletions

File tree

plugins/flatpak/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ add_library(plugin_flatpak STATIC
3232
portals/portal_proxy.cc
3333
portals/access_portal/access_portal.cc
3434
portals/access_portal/access_portal.h
35+
operation_tracker.cc
36+
operation_tracker.h
3537
)
3638
target_include_directories(plugin_flatpak PRIVATE include)
3739
target_compile_options(plugin_flatpak PRIVATE

plugins/flatpak/flatpak_shim.cc

Lines changed: 83 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ void FlatpakShim::ApplicationInstall(
964964

965965
spdlog::info("[FlatpakPlugin] Starting TWO-PHASE installation for: {}", id);
966966

967+
operation_tracker_->TrackOperationStart(id, "install");
967968
FlatpakTransaction* transaction =
968969
flatpak_transaction_new_for_installation(installation, nullptr, &error);
969970

@@ -1055,7 +1056,7 @@ void FlatpakShim::ApplicationInstall(
10551056

10561057
// run transaction in a detached thread
10571058
std::thread([self, transaction_raw, callback, ref_name, remote_name,
1058-
strand_ptr = strand_, installation_raw, found_ref_raw]() {
1059+
strand_ptr = strand_, installation_raw, found_ref_raw, id]() {
10591060
pthread_setname_np(pthread_self(), "flatpak-install");
10601061

10611062
GError* error = nullptr;
@@ -1077,7 +1078,9 @@ void FlatpakShim::ApplicationInstall(
10771078
if (!success) {
10781079
spdlog::error("[FlatpakPlugin] Phase 1 (dependencies) failed");
10791080
asio::post(*strand_ptr, [self, callback, err_msg, transaction_raw,
1080-
found_ref_raw, installation_raw]() {
1081+
found_ref_raw, installation_raw, id]() {
1082+
self->operation_tracker_->SendOperationFinish(id, "install", false);
1083+
10811084
callback(ErrorOr<bool>(FlutterError(
10821085
"INSTALL_FAILED", "Dependency installation failed: " + err_msg)));
10831086
g_object_unref(transaction_raw);
@@ -1208,7 +1211,8 @@ void FlatpakShim::ApplicationInstall(
12081211

12091212
if (!phase2_success) {
12101213
asio::post(*strand_ptr, [self, callback, phase2_err_msg, transaction_raw,
1211-
found_ref_raw, installation_raw]() {
1214+
found_ref_raw, installation_raw, id]() {
1215+
self->operation_tracker_->SendOperationFinish(id, "install", false);
12121216
callback(ErrorOr<bool>(FlutterError(
12131217
"INSTALL_FAILED", "App installation failed: " + phase2_err_msg)));
12141218
g_object_unref(transaction_raw);
@@ -1247,17 +1251,19 @@ void FlatpakShim::ApplicationInstall(
12471251
}
12481252

12491253
asio::post(*strand_ptr, [self, callback, verified, ref_name,
1250-
transaction_raw, found_ref_raw,
1251-
installation_raw]() {
1254+
transaction_raw, found_ref_raw, installation_raw,
1255+
id]() {
12521256
if (verified) {
12531257
spdlog::info(
12541258
"[FlatpakPlugin] Application '{}' successfully installed and "
12551259
"verified",
12561260
ref_name);
1261+
self->operation_tracker_->SendOperationFinish(id, "install", true);
12571262
callback(ErrorOr<bool>(true));
12581263
} else {
12591264
spdlog::error(
12601265
"[FlatpakPlugin] Installation completed but verification failed");
1266+
self->operation_tracker_->SendOperationFinish(id, "install", false);
12611267
callback(ErrorOr<bool>(
12621268
FlutterError("INSTALL_VERIFICATION_FAILED",
12631269
"Installation completed but app not found")));
@@ -3981,38 +3987,72 @@ void FlatpakShim::OnOperationComplete(FlatpakTransaction* /* transaction */,
39813987
const char* ref = flatpak_transaction_operation_get_ref(operation);
39823988
auto type = flatpak_transaction_operation_get_operation_type(operation);
39833989

3984-
std::string type_str =
3985-
(type == FLATPAK_TRANSACTION_OPERATION_INSTALL) ? "install" : "other";
3990+
std::string type_str;
3991+
switch (type) {
3992+
case FLATPAK_TRANSACTION_OPERATION_INSTALL:
3993+
type_str = "install";
3994+
break;
3995+
case FLATPAK_TRANSACTION_OPERATION_UPDATE:
3996+
type_str = "update";
3997+
break;
3998+
case FLATPAK_TRANSACTION_OPERATION_UNINSTALL:
3999+
type_str = "uninstall";
4000+
break;
4001+
default:
4002+
type_str = "other";
4003+
break;
4004+
}
4005+
4006+
std::string ref_str = ref ? std::string(ref) : std::string("");
39864007

39874008
if (ref) {
39884009
spdlog::info(
39894010
"[FlatpakPlugin] Operation completed: {} {} (result: {})", type_str,
3990-
std::string(ref),
4011+
ref_str,
39914012
result == FLATPAK_TYPE_TRANSACTION_RESULT ? "SUCCESS" : "FAILED");
39924013
}
39934014

4015+
std::string app_id;
4016+
auto active_ops = handler->operation_tracker_->GetActiveOperations();
4017+
4018+
for (const auto& [id, op_info] : active_ops) {
4019+
if (ref_str.find(id) != std::string::npos || op_info.op_type == type_str) {
4020+
app_id = id;
4021+
handler->operation_tracker_->TrackOperationComplete(app_id, ref_str);
4022+
break;
4023+
}
4024+
}
4025+
39944026
if (handler->strand_) {
3995-
asio::post(
3996-
*handler->strand_,
3997-
[handler, ref = ref ? std::string(ref) : std::string(""),
3998-
commit = commit ? std::string(commit) : std::string(""), result]() {
3999-
try {
4000-
flutter::EncodableMap OperationCompleteMap;
4001-
OperationCompleteMap[flutter::EncodableValue("type")] =
4002-
flutter::EncodableValue("operation_complete");
4003-
OperationCompleteMap[flutter::EncodableValue("operation_ref")] =
4004-
flutter::EncodableValue(ref);
4005-
OperationCompleteMap[flutter::EncodableValue("commit")] =
4006-
flutter::EncodableValue(commit);
4007-
OperationCompleteMap[flutter::EncodableValue("success")] =
4008-
flutter::EncodableValue(static_cast<int32_t>(result));
4009-
4010-
handler->SendTransactionEvent(OperationCompleteMap);
4011-
} catch (const std::exception& e) {
4012-
spdlog::error("[FlatpakPlugin] Error sending complete event: {}",
4013-
e.what());
4014-
}
4015-
});
4027+
asio::post(*handler->strand_, [handler, ref_str,
4028+
commit = commit ? std::string(commit)
4029+
: std::string(""),
4030+
result, type_str, app_id]() {
4031+
try {
4032+
flutter::EncodableMap OperationCompleteMap;
4033+
OperationCompleteMap[flutter::EncodableValue("type")] =
4034+
flutter::EncodableValue("operation_complete");
4035+
OperationCompleteMap[flutter::EncodableValue("operation_ref")] =
4036+
flutter::EncodableValue(ref_str);
4037+
OperationCompleteMap[flutter::EncodableValue("commit")] =
4038+
flutter::EncodableValue(commit);
4039+
OperationCompleteMap[flutter::EncodableValue("success")] =
4040+
flutter::EncodableValue(static_cast<int32_t>(result));
4041+
OperationCompleteMap[flutter::EncodableValue("operation_type")] =
4042+
flutter::EncodableValue(type_str);
4043+
4044+
// Determine if this is the main app
4045+
bool is_main_app = ref_str.find("app/") == 0 && !app_id.empty() &&
4046+
ref_str.find(app_id) != std::string::npos;
4047+
OperationCompleteMap[flutter::EncodableValue("is_main_app")] =
4048+
flutter::EncodableValue(is_main_app);
4049+
4050+
handler->SendTransactionEvent(OperationCompleteMap);
4051+
} catch (const std::exception& e) {
4052+
spdlog::error("[FlatpakPlugin] Error sending complete event: {}",
4053+
e.what());
4054+
}
4055+
});
40164056
}
40174057
}
40184058

@@ -4067,6 +4107,7 @@ gboolean FlatpakShim::OnTransactionReady(FlatpakTransaction* transaction,
40674107

40684108
spdlog::info("[FlatpakPlugin] Total operations to perform: {}", total_ops);
40694109

4110+
std::string app_id;
40704111
flutter::EncodableList ops_list;
40714112
for (GList* l = operations; l != nullptr; l = l->next) {
40724113
auto* op = static_cast<FlatpakTransactionOperation*>(l->data);
@@ -4099,6 +4140,13 @@ gboolean FlatpakShim::OnTransactionReady(FlatpakTransaction* transaction,
40994140
std::string kind = "unknown";
41004141
if (ref_str.find("app/") == 0) {
41014142
kind = "app";
4143+
4144+
// extract app to pass
4145+
size_t first_slash = ref_str.find('/') + 1;
4146+
size_t second_slash = ref_str.find('/', first_slash);
4147+
if (second_slash != std::string::npos) {
4148+
app_id = ref_str.substr(first_slash, second_slash - first_slash);
4149+
}
41024150
} else if (ref_str.find("runtime/") == 0) {
41034151
kind = "runtime";
41044152
}
@@ -4111,8 +4159,11 @@ gboolean FlatpakShim::OnTransactionReady(FlatpakTransaction* transaction,
41114159
ops_list.emplace_back(op_map);
41124160
}
41134161

4162+
if (app_id.empty()) {
4163+
handler->operation_tracker_->UpdateTotalOperations(app_id, total_ops);
4164+
}
41144165
if (handler->strand_) {
4115-
asio::post(*handler->strand_, [handler, total_ops,
4166+
asio::post(*handler->strand_, [handler, app_id, total_ops,
41164167
ops_list = std::move(ops_list)]() {
41174168
try {
41184169
flutter::EncodableMap ready_event;
@@ -4122,7 +4173,8 @@ gboolean FlatpakShim::OnTransactionReady(FlatpakTransaction* transaction,
41224173
flutter::EncodableValue(total_ops);
41234174
ready_event[flutter::EncodableValue("operations")] =
41244175
flutter::EncodableValue(ops_list);
4125-
4176+
ready_event[flutter::EncodableValue("main_app_id")] =
4177+
flutter::EncodableValue(app_id);
41264178
handler->SendTransactionEvent(ready_event);
41274179
} catch (const std::exception& e) {
41284180
spdlog::error("[FlatpakPlugin] Error sending ready event: {}",

plugins/flatpak/flatpak_shim.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@
3333
#include "asio/steady_timer.hpp"
3434
#include "component.h"
3535
#include "messages.g.h"
36+
#include "operation_tracker.h"
3637
#include "plugins/flatpak/portals/portal_manager.h"
3738
#include "portals/access_portal/access_portal.h"
3839

3940
namespace flatpak_plugin {
4041
class FlatpakPlugin;
42+
class OperationTracker;
4143

4244
/**
4345
* \brief A utility class providing various helper functions for interacting
@@ -50,7 +52,15 @@ struct FlatpakShim : std::enable_shared_from_this<FlatpakShim> {
5052
explicit FlatpakShim(FlatpakPlugin* plugin = nullptr,
5153
flutter::BinaryMessenger* messenger = nullptr,
5254
asio::io_context::strand* strand = nullptr)
53-
: plugin_(plugin), messenger_(messenger), strand_(strand) {}
55+
: plugin_(plugin), messenger_(messenger), strand_(strand) {
56+
if (strand_) {
57+
operation_tracker_ = std::make_unique<OperationTracker>(
58+
strand_->context(), [this](const flutter::EncodableMap& event) {
59+
this->SendTransactionEvent(
60+
const_cast<flutter::EncodableMap&>(event));
61+
});
62+
}
63+
}
5464

5565
~FlatpakShim() {
5666
plugin_ = nullptr;
@@ -463,6 +473,8 @@ struct FlatpakShim : std::enable_shared_from_this<FlatpakShim> {
463473
flutter::BinaryMessenger* messenger_;
464474
asio::io_context::strand* strand_;
465475

476+
std::unique_ptr<OperationTracker> operation_tracker_;
477+
466478
// Event channel for streaming transaction progress to Flutter
467479
std::unique_ptr<flutter::EventChannel<flutter::EncodableValue>>
468480
event_channel_;

0 commit comments

Comments
 (0)