damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

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:
Mnostrdb/nostrdb.c | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mnostrdb/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 &note->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, &note->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, &note->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