Add pluggable support for multiple storage backends.
[bluesky.git] / bluesky / store.c
index 9b509e6..abe7020 100644 (file)
  * interface, which different backends can implement.  Available backends
  * (will) include Amazon S3 and a simple local store for testing purposes. */
 
+struct _BlueSkyStore {
+    const BlueSkyStoreImplementation *impl;
+    gpointer handle;
+};
+
+GHashTable *store_implementations;
+
+void bluesky_store_register(const BlueSkyStoreImplementation *impl,
+                            const gchar *name)
+{
+    g_hash_table_insert(store_implementations, g_strdup(name), (gpointer)impl);
+}
+
+BlueSkyStore *bluesky_store_new(const gchar *type)
+{
+    const BlueSkyStoreImplementation *impl;
+
+    impl = g_hash_table_lookup(store_implementations, type);
+    if (impl == NULL)
+        return NULL;
+
+    gpointer handle = impl->create();
+    if (handle == NULL)
+        return NULL;
+
+    BlueSkyStore *store = g_new(BlueSkyStore, 1);
+    store->impl = impl;
+    store->handle = handle;
+    return store;
+}
+
+void bluesky_store_free(BlueSkyStore *store)
+{
+    store->impl->destroy(store->handle);
+    g_free(store);
+}
+
+BlueSkyRCStr *bluesky_store_get(BlueSkyStore *store, const gchar *key)
+{
+    return store->impl->get(store->handle, key);
+}
+
+void bluesky_store_put(BlueSkyStore *store,
+                       const gchar *key, BlueSkyRCStr *val)
+{
+    store->impl->put(store->handle, key, val);
+}
+
 /* Create and return a new reference-counted string.  The reference count is
  * initially one.  The newly-returned string takes ownership of the memory
  * pointed at by data, and will call g_free on it when the reference count
@@ -77,7 +125,7 @@ typedef struct {
     GHashTable *store;
 } MemStore;
 
-MemStore *memstore_new()
+static gpointer memstore_create()
 {
     MemStore *store = g_new(MemStore, 1);
     store->lock = g_mutex_new();
@@ -85,19 +133,75 @@ MemStore *memstore_new()
                                          g_free,
                                          (GDestroyNotify)bluesky_string_unref);
 
-    return store;
+    return (gpointer)store;
 }
 
-BlueSkyRCStr *memstore_get(MemStore *store, const gchar *key)
+static void memstore_destroy(gpointer store)
 {
+    /* TODO */
+}
+
+static BlueSkyRCStr *memstore_get(gpointer st, const gchar *key)
+{
+    MemStore *store = (MemStore *)st;
     BlueSkyRCStr *s = g_hash_table_lookup(store->store, key);
     if (s != NULL)
         bluesky_string_ref(s);
     return s;
 }
 
-void memstore_put(MemStore *store, const gchar *key, BlueSkyRCStr *val)
+static void memstore_put(gpointer s, const gchar *key, BlueSkyRCStr *val)
 {
+    MemStore *store = (MemStore *)s;
     bluesky_string_ref(val);
     g_hash_table_insert(store->store, g_strdup(key), val);
 }
+
+static BlueSkyStoreImplementation memstore_impl = {
+    .create = memstore_create,
+    .destroy = memstore_destroy,
+    .get = memstore_get,
+    .put = memstore_put,
+};
+
+/* Store implementation which writes data as files to disk. */
+static gpointer filestore_create()
+{
+    return GINT_TO_POINTER(1);
+}
+
+static void filestore_destroy()
+{
+}
+
+static BlueSkyRCStr *filestore_get(gpointer s, const gchar *key)
+{
+    gchar *contents = NULL;
+    gsize length;
+    GError *error;
+
+    g_file_get_contents(key, &contents, &length, &error);
+    if (contents == NULL)
+        return NULL;
+
+    return bluesky_string_new(contents, length);
+}
+
+static void filestore_put(gpointer s, const gchar *key, BlueSkyRCStr *val)
+{
+    g_file_set_contents(key, val->data, val->len, NULL);
+}
+
+static BlueSkyStoreImplementation filestore_impl = {
+    .create = filestore_create,
+    .destroy = filestore_destroy,
+    .get = filestore_get,
+    .put = filestore_put,
+};
+
+void bluesky_store_init()
+{
+    store_implementations = g_hash_table_new(g_str_hash, g_str_equal);
+    bluesky_store_register(&memstore_impl, "mem");
+    bluesky_store_register(&filestore_impl, "file");
+}