[gnome-software: 42/72] packagekit-refine-repos: Make refine asynchronous
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software: 42/72] packagekit-refine-repos: Make refine asynchronous
- Date: Wed, 15 Dec 2021 13:00:55 +0000 (UTC)
commit 68e083ff39c9ac7a59ce7b46e4ec46887e071e67
Author: Philip Withnall <pwithnall endlessos org>
Date: Fri Nov 5 17:27:55 2021 +0000
packagekit-refine-repos: Make refine asynchronous
The handling of `gs_packagekit_helper_cb()` and its data will be
reworked in a subsequent commit. It currently (temporarily,
deliberately) leaks the helper struct.
Signed-off-by: Philip Withnall <pwithnall endlessos org>
Helps: #1472
.../packagekit/gs-plugin-packagekit-refine-repos.c | 200 +++++++++++++++++----
1 file changed, 170 insertions(+), 30 deletions(-)
---
diff --git a/plugins/packagekit/gs-plugin-packagekit-refine-repos.c
b/plugins/packagekit/gs-plugin-packagekit-refine-repos.c
index e1bc35b9f..5dd5032a4 100644
--- a/plugins/packagekit/gs-plugin-packagekit-refine-repos.c
+++ b/plugins/packagekit/gs-plugin-packagekit-refine-repos.c
@@ -69,22 +69,127 @@ gs_plugin_packagekit_refine_repos_finalize (GObject *object)
G_OBJECT_CLASS (gs_plugin_packagekit_refine_repos_parent_class)->finalize (object);
}
-gboolean
-gs_plugin_refine (GsPlugin *plugin,
- GsAppList *list,
- GsPluginRefineFlags flags,
- GCancellable *cancellable,
- GError **error)
+typedef struct {
+ /* Track pending operations. */
+ guint n_pending_operations;
+ gboolean completed;
+ GError *error; /* (nullable) (owned) */
+} RefineData;
+
+static void
+refine_data_free (RefineData *data)
+{
+ g_assert (data->n_pending_operations == 0);
+ g_assert (data->completed);
+
+ g_clear_error (&data->error);
+ g_free (data);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (RefineData, refine_data_free)
+
+static GTask *
+refine_task_add_operation (GTask *refine_task)
+{
+ RefineData *data = g_task_get_task_data (refine_task);
+
+ g_assert (!data->completed);
+ data->n_pending_operations++;
+
+ return g_object_ref (refine_task);
+}
+
+static void
+refine_task_complete_operation (GTask *refine_task)
+{
+ RefineData *data = g_task_get_task_data (refine_task);
+
+ g_assert (data->n_pending_operations > 0);
+ data->n_pending_operations--;
+
+ /* Have all operations completed? */
+ if (data->n_pending_operations == 0) {
+ g_assert (!data->completed);
+ data->completed = TRUE;
+
+ if (data->error != NULL)
+ g_task_return_error (refine_task, g_steal_pointer (&data->error));
+ else
+ g_task_return_boolean (refine_task, TRUE);
+ }
+}
+
+static void
+refine_task_complete_operation_with_error (GTask *refine_task,
+ GError *error /* (transfer full) */)
+{
+ RefineData *data = g_task_get_task_data (refine_task);
+ g_autoptr(GError) owned_error = g_steal_pointer (&error);
+
+ /* Multiple operations might fail. Just take the first error. */
+ if (data->error == NULL)
+ data->error = g_steal_pointer (&owned_error);
+
+ refine_task_complete_operation (refine_task);
+}
+
+typedef struct {
+ GTask *refine_task; /* (owned) (not nullable) */
+ GsApp *app; /* (owned) (not nullable) */
+ gchar *filename; /* (owned) (not nullable) */
+} SearchFilesData;
+
+static void
+search_files_data_free (SearchFilesData *data)
+{
+ g_free (data->filename);
+ g_clear_object (&data->app);
+ g_clear_object (&data->refine_task);
+ g_free (data);
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SearchFilesData, search_files_data_free)
+
+static SearchFilesData *
+search_files_data_new_operation (GTask *refine_task,
+ GsApp *app,
+ const gchar *filename)
+{
+ g_autoptr(SearchFilesData) data = g_new0 (SearchFilesData, 1);
+ data->refine_task = refine_task_add_operation (refine_task);
+ data->app = g_object_ref (app);
+ data->filename = g_strdup (filename);
+
+ return g_steal_pointer (&data);
+}
+
+static void search_files_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data);
+
+static void
+gs_plugin_packagekit_refine_repos_refine_async (GsPlugin *plugin,
+ GsAppList *list,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GsPluginPackagekitRefineRepos *self = GS_PLUGIN_PACKAGEKIT_REFINE_REPOS (plugin);
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(RefineData) data = NULL;
+
+ task = g_task_new (plugin, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gs_plugin_packagekit_refine_repos_refine_async);
+ data = g_new0 (RefineData, 1);
+ data->n_pending_operations = 1; /* to prevent the task being completed before all operations have
been started */
+ g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) refine_data_free);
for (guint i = 0; i < gs_app_list_length (list); i++) {
GsApp *app = gs_app_list_index (list, i);
const gchar *filename;
const gchar *to_array[] = { NULL, NULL };
g_autoptr(GsPackagekitHelper) helper = gs_packagekit_helper_new (plugin);
- g_autoptr(PkResults) results = NULL;
- g_autoptr(GPtrArray) packages = NULL;
if (gs_app_has_quirk (app, GS_APP_QUIRK_IS_WILDCARD))
continue;
@@ -101,40 +206,75 @@ gs_plugin_refine (GsPlugin *plugin,
gs_packagekit_helper_add_app (helper, app);
g_mutex_lock (&self->client_mutex);
pk_client_set_interactive (self->client, gs_plugin_has_flags (plugin,
GS_PLUGIN_FLAGS_INTERACTIVE));
- results = pk_client_search_files (self->client,
- pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1),
- (gchar **) to_array,
- cancellable,
- gs_packagekit_helper_cb, helper,
- error);
+ pk_client_search_files_async (self->client,
+ pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED, -1),
+ (gchar **) to_array,
+ cancellable,
+ /* TODO: @helper is leaked here; this will be reworked in a
subsequent commit */
+ gs_packagekit_helper_cb, g_object_ref (helper),
+ search_files_cb,
+ search_files_data_new_operation (task, app, filename));
g_mutex_unlock (&self->client_mutex);
- if (!gs_plugin_packagekit_results_valid (results, error)) {
- g_prefix_error (error, "failed to search file %s: ", filename);
- return FALSE;
- }
-
- /* get results */
- packages = pk_results_get_package_array (results);
- if (packages->len == 1) {
- PkPackage *package = g_ptr_array_index (packages, 0);
- gs_app_add_source_id (app, pk_package_get_id (package));
- } else {
- g_debug ("failed to find one package for repo %s, %s, [%u]",
- gs_app_get_id (app), filename, packages->len);
- }
}
- /* success */
- return TRUE;
+ /* Mark the operation to set up all the other operations as completed.
+ * The @refine_task will now be completed once all the async operations
+ * have completed, and the task callback invoked. */
+ refine_task_complete_operation (task);
+}
+
+static void
+search_files_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ PkClient *client = PK_CLIENT (source_object);
+ g_autoptr(SearchFilesData) search_files_data = g_steal_pointer (&user_data);
+ GTask *refine_task = search_files_data->refine_task;
+ g_autoptr(PkResults) results = NULL;
+ g_autoptr(GPtrArray) packages = NULL;
+ g_autoptr(GError) local_error = NULL;
+
+ results = pk_client_generic_finish (client, result, &local_error);
+
+ if (!gs_plugin_packagekit_results_valid (results, &local_error)) {
+ g_prefix_error (&local_error, "failed to search file %s: ", search_files_data->filename);
+ refine_task_complete_operation_with_error (refine_task, g_steal_pointer (&local_error));
+ return;
+ }
+
+ /* get results */
+ packages = pk_results_get_package_array (results);
+ if (packages->len == 1) {
+ PkPackage *package = g_ptr_array_index (packages, 0);
+ gs_app_add_source_id (search_files_data->app, pk_package_get_id (package));
+ } else {
+ g_debug ("failed to find one package for repo %s, %s, [%u]",
+ gs_app_get_id (search_files_data->app), search_files_data->filename, packages->len);
+ }
+
+ refine_task_complete_operation (refine_task);
+}
+
+static gboolean
+gs_plugin_packagekit_refine_repos_refine_finish (GsPlugin *plugin,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
}
static void
gs_plugin_packagekit_refine_repos_class_init (GsPluginPackagekitRefineReposClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GsPluginClass *plugin_class = GS_PLUGIN_CLASS (klass);
object_class->dispose = gs_plugin_packagekit_refine_repos_dispose;
object_class->finalize = gs_plugin_packagekit_refine_repos_finalize;
+
+ plugin_class->refine_async = gs_plugin_packagekit_refine_repos_refine_async;
+ plugin_class->refine_finish = gs_plugin_packagekit_refine_repos_refine_finish;
}
GType
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]