commit 74793de06b885955b59f0b6a3f0e35ac47eefd35
parent 96539f09287c86af39108d0f06c5a0e889e46657
Author: lash <dev@holbrook.no>
Date: Thu, 28 Mar 2024 18:05:55 +0000
Implement database backend, deserialization to entry, list item
Diffstat:
7 files changed, 198 insertions(+), 41 deletions(-)
diff --git a/src/db.c b/src/db.c
@@ -3,10 +3,12 @@
#include <lmdb.h>
#include <gcrypt.h>
#include <time.h>
+
#include "db.h"
#include "digest.h"
#include "err.h"
#include "endian.h"
+#include "debug.h"
int db_connect(struct db_ctx *ctx, char *conn) {
int r;
@@ -22,6 +24,8 @@ int db_connect(struct db_ctx *ctx, char *conn) {
return ERR_FAIL;
}
+ debug_log(DEBUG_INFO, "db connected");
+
return ERR_OK;
}
@@ -122,12 +126,13 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha
return ERR_DB_INVALID;
}
- if (ctx->current_key == DbNoKey) {
- if (ctx->started) {
- mdb_cursor_close(ctx->crsr);
- mdb_dbi_close(ctx->env, ctx->dbi);
- mdb_txn_abort(ctx->tx);
- }
+ //if (ctx->current_key == DbNoKey) {
+ if (!ctx->browsing) {
+// if (ctx->started) {
+// mdb_cursor_close(ctx->crsr);
+// mdb_dbi_close(ctx->env, ctx->dbi);
+// mdb_txn_abort(ctx->tx);
+// }
r = mdb_txn_begin(ctx->env, NULL, MDB_RDONLY, &ctx->tx);
if (r) {
@@ -146,18 +151,20 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha
start[0] = (char)pfx;
ctx->k.mv_size = 1;
- if (!ctx->browsing) {
- if (*key != 0) {
- memcpy(start+1, *key, *key_len);
- ctx->k.mv_size += *key_len;
- }
- }
+// if (!ctx->browsing) {
+// if (*key != 0) {
+// memcpy(start+1, *key, *key_len);
+// ctx->k.mv_size += *key_len;
+// }
+// }
ctx->k.mv_data = start;
- }
- if (!ctx->browsing) {
- r = mdb_cursor_get(ctx->crsr, &ctx->k, &ctx->v, MDB_SET_RANGE);
ctx->browsing = 1;
+ if (*key != 0) {
+ memcpy(ctx->k.mv_data, *key, *key_len);
+ ctx->k.mv_size += *key_len;
+ }
+ r = mdb_cursor_get(ctx->crsr, &ctx->k, &ctx->v, MDB_SET_RANGE);
} else {
r = mdb_cursor_get(ctx->crsr, &ctx->k, &ctx->v, MDB_NEXT_NODUP);
}
@@ -166,7 +173,8 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha
}
start[0] = (char)*((char*)ctx->k.mv_data);
if (start[0] != ctx->current_key) {
- db_reset(ctx);
+ //db_reset(ctx);
+ ctx->browsing = 0;
return ERR_DB_NOMATCH;
}
@@ -181,5 +189,8 @@ int db_next(struct db_ctx *ctx, enum DbKey pfx, char **key, size_t *key_len, cha
void db_reset(struct db_ctx *ctx) {
+ mdb_cursor_close(ctx->crsr);
+ mdb_dbi_close(ctx->env, ctx->dbi);
+ mdb_txn_abort(ctx->tx);
memset(ctx, 0, sizeof(struct db_ctx));
}
diff --git a/src/db.h b/src/db.h
@@ -25,7 +25,9 @@ enum DbKey {
/// Noop value, used for default value of a DbKey variable
DbNoKey = 0x00,
/// A credit item record
- DbKeyCreditItem = 0x01,
+ DbKeyLedgerHead = 0x01,
+ /// A credit item record
+ DbKeyLedgerEntry = 0x02,
/// A reverse lookup record; resolves the content hash to the content entry in the database.
DbKeyReverse = 0xff,
};
diff --git a/src/gtk/kee-entry-list.c b/src/gtk/kee-entry-list.c
@@ -2,6 +2,7 @@
#include <gtk/gtk.h>
#include "kee-entry-list.h"
+#include "kee-entry.h"
#include "err.h"
typedef struct {
@@ -16,18 +17,30 @@ struct _KeeEntryList {
G_DEFINE_TYPE(KeeEntryList, kee_entry_list, GTK_TYPE_BOX);
static void kee_entry_handle_setup(KeeEntryList* o, GtkListItem *item) {
- g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "setup");
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "entry list setup");
}
-static void kee_entry_handle_bind(KeeEntryList* o, GtkListItem *item) {
- const char *s;
- GObject *go;
- GtkWidget *label;
+static void kee_entry_handle_bind(KeeEntryList *o, GtkListItem *item) {
+ GtkWidget *widget;
+ char *s;
+ KeeEntry *go;
- go = G_OBJECT(gtk_list_item_get_item(item));
- s = g_object_get_data(go, "foo");
- label = gtk_label_new(s);
- gtk_list_item_set_child(item, label);
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "entry list bind");
+ go = gtk_list_item_get_item(item);
+ g_object_take_ref(G_OBJECT(go));
+ gtk_list_item_set_child(item, GTK_WIDGET(go));
+}
+
+static void kee_entry_handle_unbind(KeeEntryList* o, GtkListItem *item) {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "entry list unbind");
+ //GObject *go;
+ //go = gtk_list_item_get_child(item);
+ gtk_list_item_set_child(item, NULL);
+ //g_object_unref(go);
+}
+
+static void kee_entry_handle_teardown(KeeEntryList* o, GtkListItem *item) {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "entry list teardown");
}
static void kee_entry_list_class_init(KeeEntryListClass *kls) {
@@ -37,6 +50,8 @@ static void kee_entry_list_init(KeeEntryList *o) {
o->factory = gtk_signal_list_item_factory_new();
g_signal_connect(o->factory, "setup", G_CALLBACK(kee_entry_handle_setup), NULL);
g_signal_connect(o->factory, "bind", G_CALLBACK(kee_entry_handle_bind), NULL);
+ g_signal_connect(o->factory, "unbind", G_CALLBACK(kee_entry_handle_unbind), NULL);
+ g_signal_connect(o->factory, "teardown", G_CALLBACK(kee_entry_handle_teardown), NULL);
}
GtkWidget* kee_entry_list_new(GListModel *model) {
diff --git a/src/gtk/kee-entry-store.c b/src/gtk/kee-entry-store.c
@@ -1,8 +1,11 @@
#include <glib-object.h>
#include <gtk/gtk.h>
#include <gio/gio.h>
+#include <limits.h>
#include "kee-entry-store.h"
+#include "kee-entry.h"
+#include "err.h"
typedef struct {
@@ -11,6 +14,14 @@ typedef struct {
struct _KeeEntryStore {
GObject parent;
struct db_ctx *db;
+ int last_idx;
+ int last_state;
+ int last_count;
+ char *last;
+ char *last_key;
+ char *last_digest;
+ char *last_value;
+ size_t last_value_length;
};
@@ -22,40 +33,96 @@ static void kee_entry_store_class_init(KeeEntryStoreClass *kls) {
}
+static int kee_entry_store_seek(KeeEntryStore *o, int idx);
+
static void kee_entry_store_init(KeeEntryStore *o) {
}
static GType kee_entry_store_get_item_type(GListModel *list) {
- return G_TYPE_OBJECT;
+ return KEE_TYPE_ENTRY;
}
static guint kee_entry_store_get_n_items(GListModel *list) {
- return 1;
+ return KEE_ENTRY_STORE(list)->last_count;
}
static gpointer kee_entry_store_get_item(GListModel *list, guint index) {
- GObject *o;
+ KeeEntry *o;
+ KeeEntryStore *store;
+ char s;
+
+ o = g_object_new(KEE_TYPE_ENTRY, NULL);
- o = g_object_new(G_TYPE_OBJECT, NULL);
+ //kee_entry_load(o, list->db);
+ store = KEE_ENTRY_STORE(list);
+ kee_entry_store_seek(store, index);
+ kee_entry_deserialize(o, store->last_key, 9, store->last_value, store->last_value_length);
+
+ //return o;
+ kee_entry_apply_list_item_widget(o);
- g_object_set_data(o, "foo", "bar");
return o;
}
-
static void kee_entry_store_iface_init(GListModelInterface *ifc) {
ifc->get_item_type = kee_entry_store_get_item_type;
ifc->get_n_items = kee_entry_store_get_n_items;
ifc->get_item = kee_entry_store_get_item;
}
+/// \todo always scans from 0, inefficient
+/// \todo enum lookup states
+static int kee_entry_store_seek(KeeEntryStore *o, int idx) {
+ int c;
+ int r;
+ int i;
+ size_t key_len;
+ //int direction;
+
+ //c = o->last_idx;
+ //if (idx == c) {
+ // return;
+ //}
+
+ //direction = 0;
+ key_len = 9;
+ o->last_key = o->last;
+ o->last_value = o->last_digest + 64;
+ *o->last_key = DbKeyLedgerHead;
+ i = 0;
+ o->last_state = 2;
+ while (i <= idx) {
+ o->last_idx = i;
+ o->last_value_length = 1024;
+ r = db_next(o->db, DbKeyLedgerHead, &o->last_key, &key_len, &o->last_value, &o->last_value_length);
+ if (r) {
+ o->last_state = 0;
+ return i;
+ }
+ o->last_state = 1;
+ i++;
+ }
+ return i;
+}
+
KeeEntryStore* kee_entry_store_new(struct db_ctx *db) {
KeeEntryStore *o;
o = g_object_new(KEE_TYPE_ENTRY_STORE, NULL);
o->db = db;
+ o->last_value_length = 1024;
+ o->last = calloc(2048, 1);
+ o->last_digest = o->last + DB_KEY_SIZE_LIMIT;
+
+ o->last_count = kee_entry_store_seek(o, INT_MAX);
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "max key index is: %d", o->last_idx - 1);
return o;
}
+
+void kee_entry_store_finalize(KeeEntryStore *o) {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "freeing entry store");
+ free(o->last);
+}
diff --git a/src/gtk/kee-entry.c b/src/gtk/kee-entry.c
@@ -4,23 +4,75 @@
#include "kee-entry.h"
#include "db.h"
#include "err.h"
+#include "export.h"
typedef struct {
} KeeEntryPrivate;
+struct _KeeEntryClass {
+ GtkWidget parent_class;
+};
+
struct _KeeEntry {
GtkWidget parent;
char *current_id;
+ int state;
+ long long timestamp;
+ char mem[4096];
+ char *unit_of_account;
};
G_DEFINE_TYPE(KeeEntry, kee_entry, GTK_TYPE_BOX);
+static void kee_entry_finalize(GObject *o) {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "tearing down entry");
+ //G_OBJECT_CLASS(kee_entry_parent_class)->finalize(o);
+}
+
static void kee_entry_class_init(KeeEntryClass *kls) {
+ GObjectClass *object_class = G_OBJECT_CLASS(kls);
+ object_class->finalize = kee_entry_finalize;
}
static void kee_entry_init(KeeEntry *o) {
+ o->current_id = (char*)o->mem;
+ o->unit_of_account = (char*)((o->mem)+64);
+ o->state = 2;
}
+
int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id) {
return ERR_OK;
}
+
+/// \todo enum state
+int kee_entry_deserialize(KeeEntry *o, const char *key, size_t key_len, const char *data, size_t data_len) {
+ int r;
+ struct kee_import im;
+ char out[4096];
+ size_t out_len;
+
+ o->state = 1;
+ import_init(&im, data, data_len);
+
+ out_len = 4096;
+ r = import_read(&im, o->unit_of_account, out_len);
+ *(o->unit_of_account + r) = 0;
+
+ o->state = 0;
+
+ return ERR_OK;
+}
+
+void kee_entry_apply_list_item_widget(KeeEntry *o) {
+ GtkWidget *widget;
+
+ if (o->state) {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, "entry must be loaded first");
+ return;
+ }
+
+ widget = gtk_label_new(o->unit_of_account);
+ gtk_box_append(GTK_BOX(o), widget);
+ return;
+}
diff --git a/src/gtk/kee-entry.h b/src/gtk/kee-entry.h
@@ -8,10 +8,17 @@
G_BEGIN_DECLS
+enum KEE_ENTRY_PROPS {
+ KEE_P_ENTRY_UNIT_OF_ACCOUNT = 1,
+ KEE_N_ENTRY_PROPS,
+};
+
#define KEE_TYPE_ENTRY kee_entry_get_type()
G_DECLARE_FINAL_TYPE(KeeEntry, kee_entry, KEE, ENTRY, GtkBox);
int kee_entry_load(KeeEntry *o, struct db_ctx *db, const char *id);
+int kee_entry_deserialize(KeeEntry *o, const char *key, size_t key_len, const char *data, size_t data_len);
+void kee_entry_apply_unit_of_account(KeeEntry *o);
G_END_DECLS
diff --git a/testdata.py b/testdata.py
@@ -210,20 +210,23 @@ if __name__ == '__main__':
env = lmdb.open(d)
dbi = env.open_db()
- with env.begin(write=True) as tx:
- c = random.randint(1, 20)
- r = generate_ledger(entry_count=c)
+ count_ledgers = os.environ.get('COUNT', '1')
- v = r.pop(0)
+ with env.begin(write=True) as tx:
+ for i in range(int(count_ledgers)):
+ c = random.randint(1, 20)
+ r = generate_ledger(entry_count=c)
- z = v[0]
- k = LedgerHead.to_key(v[0])
- tx.put(k, v[1])
+ v = r.pop(0)
- for v in r:
- k = LedgerEntry.to_key(v[1], z)
+ z = v[0]
+ k = LedgerHead.to_key(v[0])
tx.put(k, v[1])
+ for v in r:
+ k = LedgerEntry.to_key(v[1], z)
+ tx.put(k, v[1])
+
#pfx = b'\x00\x00\x00'
#pfx_two = b'\x00\x00\x01'