From f8d65da606cc460ebac5f273b754e8885dc91433 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 19 Jan 2010 10:42:11 -0600 Subject: Adding an object to start tracking the lru of the app indicators --- src/application-service-lru-file.c | 56 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/application-service-lru-file.c (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c new file mode 100644 index 0000000..3cbb1dc --- /dev/null +++ b/src/application-service-lru-file.c @@ -0,0 +1,56 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "application-service-lru-file.h" + +typedef struct _AppLruFilePrivate AppLruFilePrivate; +struct _AppLruFilePrivate { + gint temp; +}; + +#define APP_LRU_FILE_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_LRU_FILE_TYPE, AppLruFilePrivate)) + +static void app_lru_file_class_init (AppLruFileClass *klass); +static void app_lru_file_init (AppLruFile *self); +static void app_lru_file_dispose (GObject *object); +static void app_lru_file_finalize (GObject *object); + +G_DEFINE_TYPE (AppLruFile, app_lru_file, G_TYPE_OBJECT); + +static void +app_lru_file_class_init (AppLruFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (AppLruFilePrivate)); + + object_class->dispose = app_lru_file_dispose; + object_class->finalize = app_lru_file_finalize; + + return; +} + +static void +app_lru_file_init (AppLruFile *self) +{ + + return; +} + +static void +app_lru_file_dispose (GObject *object) +{ + + G_OBJECT_CLASS (app_lru_file_parent_class)->dispose (object); + return; +} + +static void +app_lru_file_finalize (GObject *object) +{ + + G_OBJECT_CLASS (app_lru_file_parent_class)->finalize (object); + return; +} -- cgit v1.2.3 From 2f82ed57b751145449506164888281b57819abcc Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Tue, 19 Jan 2010 17:01:57 -0600 Subject: Adding some API to our LRU file --- src/application-service-lru-file.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index 3cbb1dc..47cfab9 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -54,3 +54,36 @@ app_lru_file_finalize (GObject *object) G_OBJECT_CLASS (app_lru_file_parent_class)->finalize (object); return; } + +/* API */ + +/* Simple helper to create a new object */ +AppLruFile * +app_lru_file_new (void) +{ + return APP_LRU_FILE(g_object_new(APP_LRU_FILE_TYPE, NULL)); +} + +/* This updates the timestamp for a particular + entry in the database. It also queues up a + write out of the database. But that'll happen + later. */ +void +app_lru_file_touch (AppLruFile * lrufile, const gchar * id, const gchar * category) +{ + g_return_if_fail(IS_APP_LRU_FILE(lrufile)); + g_return_if_fail(id != NULL && id[0] != '\0'); + g_return_if_fail(category != NULL && category[0] != '\0'); + + return; +} + +/* Used to sort or compare different applications. */ +gint +app_lru_file_sort (AppLruFile * lrufile, const gchar * id_a, const gchar * id_b) +{ + g_return_val_if_fail(IS_APP_LRU_FILE(lrufile), -1); + + + return 0; +} -- cgit v1.2.3 From c663b234f90d1b6b5c5eea53d309d5295342b1e0 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 11:14:21 -0600 Subject: Allocating memory and objects in the lur world --- src/application-service-lru-file.c | 69 +++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index 47cfab9..a041453 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -6,7 +6,18 @@ typedef struct _AppLruFilePrivate AppLruFilePrivate; struct _AppLruFilePrivate { - gint temp; + GHashTable * apps; + gboolean dirty; + guint timer; + gchar * filename; +}; + +typedef struct _AppData AppData; +struct _AppData { + gchar * id; + gchar * category; + GTimeVal last_touched; + GTimeVal first_touched; }; #define APP_LRU_FILE_GET_PRIVATE(o) \ @@ -16,9 +27,12 @@ static void app_lru_file_class_init (AppLruFileClass *klass); static void app_lru_file_init (AppLruFile *self); static void app_lru_file_dispose (GObject *object); static void app_lru_file_finalize (GObject *object); +static void app_data_free (gpointer data); +static gboolean load_from_file (gpointer data); G_DEFINE_TYPE (AppLruFile, app_lru_file, G_TYPE_OBJECT); +/* Set up the class variable stuff */ static void app_lru_file_class_init (AppLruFileClass *klass) { @@ -32,29 +46,82 @@ app_lru_file_class_init (AppLruFileClass *klass) return; } +/* Set all the data of the per-instance variables */ static void app_lru_file_init (AppLruFile *self) { + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(self); + + /* Default values */ + priv->apps = NULL; + priv->dirty = FALSE; + priv->timer = 0; + priv->filename = NULL; + + /* Now let's build some stuff */ + priv->apps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, app_data_free); + priv->filename = g_build_filename(g_get_user_config_dir(), "indicators", "application", "lru-file.json", NULL); + + /* No reason to delay other stuff for this, we'll + merge any values that get touched. */ + g_idle_add(load_from_file, self); return; } +/* Get rid of objects and other big things */ static void app_lru_file_dispose (GObject *object) { + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(object); + + if (priv->timer != 0) { + g_source_remove(priv->timer); + priv->timer = 0; + } + + if (priv->apps != NULL) { + /* Cleans up the keys and entries itself */ + g_hash_table_destroy(priv->apps); + priv->apps = NULL; + } G_OBJECT_CLASS (app_lru_file_parent_class)->dispose (object); return; } +/* Deallocate memory */ static void app_lru_file_finalize (GObject *object) { + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(object); + + if (priv->filename != NULL) { + g_free(priv->filename); + priv->filename = NULL; + } G_OBJECT_CLASS (app_lru_file_parent_class)->finalize (object); return; } +/* Takes an AppData structure and free's the + memory from it. */ +static void +app_data_free (gpointer data) +{ + + return; +} + +/* Loads all of the data out of a json file */ +static gboolean +load_from_file (gpointer data) +{ + + return FALSE; +} + /* API */ /* Simple helper to create a new object */ -- cgit v1.2.3 From 064fd75a5fe489e03bba5b99ed170401d2fa1def Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 11:45:13 -0600 Subject: Fleshing out touching. --- src/application-service-lru-file.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index a041453..45fe9db 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -14,7 +14,6 @@ struct _AppLruFilePrivate { typedef struct _AppData AppData; struct _AppData { - gchar * id; gchar * category; GTimeVal last_touched; GTimeVal first_touched; @@ -110,6 +109,13 @@ app_lru_file_finalize (GObject *object) static void app_data_free (gpointer data) { + AppData * appdata = (AppData *)data; + + if (appdata->category != NULL) { + g_free(appdata->category); + } + + g_free(appdata); return; } @@ -142,6 +148,26 @@ app_lru_file_touch (AppLruFile * lrufile, const gchar * id, const gchar * catego g_return_if_fail(id != NULL && id[0] != '\0'); g_return_if_fail(category != NULL && category[0] != '\0'); + AppData * appdata = NULL; + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(lrufile); + gpointer data = g_hash_table_lookup(priv->apps, id); + + if (data == NULL) { + /* Oh, we don't have one, let's build it and put it + into the hash table ourselves */ + appdata = g_new0(AppData, 1); + + appdata->category = g_strdup(category); + g_get_current_time(&(appdata->first_touched)); + /* NOTE: last touched set below */ + + g_hash_table_insert(priv->apps, g_strdup(id), appdata); + } else { + /* Boring, we've got this one already */ + appdata = (AppData *)data; + } + + g_get_current_time(&(appdata->last_touched)); return; } -- cgit v1.2.3 From 77f24c0cb4e46ea88a4594bd63875691c25234e4 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 11:59:33 -0600 Subject: Making a sort function that looks at two Apps and determines their ordering. --- src/application-service-lru-file.c | 46 +++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index 45fe9db..fd0b7ed 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -167,7 +167,9 @@ app_lru_file_touch (AppLruFile * lrufile, const gchar * id, const gchar * catego appdata = (AppData *)data; } + /* Touch it and mark the DB as dirty */ g_get_current_time(&(appdata->last_touched)); + /* TODO: Make dirty */ return; } @@ -177,6 +179,48 @@ app_lru_file_sort (AppLruFile * lrufile, const gchar * id_a, const gchar * id_b) { g_return_val_if_fail(IS_APP_LRU_FILE(lrufile), -1); + /* Let's first look to see if the IDs are the same, this + really shouldn't happen, but it'll be confusing if we + don't get it out of the way to start. */ + if (g_strcmp0(id_a, id_b) == 0) { + return 0; + } + + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(lrufile); + + /* Now make sure we have app data for both of these. If + not we'll assume that the one without is newer? */ + gpointer data_a = g_hash_table_lookup(priv->apps, id_a); + if (data_a == NULL) { + return -1; + } + + gpointer data_b = g_hash_table_lookup(priv->apps, id_b); + if (data_b == NULL) { + return 1; + } + + /* Ugly casting */ + AppData * appdata_a = (AppData *)data_a; + AppData * appdata_b = (AppData *)data_b; + + /* Look at categories, we'll put the categories in alpha + order if they're not the same. */ + gint catcompare = g_strcmp0(appdata_a->category, appdata_b->category); + if (catcompare != 0) { + return catcompare; + } + + /* Now we're looking at the first time that these two were + seen in this account. Only using seconds. I mean, seriously. */ + if (appdata_a->first_touched.tv_sec < appdata_b->first_touched.tv_sec) { + return -1; + } + if (appdata_b->first_touched.tv_sec < appdata_a->first_touched.tv_sec) { + return 1; + } - return 0; + /* Eh, this seems roughly impossible. But if we have to choose, + I like A better. */ + return 1; } -- cgit v1.2.3 From de476ff16608cc71b09c8ed6591c728b486f4b94 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 13:36:38 -0600 Subject: Fleshing out the cleaning and dirtying functions. Now we should write out a file. --- src/application-service-lru-file.c | 130 ++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 1 deletion(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index fd0b7ed..c7911bc 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -2,6 +2,8 @@ #include "config.h" #endif +#include +#include #include "application-service-lru-file.h" typedef struct _AppLruFilePrivate AppLruFilePrivate; @@ -28,6 +30,9 @@ static void app_lru_file_dispose (GObject *object); static void app_lru_file_finalize (GObject *object); static void app_data_free (gpointer data); static gboolean load_from_file (gpointer data); +static void clean_off_hash_cb (gpointer key, gpointer value, gpointer data); +static void clean_off_write_cb (GObject * obj, GAsyncResult * res, gpointer data); +static void clean_off_write_end_cb (GObject * obj, GAsyncResult * res, gpointer data); G_DEFINE_TYPE (AppLruFile, app_lru_file, G_TYPE_OBJECT); @@ -128,6 +133,129 @@ load_from_file (gpointer data) return FALSE; } +/* Write out our cache to a file so that we can unmark the dirty + bit and be happy. */ +static gboolean +clean_off (gpointer data) +{ + AppLruFile * lrufile = (AppLruFile *)data; + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(lrufile); + priv->timer = 0; + + GError * error = NULL; + GFile * file = g_file_new_for_path(priv->filename); + GFileOutputStream * ostream = g_file_replace(file, + NULL, /* etag */ + TRUE, /* backup */ + G_FILE_CREATE_NONE, /* flags */ + NULL, /* cancelable */ + &error); + if (error != NULL) { + g_warning("Unable to open a file to store LRU file: %s", error->message); + return FALSE; + } + + /* This is how the file will start and end. */ + gchar * start = g_strdup("{\n \"version\": 1"); + gchar * end = g_strdup("\n}\n"); + + /* Put the front on. */ + g_output_stream_write_async(G_OUTPUT_STREAM(ostream), + start, + strlen(start), + G_PRIORITY_LOW, + NULL, + clean_off_write_cb, + start); + + /* Put the middle in. */ + g_hash_table_foreach (priv->apps, clean_off_hash_cb, ostream); + + + /* And then tack on the end. */ + g_output_stream_write_async(G_OUTPUT_STREAM(ostream), + end, + strlen(end), + G_PRIORITY_LOW, + NULL, + clean_off_write_end_cb, + end); + + return FALSE; /* drop the timer */ +} + +/* Looks at every value in the applications hash table and + turns it into a string for writing out. */ +static void +clean_off_hash_cb (gpointer key, gpointer value, gpointer data) +{ + /* Mega-cast */ + gchar * id = (gchar *)key; + AppData * appdata = (AppData *)value; + GOutputStream * ostream = (GOutputStream *)ostream; + + gchar * firsttime = g_time_val_to_iso8601(&appdata->first_touched); + gchar * lasttime = g_time_val_to_iso8601(&appdata->last_touched); + + gchar * output = g_strdup_printf(",\n \"%s\": { \"first-time\": \"%s\", \"last-time\": \"%s\"}", id, firsttime, lasttime); + + g_free(lasttime); + g_free(firsttime); + + g_output_stream_write_async(ostream, + output, + strlen(output), + G_PRIORITY_LOW, + NULL, + clean_off_write_cb, + output); + + return; +} + +/* After the data has been written to the file we make + sure to free the string we created */ +static void +clean_off_write_cb (GObject * obj, GAsyncResult * res, gpointer data) +{ + g_free(data); + return; +} + +/* Very much like clean_off_write_cb except that it is the + last actor on this Output Stream so it closes it. */ +static void +clean_off_write_end_cb (GObject * obj, GAsyncResult * res, gpointer data) +{ + clean_off_write_cb(obj, res, data); + + GError * error = NULL; + g_output_stream_close(G_OUTPUT_STREAM(obj), NULL, &error); + + if (error != NULL) { + g_warning("Unable to close LRU File: %s", error->message); + g_error_free(error); + } + + return; +} + +/* Sets the dirty bit if not already set and makes sure that + we have a timer to fix that at some point. */ +static void +get_dirty (AppLruFile * lrufile) +{ + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(lrufile); + + priv->dirty = TRUE; + + if (priv->timer == 0) { + priv->timer = g_timeout_add_seconds(60, clean_off, lrufile); + } + + return; +} + /* API */ /* Simple helper to create a new object */ @@ -169,7 +297,7 @@ app_lru_file_touch (AppLruFile * lrufile, const gchar * id, const gchar * catego /* Touch it and mark the DB as dirty */ g_get_current_time(&(appdata->last_touched)); - /* TODO: Make dirty */ + get_dirty(lrufile); return; } -- cgit v1.2.3 From 39c33f772eb63624b4479a5d8a21eb58d37baf8e Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 14:28:09 -0600 Subject: Build the directory and some debugging info --- src/application-service-lru-file.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index c7911bc..cb69a6e 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -143,6 +143,16 @@ clean_off (gpointer data) priv->timer = 0; GError * error = NULL; + + /* Check to see if our directory exists. Build it if not. */ + gchar * dirname = g_build_filename(g_get_user_config_dir(), "indicators", "application", NULL); + if (!g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + GFile * dirfile = g_file_new_for_path(dirname); + g_file_make_directory_with_parents(dirfile, NULL, NULL); + g_object_unref(dirfile); + } + g_free(dirname); + GFile * file = g_file_new_for_path(priv->filename); GFileOutputStream * ostream = g_file_replace(file, NULL, /* etag */ @@ -163,10 +173,11 @@ clean_off (gpointer data) g_output_stream_write_async(G_OUTPUT_STREAM(ostream), start, strlen(start), - G_PRIORITY_LOW, + G_PRIORITY_DEFAULT_IDLE, NULL, clean_off_write_cb, start); + g_debug("Start Write : %s", start); /* Put the middle in. */ g_hash_table_foreach (priv->apps, clean_off_hash_cb, ostream); @@ -176,10 +187,11 @@ clean_off (gpointer data) g_output_stream_write_async(G_OUTPUT_STREAM(ostream), end, strlen(end), - G_PRIORITY_LOW, + G_PRIORITY_DEFAULT_IDLE, NULL, clean_off_write_end_cb, end); + g_debug("Start Write : %s", end); return FALSE; /* drop the timer */ } @@ -192,7 +204,7 @@ clean_off_hash_cb (gpointer key, gpointer value, gpointer data) /* Mega-cast */ gchar * id = (gchar *)key; AppData * appdata = (AppData *)value; - GOutputStream * ostream = (GOutputStream *)ostream; + GOutputStream * ostream = (GOutputStream *)data; gchar * firsttime = g_time_val_to_iso8601(&appdata->first_touched); gchar * lasttime = g_time_val_to_iso8601(&appdata->last_touched); @@ -205,10 +217,11 @@ clean_off_hash_cb (gpointer key, gpointer value, gpointer data) g_output_stream_write_async(ostream, output, strlen(output), - G_PRIORITY_LOW, + G_PRIORITY_DEFAULT_IDLE, NULL, clean_off_write_cb, output); + g_debug("Start Write : %s", output); return; } @@ -218,6 +231,7 @@ clean_off_hash_cb (gpointer key, gpointer value, gpointer data) static void clean_off_write_cb (GObject * obj, GAsyncResult * res, gpointer data) { + g_debug("Complete Write: %s", (gchar *)data); g_free(data); return; } -- cgit v1.2.3 From 72432728b161a54dfd711242e17cd2e55a011c2c Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 14:40:14 -0600 Subject: Switch to building a string and writing it out instead of async writes as the order doesn't seem to be predictable. --- src/application-service-lru-file.c | 53 ++++++++------------------------------ 1 file changed, 11 insertions(+), 42 deletions(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index cb69a6e..95ffb3c 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -31,7 +31,6 @@ static void app_lru_file_finalize (GObject *object); static void app_data_free (gpointer data); static gboolean load_from_file (gpointer data); static void clean_off_hash_cb (gpointer key, gpointer value, gpointer data); -static void clean_off_write_cb (GObject * obj, GAsyncResult * res, gpointer data); static void clean_off_write_end_cb (GObject * obj, GAsyncResult * res, gpointer data); G_DEFINE_TYPE (AppLruFile, app_lru_file, G_TYPE_OBJECT); @@ -165,33 +164,22 @@ clean_off (gpointer data) return FALSE; } - /* This is how the file will start and end. */ - gchar * start = g_strdup("{\n \"version\": 1"); - gchar * end = g_strdup("\n}\n"); - - /* Put the front on. */ - g_output_stream_write_async(G_OUTPUT_STREAM(ostream), - start, - strlen(start), - G_PRIORITY_DEFAULT_IDLE, - NULL, - clean_off_write_cb, - start); - g_debug("Start Write : %s", start); + /* This is how the file will start */ + GString * filestring = g_string_new("{\n \"version\": 1"); /* Put the middle in. */ - g_hash_table_foreach (priv->apps, clean_off_hash_cb, ostream); - + g_hash_table_foreach (priv->apps, clean_off_hash_cb, filestring); /* And then tack on the end. */ + g_string_append(filestring, "\n}\n"); + gchar * filedata = g_string_free(filestring, FALSE); g_output_stream_write_async(G_OUTPUT_STREAM(ostream), - end, - strlen(end), + filedata, + strlen(filedata), G_PRIORITY_DEFAULT_IDLE, NULL, clean_off_write_end_cb, - end); - g_debug("Start Write : %s", end); + filedata); return FALSE; /* drop the timer */ } @@ -204,35 +192,16 @@ clean_off_hash_cb (gpointer key, gpointer value, gpointer data) /* Mega-cast */ gchar * id = (gchar *)key; AppData * appdata = (AppData *)value; - GOutputStream * ostream = (GOutputStream *)data; + GString * string = (GString *)data; gchar * firsttime = g_time_val_to_iso8601(&appdata->first_touched); gchar * lasttime = g_time_val_to_iso8601(&appdata->last_touched); - gchar * output = g_strdup_printf(",\n \"%s\": { \"first-time\": \"%s\", \"last-time\": \"%s\"}", id, firsttime, lasttime); + g_string_append_printf(string, ",\n \"%s\": { \"first-time\": \"%s\", \"last-time\": \"%s\"}", id, firsttime, lasttime); g_free(lasttime); g_free(firsttime); - g_output_stream_write_async(ostream, - output, - strlen(output), - G_PRIORITY_DEFAULT_IDLE, - NULL, - clean_off_write_cb, - output); - g_debug("Start Write : %s", output); - - return; -} - -/* After the data has been written to the file we make - sure to free the string we created */ -static void -clean_off_write_cb (GObject * obj, GAsyncResult * res, gpointer data) -{ - g_debug("Complete Write: %s", (gchar *)data); - g_free(data); return; } @@ -241,7 +210,7 @@ clean_off_write_cb (GObject * obj, GAsyncResult * res, gpointer data) static void clean_off_write_end_cb (GObject * obj, GAsyncResult * res, gpointer data) { - clean_off_write_cb(obj, res, data); + g_free(data); GError * error = NULL; g_output_stream_close(G_OUTPUT_STREAM(obj), NULL, &error); -- cgit v1.2.3 From 5317706e5e2c21962a872f0bbe2cbd948d520e95 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 15:53:17 -0600 Subject: Fleshing out loading of the LRU file and realizing we need a json-glib dep and the 'category' field in the output. --- src/application-service-lru-file.c | 80 +++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index 95ffb3c..de28b81 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -4,6 +4,7 @@ #include #include +#include #include "application-service-lru-file.h" typedef struct _AppLruFilePrivate AppLruFilePrivate; @@ -30,6 +31,7 @@ static void app_lru_file_dispose (GObject *object); static void app_lru_file_finalize (GObject *object); static void app_data_free (gpointer data); static gboolean load_from_file (gpointer data); +static void load_file_object_cb (JsonObject * obj, const gchar * key, JsonNode * value, gpointer data); static void clean_off_hash_cb (gpointer key, gpointer value, gpointer data); static void clean_off_write_end_cb (GObject * obj, GAsyncResult * res, gpointer data); @@ -128,10 +130,86 @@ app_data_free (gpointer data) static gboolean load_from_file (gpointer data) { + AppLruFile * lrufile = (AppLruFile *)data; + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(lrufile); + + if (!g_file_test(priv->filename, G_FILE_TEST_EXISTS)) { + return FALSE; + } + + JsonParser * parser = json_parser_new(); + if (!json_parser_load_from_file(parser, priv->filename, NULL)) { + g_warning("Unable to parse JSON file '%s'", priv->filename); + g_object_unref(parser); + return FALSE; + } + + JsonNode * root = json_parser_get_root(parser); + JsonObject * rootobj = json_node_get_object(root); + if (rootobj == NULL) { + g_warning("Malformed LRU file. The root node is not an object."); + g_object_unref(parser); + return FALSE; + } + + json_object_foreach_member(rootobj, load_file_object_cb, priv); + + g_object_unref(parser); return FALSE; } +/* Looks at the various things that we need on a node, makes + sure that we have them, and then copies them into the + application hash table of love. */ +static void +load_file_object_cb (JsonObject * rootobj, const gchar * key, JsonNode * value, gpointer data) +{ + AppLruFilePrivate * priv = (AppLruFilePrivate *)data; + + /* We're not looking at this today. */ + if (!g_strcmp0(key, "version")) { + return; + } + + JsonObject * obj = json_node_get_object(value); + if (obj == NULL) { + g_warning("Data for node '%s' is not an object.", key); + return; + } + + const gchar * obj_category = json_object_get_string_member(obj, "category"); + const gchar * obj_first = json_object_get_string_member(obj, "first-time"); + const gchar * obj_last = json_object_get_string_member(obj, "last-time"); + + if (obj_category == NULL || obj_first == NULL || obj_last == NULL) { + g_warning("Node '%s' is missing data. Got: ('%s', '%s', '%s')", key, obj_category, obj_first, obj_last); + return; + } + + gpointer datapntr = g_hash_table_lookup(priv->apps, key); + if (datapntr == NULL) { + /* Build a new node */ + AppData * appdata = g_new0(AppData, 1); + appdata->category = g_strdup(obj_category); + g_time_val_from_iso8601(obj_first, &appdata->first_touched); + g_time_val_from_iso8601(obj_last, &appdata->last_touched); + + g_hash_table_insert(priv->apps, g_strdup(key), appdata); + } else { + /* Merge nodes */ + AppData * appdata = (AppData *)datapntr; + GTimeVal temptime; + g_time_val_from_iso8601(obj_first, &temptime); + + if (temptime.tv_sec < appdata->first_touched.tv_sec) { + g_time_val_from_iso8601(obj_first, &appdata->first_touched); + } + } + + return; +} + /* Write out our cache to a file so that we can unmark the dirty bit and be happy. */ static gboolean @@ -197,7 +275,7 @@ clean_off_hash_cb (gpointer key, gpointer value, gpointer data) gchar * firsttime = g_time_val_to_iso8601(&appdata->first_touched); gchar * lasttime = g_time_val_to_iso8601(&appdata->last_touched); - g_string_append_printf(string, ",\n \"%s\": { \"first-time\": \"%s\", \"last-time\": \"%s\"}", id, firsttime, lasttime); + g_string_append_printf(string, ",\n \"%s\": { \"first-time\": \"%s\", \"last-time\": \"%s\", \"category\": \"%s\"}", id, firsttime, lasttime, appdata->category); g_free(lasttime); g_free(firsttime); -- cgit v1.2.3 From 33644ed5b49b8af5a0d6b2f702c783319285db8d Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 16:12:11 -0600 Subject: Moving the JSON file values into #defines --- src/application-service-lru-file.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index de28b81..26ff2e8 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -7,6 +7,11 @@ #include #include "application-service-lru-file.h" +#define ENTRY_CATEGORY "category" +#define ENTRY_FIRST_TIME "first-time" +#define ENTRY_LAST_TIME "last-time" +#define ENTRY_VERSION "version" + typedef struct _AppLruFilePrivate AppLruFilePrivate; struct _AppLruFilePrivate { GHashTable * apps; @@ -168,7 +173,7 @@ load_file_object_cb (JsonObject * rootobj, const gchar * key, JsonNode * value, AppLruFilePrivate * priv = (AppLruFilePrivate *)data; /* We're not looking at this today. */ - if (!g_strcmp0(key, "version")) { + if (!g_strcmp0(key, ENTRY_VERSION)) { return; } @@ -178,9 +183,9 @@ load_file_object_cb (JsonObject * rootobj, const gchar * key, JsonNode * value, return; } - const gchar * obj_category = json_object_get_string_member(obj, "category"); - const gchar * obj_first = json_object_get_string_member(obj, "first-time"); - const gchar * obj_last = json_object_get_string_member(obj, "last-time"); + const gchar * obj_category = json_object_get_string_member(obj, ENTRY_CATEGORY); + const gchar * obj_first = json_object_get_string_member(obj, ENTRY_FIRST_TIME); + const gchar * obj_last = json_object_get_string_member(obj, ENTRY_LAST_TIME); if (obj_category == NULL || obj_first == NULL || obj_last == NULL) { g_warning("Node '%s' is missing data. Got: ('%s', '%s', '%s')", key, obj_category, obj_first, obj_last); @@ -243,7 +248,7 @@ clean_off (gpointer data) } /* This is how the file will start */ - GString * filestring = g_string_new("{\n \"version\": 1"); + GString * filestring = g_string_new("{\n \"" ENTRY_VERSION "\": 1"); /* Put the middle in. */ g_hash_table_foreach (priv->apps, clean_off_hash_cb, filestring); @@ -275,7 +280,7 @@ clean_off_hash_cb (gpointer key, gpointer value, gpointer data) gchar * firsttime = g_time_val_to_iso8601(&appdata->first_touched); gchar * lasttime = g_time_val_to_iso8601(&appdata->last_touched); - g_string_append_printf(string, ",\n \"%s\": { \"first-time\": \"%s\", \"last-time\": \"%s\", \"category\": \"%s\"}", id, firsttime, lasttime, appdata->category); + g_string_append_printf(string, ",\n \"%s\": { \"" ENTRY_FIRST_TIME "\": \"%s\", \"" ENTRY_LAST_TIME "\": \"%s\", \"" ENTRY_CATEGORY "\": \"%s\"}", id, firsttime, lasttime, appdata->category); g_free(lasttime); g_free(firsttime); -- cgit v1.2.3 From 26a0d6f4bb11f7f31d1e8f0f6218cfca859f8a1f Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 16:16:43 -0600 Subject: Moving directory and filename into defines --- src/application-service-lru-file.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index 26ff2e8..a13227a 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -12,6 +12,9 @@ #define ENTRY_LAST_TIME "last-time" #define ENTRY_VERSION "version" +#define CONFIG_DIR ("indicators" G_DIR_SEPARATOR_S "application") +#define CONFIG_FILE "lru-file.json" + typedef struct _AppLruFilePrivate AppLruFilePrivate; struct _AppLruFilePrivate { GHashTable * apps; @@ -70,7 +73,7 @@ app_lru_file_init (AppLruFile *self) /* Now let's build some stuff */ priv->apps = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, app_data_free); - priv->filename = g_build_filename(g_get_user_config_dir(), "indicators", "application", "lru-file.json", NULL); + priv->filename = g_build_filename(g_get_user_config_dir(), CONFIG_DIR, CONFIG_FILE, NULL); /* No reason to delay other stuff for this, we'll merge any values that get touched. */ @@ -227,7 +230,7 @@ clean_off (gpointer data) GError * error = NULL; /* Check to see if our directory exists. Build it if not. */ - gchar * dirname = g_build_filename(g_get_user_config_dir(), "indicators", "application", NULL); + gchar * dirname = g_build_filename(g_get_user_config_dir(), CONFIG_DIR, NULL); if (!g_file_test(dirname, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { GFile * dirfile = g_file_new_for_path(dirname); g_file_make_directory_with_parents(dirfile, NULL, NULL); -- cgit v1.2.3 From 0ccf950d37c2de390f79c10d9bebbd4ca6dfc894 Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 16:28:13 -0600 Subject: License headers. --- src/application-service-lru-file.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index a13227a..fec9644 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -1,3 +1,25 @@ +/* +This object manages the database of when the entires were touched +and loved. And writes that out to disk occationally as well. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould + +This program is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License version 3, as published +by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranties of +MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program. If not, see . +*/ + #ifdef HAVE_CONFIG_H #include "config.h" #endif -- cgit v1.2.3 From da6242ba497bf70eb2ee8c75e74ddf5ac7f699ca Mon Sep 17 00:00:00 2001 From: Ted Gould Date: Wed, 20 Jan 2010 16:41:38 -0600 Subject: Looking at the last touch date of entries as we're loading the file and removing ones that are very old. --- src/application-service-lru-file.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'src/application-service-lru-file.c') diff --git a/src/application-service-lru-file.c b/src/application-service-lru-file.c index fec9644..c69a20f 100644 --- a/src/application-service-lru-file.c +++ b/src/application-service-lru-file.c @@ -60,6 +60,7 @@ static void app_lru_file_init (AppLruFile *self); static void app_lru_file_dispose (GObject *object); static void app_lru_file_finalize (GObject *object); static void app_data_free (gpointer data); +static void get_dirty (AppLruFile * lrufile); static gboolean load_from_file (gpointer data); static void load_file_object_cb (JsonObject * obj, const gchar * key, JsonNode * value, gpointer data); static void clean_off_hash_cb (gpointer key, gpointer value, gpointer data); @@ -183,7 +184,7 @@ load_from_file (gpointer data) return FALSE; } - json_object_foreach_member(rootobj, load_file_object_cb, priv); + json_object_foreach_member(rootobj, load_file_object_cb, lrufile); g_object_unref(parser); return FALSE; @@ -195,7 +196,8 @@ load_from_file (gpointer data) static void load_file_object_cb (JsonObject * rootobj, const gchar * key, JsonNode * value, gpointer data) { - AppLruFilePrivate * priv = (AppLruFilePrivate *)data; + AppLruFile * lrufile = (AppLruFile *)data; + AppLruFilePrivate * priv = APP_LRU_FILE_GET_PRIVATE(lrufile); /* We're not looking at this today. */ if (!g_strcmp0(key, ENTRY_VERSION)) { @@ -214,9 +216,35 @@ load_file_object_cb (JsonObject * rootobj, const gchar * key, JsonNode * value, if (obj_category == NULL || obj_first == NULL || obj_last == NULL) { g_warning("Node '%s' is missing data. Got: ('%s', '%s', '%s')", key, obj_category, obj_first, obj_last); + get_dirty(lrufile); + return; + } + + /* Check to see how old this entry is. If it hasn't been + used in the last year, we remove the cruft. */ + GTimeVal currenttime; + g_get_current_time(¤ttime); + GDate * currentdate = g_date_new(); + g_date_set_time_val(currentdate, ¤ttime); + + GTimeVal lasttouch; + g_time_val_from_iso8601(obj_last, &lasttouch); + GDate * lastdate = g_date_new(); + g_date_set_time_val(lastdate, &lasttouch); + + gint spread = g_date_days_between(lastdate, currentdate); + + g_date_free(currentdate); + g_date_free(lastdate); + + if (spread > 365) { + g_debug("Removing node '%s' as it's %d days old.", key, spread); + get_dirty(lrufile); return; } + /* See if we already have one of these. It's a little bit + unlikely, but since we're async, we need to check */ gpointer datapntr = g_hash_table_lookup(priv->apps, key); if (datapntr == NULL) { /* Build a new node */ -- cgit v1.2.3