commit d1ef113a8b254b1f80ffbad8a2223f48ac13904e
parent f187f4f8f29fd14448ac4359cb6cdcb853781c52
Author: William Casarin <jb55@jb55.com>
Date: Tue, 12 Dec 2023 13:19:58 -0800
nostrdb/api: don't expose many internals, like note
rust doesn't like packed structures, so hide this from bindgen
This also buttons up the API so less things are exposed which is good.
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
M | nostrdb/nostrdb.c | | | 276 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
M | nostrdb/nostrdb.h | | | 538 | ++++++++++++++++++++++++------------------------------------------------------- |
2 files changed, 430 insertions(+), 384 deletions(-)
diff --git a/nostrdb/nostrdb.c b/nostrdb/nostrdb.c
@@ -51,6 +51,52 @@ typedef int (*ndb_migrate_fn)(struct ndb *);
typedef int (*ndb_word_parser_fn)(void *, const char *word, int word_len,
int word_index);
+// these must be byte-aligned, they are directly accessing the serialized data
+// representation
+#pragma pack(push, 1)
+
+
+union ndb_packed_str {
+ struct {
+ char str[3];
+ // we assume little endian everywhere. sorry not sorry.
+ unsigned char flag; // NDB_PACKED_STR, etc
+ } packed;
+
+ uint32_t offset;
+ unsigned char bytes[4];
+};
+
+struct ndb_tag {
+ uint16_t count;
+ union ndb_packed_str strs[0];
+};
+
+struct ndb_tags {
+ uint16_t padding;
+ uint16_t count;
+ struct ndb_tag tag[0];
+};
+
+// v1
+struct ndb_note {
+ unsigned char version; // v=1
+ unsigned char padding[3]; // keep things aligned
+ unsigned char id[32];
+ unsigned char pubkey[32];
+ unsigned char sig[64];
+
+ uint64_t created_at;
+ uint32_t kind;
+ uint32_t content_length;
+ union ndb_packed_str content;
+ uint32_t strings;
+ // nothing can come after tags since it contains variadic data
+ struct ndb_tags tags;
+};
+
+#pragma pack(pop)
+
struct ndb_migration {
ndb_migrate_fn fn;
};
@@ -674,7 +720,7 @@ static int ndb_generic_filter_matches(struct ndb_filter_elements *els,
if (it->tag->count < 2)
continue;
- str = ndb_note_str(note, &it->tag->strs[0]);
+ str = ndb_tag_str(note, it->tag, 0);
// we only care about packed strings (single char, etc)
if (str.flag != NDB_PACKED_STR)
@@ -684,7 +730,7 @@ static int ndb_generic_filter_matches(struct ndb_filter_elements *els,
if (str.str[0] != els->field.generic || str.str[1] != 0)
continue;
- str = ndb_note_str(note, &it->tag->strs[1]);
+ str = ndb_tag_str(note, it->tag, 1);
switch (els->field.elem_type) {
case NDB_ELEMENT_ID:
@@ -1966,11 +2012,11 @@ static unsigned char *ndb_note_last_id_tag(struct ndb_note *note, char type)
if (iter.tag->count < 2)
continue;
- str = ndb_note_str(note, &iter.tag->strs[0]);
+ str = ndb_tag_str(note, iter.tag, 0);
// assign liked to the last e tag
if (str.flag == NDB_PACKED_STR && str.str[0] == type) {
- str = ndb_note_str(note, &iter.tag->strs[1]);
+ str = ndb_tag_str(note, iter.tag, 1);
if (str.flag == NDB_PACKED_ID)
last = str.id;
}
@@ -3481,7 +3527,7 @@ static int cursor_push_json_tag(struct cursor *cur, struct ndb_note *note,
return 0;
for (i = 0; i < tag->count; i++) {
- if (!cursor_push_json_tag_str(cur, ndb_note_str(note, &tag->strs[i])))
+ if (!cursor_push_json_tag_str(cur, ndb_tag_str(note, tag, i)))
return 0;
if (i != tag->count-1 && !cursor_push_byte(cur, ','))
return 0;
@@ -3652,6 +3698,16 @@ struct ndb_note * ndb_builder_note(struct ndb_builder *builder)
return builder->note;
}
+static union ndb_packed_str ndb_offset_str(uint32_t offset)
+{
+ // ensure accidents like -1 don't corrupt our packed_str
+ union ndb_packed_str str;
+ // most significant byte is reserved for ndb_packtype
+ str.offset = offset & 0xFFFFFF;
+ return str;
+}
+
+
/// find an existing string via str_indices. these indices only exist in the
/// builder phase just for this purpose.
static inline int ndb_builder_find_str(struct ndb_builder *builder,
@@ -3715,6 +3771,25 @@ static int ndb_builder_push_packed_id(struct ndb_builder *builder,
return 0;
}
+union ndb_packed_str ndb_chars_to_packed_str(char c1, char c2)
+{
+ union ndb_packed_str str;
+ str.packed.flag = NDB_PACKED_STR;
+ str.packed.str[0] = c1;
+ str.packed.str[1] = c2;
+ str.packed.str[2] = '\0';
+ return str;
+}
+
+static union ndb_packed_str ndb_char_to_packed_str(char c)
+{
+ union ndb_packed_str str;
+ str.packed.flag = NDB_PACKED_STR;
+ str.packed.str[0] = c;
+ str.packed.str[1] = '\0';
+ return str;
+}
+
/// Check for small strings to pack
static inline int ndb_builder_try_compact_str(struct ndb_builder *builder,
@@ -4358,3 +4433,194 @@ int ndb_print_search_keys(struct ndb_txn *txn)
return 1;
}
+
+struct ndb_tags *ndb_note_tags(struct ndb_note *note)
+{
+ return ¬e->tags;
+}
+
+struct ndb_str ndb_note_str(struct ndb_note *note, union ndb_packed_str *pstr)
+{
+ struct ndb_str str;
+ str.flag = pstr->packed.flag;
+
+ if (str.flag == NDB_PACKED_STR) {
+ str.str = pstr->packed.str;
+ return str;
+ }
+
+ str.str = ((const char *)note) + note->strings + (pstr->offset & 0xFFFFFF);
+ return str;
+}
+
+struct ndb_str ndb_tag_str(struct ndb_note *note, struct ndb_tag *tag, int ind)
+{
+ return ndb_note_str(note, &tag->strs[ind]);
+}
+
+struct ndb_str ndb_iter_tag_str(struct ndb_iterator *iter, int ind)
+{
+ return ndb_tag_str(iter->note, iter->tag, ind);
+}
+
+unsigned char * ndb_note_id(struct ndb_note *note)
+{
+ return note->id;
+}
+
+unsigned char * ndb_note_pubkey(struct ndb_note *note)
+{
+ return note->pubkey;
+}
+
+unsigned char * ndb_note_sig(struct ndb_note *note)
+{
+ return note->sig;
+}
+
+uint32_t ndb_note_created_at(struct ndb_note *note)
+{
+ return note->created_at;
+}
+
+uint32_t ndb_note_kind(struct ndb_note *note)
+{
+ return note->kind;
+}
+
+void _ndb_note_set_kind(struct ndb_note *note, uint32_t kind)
+{
+ note->kind = kind;
+}
+
+const char *ndb_note_content(struct ndb_note *note)
+{
+ return ndb_note_str(note, ¬e->content).str;
+}
+
+uint32_t ndb_note_content_length(struct ndb_note *note)
+{
+ return note->content_length;
+}
+
+struct ndb_note * ndb_note_from_bytes(unsigned char *bytes)
+{
+ struct ndb_note *note = (struct ndb_note *)bytes;
+ if (note->version != 1)
+ return 0;
+ return note;
+}
+
+void ndb_tags_iterate_start(struct ndb_note *note, struct ndb_iterator *iter)
+{
+ iter->note = note;
+ iter->tag = NULL;
+ iter->index = -1;
+}
+
+int ndb_tags_iterate_next(struct ndb_iterator *iter)
+{
+ if (iter->tag == NULL || iter->index == -1) {
+ iter->tag = iter->note->tags.tag;
+ iter->index = 0;
+ return iter->note->tags.count != 0;
+ }
+
+ struct ndb_tags *tags = &iter->note->tags;
+
+ if (++iter->index < tags->count) {
+ uint32_t tag_data_size = iter->tag->count * sizeof(iter->tag->strs[0]);
+ iter->tag = (struct ndb_tag *)(iter->tag->strs[0].bytes + tag_data_size);
+ return 1;
+ }
+
+ return 0;
+}
+
+uint16_t ndb_tags_count(struct ndb_tags *tags)
+{
+ return tags->count;
+}
+
+uint16_t ndb_tag_count(struct ndb_tag *tags)
+{
+ return tags->count;
+}
+
+enum ndb_common_kind ndb_kind_to_common_kind(int kind)
+{
+ switch (kind)
+ {
+ case 0: return NDB_CKIND_PROFILE;
+ case 1: return NDB_CKIND_TEXT;
+ case 3: return NDB_CKIND_CONTACTS;
+ case 4: return NDB_CKIND_DM;
+ case 5: return NDB_CKIND_DELETE;
+ case 6: return NDB_CKIND_REPOST;
+ case 7: return NDB_CKIND_REACTION;
+ case 9735: return NDB_CKIND_ZAP;
+ case 9734: return NDB_CKIND_ZAP_REQUEST;
+ case 23194: return NDB_CKIND_NWC_REQUEST;
+ case 23195: return NDB_CKIND_NWC_RESPONSE;
+ case 27235: return NDB_CKIND_HTTP_AUTH;
+ case 30000: return NDB_CKIND_LIST;
+ case 30023: return NDB_CKIND_LONGFORM;
+ case 30315: return NDB_CKIND_STATUS;
+ }
+
+ return -1;
+}
+
+const char *ndb_kind_name(enum ndb_common_kind ck)
+{
+ switch (ck) {
+ case NDB_CKIND_PROFILE: return "profile";
+ case NDB_CKIND_TEXT: return "text";
+ case NDB_CKIND_CONTACTS: return "contacts";
+ case NDB_CKIND_DM: return "dm";
+ case NDB_CKIND_DELETE: return "delete";
+ case NDB_CKIND_REPOST: return "repost";
+ case NDB_CKIND_REACTION: return "reaction";
+ case NDB_CKIND_ZAP: return "zap";
+ case NDB_CKIND_ZAP_REQUEST: return "zap_request";
+ case NDB_CKIND_NWC_REQUEST: return "nwc_request";
+ case NDB_CKIND_NWC_RESPONSE: return "nwc_response";
+ case NDB_CKIND_HTTP_AUTH: return "http_auth";
+ case NDB_CKIND_LIST: return "list";
+ case NDB_CKIND_LONGFORM: return "longform";
+ case NDB_CKIND_STATUS: return "status";
+ case NDB_CKIND_COUNT: return "unknown";
+ }
+
+ return "unknown";
+}
+
+const char *ndb_db_name(enum ndb_dbs db)
+{
+ switch (db) {
+ case NDB_DB_NOTE:
+ return "note";
+ case NDB_DB_META:
+ return "note_metadata";
+ case NDB_DB_PROFILE:
+ return "profile";
+ case NDB_DB_NOTE_ID:
+ return "note_index";
+ case NDB_DB_PROFILE_PK:
+ return "profile_pubkey_index";
+ case NDB_DB_NDB_META:
+ return "nostrdb_metadata";
+ case NDB_DB_PROFILE_SEARCH:
+ return "profile_search";
+ case NDB_DB_PROFILE_LAST_FETCH:
+ return "profile_last_fetch";
+ case NDB_DB_NOTE_KIND:
+ return "note_kind_index";
+ case NDB_DB_NOTE_TEXT:
+ return "note_fulltext";
+ case NDB_DBS:
+ return "count";
+ }
+
+ return "unknown";
+}
diff --git a/nostrdb/nostrdb.h b/nostrdb/nostrdb.h
@@ -20,70 +20,42 @@
struct ndb_json_parser;
struct ndb;
+struct ndb_note;
+struct ndb_tag;
+struct ndb_tags;
+struct ndb_lmdb;
+union ndb_packed_str;
// sorry, swift needs help with forward declared pointers like this
struct ndb_t {
struct ndb *ndb;
};
-struct ndb_search_key
-{
- char search[24];
- unsigned char id[32];
- uint64_t timestamp;
-};
-
-enum ndb_dbs {
- NDB_DB_NOTE,
- NDB_DB_META,
- NDB_DB_PROFILE,
- NDB_DB_NOTE_ID,
- NDB_DB_PROFILE_PK, // profile pk index
- NDB_DB_NDB_META,
- NDB_DB_PROFILE_SEARCH,
- NDB_DB_PROFILE_LAST_FETCH,
- NDB_DB_NOTE_KIND, // note kind index
- NDB_DB_NOTE_TEXT, // note fulltext index
- NDB_DBS,
-};
-
-// common kinds. we collect stats on these in ndb_stat. mainly because I don't
-// want to deal with including a hashtable to the project.
-enum ndb_common_kind {
- NDB_CKIND_PROFILE,
- NDB_CKIND_TEXT,
- NDB_CKIND_CONTACTS,
- NDB_CKIND_DM,
- NDB_CKIND_DELETE,
- NDB_CKIND_REPOST,
- NDB_CKIND_REACTION,
- NDB_CKIND_ZAP,
- NDB_CKIND_ZAP_REQUEST,
- NDB_CKIND_NWC_REQUEST,
- NDB_CKIND_NWC_RESPONSE,
- NDB_CKIND_HTTP_AUTH,
- NDB_CKIND_LIST,
- NDB_CKIND_LONGFORM,
- NDB_CKIND_STATUS,
- NDB_CKIND_COUNT, // should always be last
+struct ndb_str {
+ unsigned char flag;
+ union {
+ const char *str;
+ unsigned char *id;
+ };
};
-struct ndb_stat_counts {
- size_t key_size;
- size_t value_size;
- size_t count;
+struct ndb_keypair {
+ unsigned char pubkey[32];
+ unsigned char secret[32];
+
+ // this corresponds to secp256k1's keypair type. it's guaranteed to
+ // be 96 bytes according to their docs. I don't want to depend on
+ // the secp256k1 header here so we just use raw bytes.
+ unsigned char pair[96];
};
-struct ndb_stat {
- struct ndb_stat_counts dbs[NDB_DBS];
- struct ndb_stat_counts common_kinds[NDB_CKIND_COUNT];
- struct ndb_stat_counts other_kinds;
-};
+// function pointer for controlling what to do after we parse an id
+typedef enum ndb_idres (*ndb_id_fn)(void *, const char *);
-struct ndb_search {
- struct ndb_search_key *key;
- uint64_t profile_key;
- void *cursor; // MDB_cursor *
+// id callback + closure data
+struct ndb_id_cb {
+ ndb_id_fn fn;
+ void *data;
};
// required to keep a read
@@ -92,6 +64,16 @@ struct ndb_txn {
void *mdb_txn;
};
+struct ndb_event {
+ struct ndb_note *note;
+};
+
+struct ndb_command_result {
+ int ok;
+ const char *msg;
+ int msglen;
+};
+
// From-client event types
enum fce_type {
NDB_FCE_EVENT = 0x1
@@ -112,34 +94,19 @@ enum ndb_ingest_filter_action {
NDB_INGEST_SKIP_VALIDATION
};
-// function pointer for controlling what to do after we parse an id
-typedef enum ndb_idres (*ndb_id_fn)(void *, const char *);
-
-// id callback + closure data
-struct ndb_id_cb {
- ndb_id_fn fn;
- void *data;
-};
-
-struct ndb_str {
- unsigned char flag;
- union {
- const char *str;
- unsigned char *id;
- };
-};
-
-struct ndb_event {
- struct ndb_note *note;
+struct ndb_search_key
+{
+ char search[24];
+ unsigned char id[32];
+ uint64_t timestamp;
};
-struct ndb_command_result {
- int ok;
- const char *msg;
- int msglen;
+struct ndb_search {
+ struct ndb_search_key *key;
+ uint64_t profile_key;
+ void *cursor; // MDB_cursor *
};
-
// From-client event
struct ndb_fce {
enum fce_type evtype;
@@ -160,88 +127,67 @@ struct ndb_tce {
};
};
-struct ndb_keypair {
- unsigned char pubkey[32];
- unsigned char secret[32];
-
- // this corresponds to secp256k1's keypair type. it's guaranteed to
- // be 96 bytes according to their docs. I don't want to depend on
- // the secp256k1 header here so we just use raw bytes.
- unsigned char pair[96];
-};
-
-#define MAX_TEXT_SEARCH_RESULTS 128
-#define MAX_TEXT_SEARCH_WORDS 8
-
-// unpacked form of the actual lmdb fulltext search key
-// see `ndb_make_text_search_key` for how the packed version is constructed
-struct ndb_text_search_key
-{
- int str_len;
- const char *str;
- uint64_t timestamp;
- uint64_t note_id;
- int word_index;
-};
-
-struct ndb_text_search_result {
- struct ndb_text_search_key key;
- int prefix_chars;
-};
+typedef enum ndb_ingest_filter_action (*ndb_ingest_filter_fn)(void *, struct ndb_note *);
-struct ndb_text_search_results {
- struct ndb_text_search_result results[MAX_TEXT_SEARCH_RESULTS];
- int num_results;
+enum ndb_filter_fieldtype {
+ NDB_FILTER_IDS = 1,
+ NDB_FILTER_AUTHORS = 2,
+ NDB_FILTER_KINDS = 3,
+ NDB_FILTER_GENERIC = 4,
+ NDB_FILTER_SINCE = 5,
+ NDB_FILTER_UNTIL = 6,
+ NDB_FILTER_LIMIT = 7,
};
+#define NDB_NUM_FILTERS 7
-// these must be byte-aligned, they are directly accessing the serialized data
-// representation
-#pragma pack(push, 1)
-
-
-union ndb_packed_str {
- struct {
- char str[3];
- // we assume little endian everywhere. sorry not sorry.
- unsigned char flag; // NDB_PACKED_STR, etc
- } packed;
-
- uint32_t offset;
- unsigned char bytes[4];
+// when matching generic tags, we need to know if we're dealing with
+// a pointer to a 32-byte ID or a null terminated string
+enum ndb_generic_element_type {
+ NDB_ELEMENT_UNKNOWN = 0,
+ NDB_ELEMENT_STRING = 1,
+ NDB_ELEMENT_ID = 2,
};
-struct ndb_tag {
- uint16_t count;
- union ndb_packed_str strs[0];
+enum ndb_search_order {
+ NDB_ORDER_DESCENDING,
+ NDB_ORDER_ASCENDING,
};
-struct ndb_tags {
- uint16_t padding;
- uint16_t count;
- struct ndb_tag tag[0];
+enum ndb_dbs {
+ NDB_DB_NOTE,
+ NDB_DB_META,
+ NDB_DB_PROFILE,
+ NDB_DB_NOTE_ID,
+ NDB_DB_PROFILE_PK, // profile pk index
+ NDB_DB_NDB_META,
+ NDB_DB_PROFILE_SEARCH,
+ NDB_DB_PROFILE_LAST_FETCH,
+ NDB_DB_NOTE_KIND, // note kind index
+ NDB_DB_NOTE_TEXT, // note fulltext index
+ NDB_DBS,
};
-// v1
-struct ndb_note {
- unsigned char version; // v=1
- unsigned char padding[3]; // keep things aligned
- unsigned char id[32];
- unsigned char pubkey[32];
- unsigned char sig[64];
-
- uint64_t created_at;
- uint32_t kind;
- uint32_t content_length;
- union ndb_packed_str content;
- uint32_t strings;
- // nothing can come after tags since it contains variadic data
- struct ndb_tags tags;
+// common kinds. we collect stats on these in ndb_stat. mainly because I don't
+// want to deal with including a hashtable to the project.
+enum ndb_common_kind {
+ NDB_CKIND_PROFILE,
+ NDB_CKIND_TEXT,
+ NDB_CKIND_CONTACTS,
+ NDB_CKIND_DM,
+ NDB_CKIND_DELETE,
+ NDB_CKIND_REPOST,
+ NDB_CKIND_REACTION,
+ NDB_CKIND_ZAP,
+ NDB_CKIND_ZAP_REQUEST,
+ NDB_CKIND_NWC_REQUEST,
+ NDB_CKIND_NWC_RESPONSE,
+ NDB_CKIND_HTTP_AUTH,
+ NDB_CKIND_LIST,
+ NDB_CKIND_LONGFORM,
+ NDB_CKIND_STATUS,
+ NDB_CKIND_COUNT, // should always be last
};
-#pragma pack(pop)
-
-typedef enum ndb_ingest_filter_action (*ndb_ingest_filter_fn)(void *, struct ndb_note *);
-
struct ndb_builder {
struct cursor mem;
struct cursor note_cur;
@@ -259,30 +205,6 @@ struct ndb_iterator {
int index;
};
-enum ndb_filter_fieldtype {
- NDB_FILTER_IDS = 1,
- NDB_FILTER_AUTHORS = 2,
- NDB_FILTER_KINDS = 3,
- NDB_FILTER_GENERIC = 4,
- NDB_FILTER_SINCE = 5,
- NDB_FILTER_UNTIL = 6,
- NDB_FILTER_LIMIT = 7,
-};
-#define NDB_NUM_FILTERS 7
-
-// when matching generic tags, we need to know if we're dealing with
-// a pointer to a 32-byte ID or a null terminated string
-enum ndb_generic_element_type {
- NDB_ELEMENT_UNKNOWN = 0,
- NDB_ELEMENT_STRING = 1,
- NDB_ELEMENT_ID = 2,
-};
-
-enum ndb_search_order {
- NDB_ORDER_DESCENDING,
- NDB_ORDER_ASCENDING,
-};
-
union ndb_filter_element {
const char *string;
const unsigned char *id;
@@ -322,6 +244,43 @@ struct ndb_text_search_config {
int limit;
};
+struct ndb_stat_counts {
+ size_t key_size;
+ size_t value_size;
+ size_t count;
+};
+
+struct ndb_stat {
+ struct ndb_stat_counts dbs[NDB_DBS];
+ struct ndb_stat_counts common_kinds[NDB_CKIND_COUNT];
+ struct ndb_stat_counts other_kinds;
+};
+
+#define MAX_TEXT_SEARCH_RESULTS 128
+#define MAX_TEXT_SEARCH_WORDS 8
+
+// unpacked form of the actual lmdb fulltext search key
+// see `ndb_make_text_search_key` for how the packed version is constructed
+struct ndb_text_search_key
+{
+ int str_len;
+ const char *str;
+ uint64_t timestamp;
+ uint64_t note_id;
+ int word_index;
+};
+
+struct ndb_text_search_result {
+ struct ndb_text_search_key key;
+ int prefix_chars;
+};
+
+struct ndb_text_search_results {
+ struct ndb_text_search_result results[MAX_TEXT_SEARCH_RESULTS];
+ int num_results;
+};
+
+
// CONFIG
void ndb_default_config(struct ndb_config *);
void ndb_config_set_ingest_threads(struct ndb_config *config, int threads);
@@ -386,7 +345,7 @@ int ndb_filter_start_generic_field(struct ndb_filter *, char tag);
int ndb_filter_matches(struct ndb_filter *, struct ndb_note *);
void ndb_filter_reset(struct ndb_filter *);
void ndb_filter_end_field(struct ndb_filter *);
-void ndb_filter_free(struct ndb_filter *filter);
+void ndb_filter_free(struct ndb_filter *);
// FULLTEXT SEARCH
int ndb_text_search(struct ndb_txn *txn, const char *query, struct ndb_text_search_results *, struct ndb_text_search_config *);
@@ -394,214 +353,35 @@ void ndb_default_text_search_config(struct ndb_text_search_config *);
void ndb_text_search_config_set_order(struct ndb_text_search_config *, enum ndb_search_order);
void ndb_text_search_config_set_limit(struct ndb_text_search_config *, int limit);
-// stats
+// STATS
int ndb_stat(struct ndb *ndb, struct ndb_stat *stat);
void ndb_stat_counts_init(struct ndb_stat_counts *counts);
-static inline struct ndb_str ndb_note_str(struct ndb_note *note,
- union ndb_packed_str *pstr)
-{
- struct ndb_str str;
- str.flag = pstr->packed.flag;
-
- if (str.flag == NDB_PACKED_STR) {
- str.str = pstr->packed.str;
- return str;
- }
-
- str.str = ((const char *)note) + note->strings + (pstr->offset & 0xFFFFFF);
- return str;
-}
-
-static inline struct ndb_str ndb_tag_str(struct ndb_note *note,
- struct ndb_tag *tag, int ind)
-{
- return ndb_note_str(note, &tag->strs[ind]);
-}
-
-static inline struct ndb_str ndb_iter_tag_str(struct ndb_iterator *iter,
- int ind)
-{
- return ndb_tag_str(iter->note, iter->tag, ind);
-}
-
-static inline unsigned char * ndb_note_id(struct ndb_note *note)
-{
- return note->id;
-}
-
-static inline unsigned char * ndb_note_pubkey(struct ndb_note *note)
-{
- return note->pubkey;
-}
-
-static inline unsigned char * ndb_note_sig(struct ndb_note *note)
-{
- return note->sig;
-}
-
-static inline uint32_t ndb_note_created_at(struct ndb_note *note)
-{
- return note->created_at;
-}
-
-static inline uint32_t ndb_note_kind(struct ndb_note *note)
-{
- return note->kind;
-}
-
-static inline const char *ndb_note_content(struct ndb_note *note)
-{
- return ndb_note_str(note, ¬e->content).str;
-}
-
-static inline uint32_t ndb_note_content_length(struct ndb_note *note)
-{
- return note->content_length;
-}
-
-static inline struct ndb_note * ndb_note_from_bytes(unsigned char *bytes)
-{
- struct ndb_note *note = (struct ndb_note *)bytes;
- if (note->version != 1)
- return 0;
- return note;
-}
-
-static inline union ndb_packed_str ndb_offset_str(uint32_t offset)
-{
- // ensure accidents like -1 don't corrupt our packed_str
- union ndb_packed_str str;
- // most significant byte is reserved for ndb_packtype
- str.offset = offset & 0xFFFFFF;
- return str;
-}
-
-static inline union ndb_packed_str ndb_char_to_packed_str(char c)
-{
- union ndb_packed_str str;
- str.packed.flag = NDB_PACKED_STR;
- str.packed.str[0] = c;
- str.packed.str[1] = '\0';
- return str;
-}
-
-static inline union ndb_packed_str ndb_chars_to_packed_str(char c1, char c2)
-{
- union ndb_packed_str str;
- str.packed.flag = NDB_PACKED_STR;
- str.packed.str[0] = c1;
- str.packed.str[1] = c2;
- str.packed.str[2] = '\0';
- return str;
-}
-
-static inline void ndb_tags_iterate_start(struct ndb_note *note,
- struct ndb_iterator *iter)
-{
- iter->note = note;
- iter->tag = NULL;
- iter->index = -1;
-}
-
-static inline int ndb_tags_iterate_next(struct ndb_iterator *iter)
-{
- if (iter->tag == NULL || iter->index == -1) {
- iter->tag = iter->note->tags.tag;
- iter->index = 0;
- return iter->note->tags.count != 0;
- }
-
- struct ndb_tags *tags = &iter->note->tags;
-
- if (++iter->index < tags->count) {
- uint32_t tag_data_size = iter->tag->count * sizeof(iter->tag->strs[0]);
- iter->tag = (struct ndb_tag *)(iter->tag->strs[0].bytes + tag_data_size);
- return 1;
- }
-
- return 0;
-}
-
-static inline enum ndb_common_kind
-ndb_kind_to_common_kind(int kind)
-{
- switch (kind)
- {
- case 0: return NDB_CKIND_PROFILE;
- case 1: return NDB_CKIND_TEXT;
- case 3: return NDB_CKIND_CONTACTS;
- case 4: return NDB_CKIND_DM;
- case 5: return NDB_CKIND_DELETE;
- case 6: return NDB_CKIND_REPOST;
- case 7: return NDB_CKIND_REACTION;
- case 9735: return NDB_CKIND_ZAP;
- case 9734: return NDB_CKIND_ZAP_REQUEST;
- case 23194: return NDB_CKIND_NWC_REQUEST;
- case 23195: return NDB_CKIND_NWC_RESPONSE;
- case 27235: return NDB_CKIND_HTTP_AUTH;
- case 30000: return NDB_CKIND_LIST;
- case 30023: return NDB_CKIND_LONGFORM;
- case 30315: return NDB_CKIND_STATUS;
- }
-
- return -1;
-}
-
-static inline const char *
-ndb_kind_name(enum ndb_common_kind ck)
-{
- switch (ck) {
- case NDB_CKIND_PROFILE: return "profile";
- case NDB_CKIND_TEXT: return "text";
- case NDB_CKIND_CONTACTS: return "contacts";
- case NDB_CKIND_DM: return "dm";
- case NDB_CKIND_DELETE: return "delete";
- case NDB_CKIND_REPOST: return "repost";
- case NDB_CKIND_REACTION: return "reaction";
- case NDB_CKIND_ZAP: return "zap";
- case NDB_CKIND_ZAP_REQUEST: return "zap_request";
- case NDB_CKIND_NWC_REQUEST: return "nwc_request";
- case NDB_CKIND_NWC_RESPONSE: return "nwc_response";
- case NDB_CKIND_HTTP_AUTH: return "http_auth";
- case NDB_CKIND_LIST: return "list";
- case NDB_CKIND_LONGFORM: return "longform";
- case NDB_CKIND_STATUS: return "status";
- case NDB_CKIND_COUNT: return "unknown";
- }
-
- return "unknown";
-}
-
-static inline const char *
-ndb_db_name(enum ndb_dbs db)
-{
- switch (db) {
- case NDB_DB_NOTE:
- return "note";
- case NDB_DB_META:
- return "note_metadata";
- case NDB_DB_PROFILE:
- return "profile";
- case NDB_DB_NOTE_ID:
- return "note_index";
- case NDB_DB_PROFILE_PK:
- return "profile_pubkey_index";
- case NDB_DB_NDB_META:
- return "nostrdb_metadata";
- case NDB_DB_PROFILE_SEARCH:
- return "profile_search";
- case NDB_DB_PROFILE_LAST_FETCH:
- return "profile_last_fetch";
- case NDB_DB_NOTE_KIND:
- return "note_kind_index";
- case NDB_DB_NOTE_TEXT:
- return "note_fulltext";
- case NDB_DBS:
- return "count";
- }
-
- return "unknown";
-}
+// NOTE
+const char *ndb_note_content(struct ndb_note *note);
+struct ndb_str ndb_note_str(struct ndb_note *note, union ndb_packed_str *pstr);
+uint32_t ndb_note_content_length(struct ndb_note *note);
+uint32_t ndb_note_created_at(struct ndb_note *note);
+uint32_t ndb_note_kind(struct ndb_note *note);
+unsigned char *ndb_note_id(struct ndb_note *note);
+unsigned char *ndb_note_pubkey(struct ndb_note *note);
+unsigned char *ndb_note_sig(struct ndb_note *note);
+void _ndb_note_set_kind(struct ndb_note *note, uint32_t kind);
+struct ndb_tags *ndb_note_tags(struct ndb_note *note);
+
+// TAGS
+void ndb_tags_iterate_start(struct ndb_note *note, struct ndb_iterator *iter);
+uint16_t ndb_tags_count(struct ndb_tags *);
+uint16_t ndb_tag_count(struct ndb_tag *);
+
+// ITER
+int ndb_tags_iterate_next(struct ndb_iterator *iter);
+struct ndb_str ndb_iter_tag_str(struct ndb_iterator *iter, int ind);
+struct ndb_str ndb_tag_str(struct ndb_note *note, struct ndb_tag *tag, int ind);
+
+// NAMES
+const char *ndb_db_name(enum ndb_dbs db);
+const char *ndb_kind_name(enum ndb_common_kind ck);
+enum ndb_common_kind ndb_kind_to_common_kind(int kind);
#endif