nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

nostrdb.h (24354B)


      1 #ifndef NOSTRDB_H
      2 #define NOSTRDB_H
      3 
      4 #include <inttypes.h>
      5 #include <stdbool.h>
      6 #include "win.h"
      7 #include "cursor.h"
      8 
      9 /* static assert helper */
     10 #define STATIC_ASSERT(cond, msg) typedef char static_assert_##msg[(cond) ? 1 : -1]
     11 /* #define STATIC_ASSERT(cond, msg)  */
     12 
     13 // maximum number of filters allowed in a filter group
     14 #define NDB_PACKED_STR     0x1
     15 #define NDB_PACKED_ID      0x2
     16 
     17 #define NDB_FLAG_NOMIGRATE        (1 << 0)
     18 #define NDB_FLAG_SKIP_NOTE_VERIFY (1 << 1)
     19 #define NDB_FLAG_NO_FULLTEXT      (1 << 2)
     20 #define NDB_FLAG_NO_NOTE_BLOCKS   (1 << 3)
     21 #define NDB_FLAG_NO_STATS         (1 << 4)
     22 
     23 //#define DEBUG 1
     24 
     25 #ifdef NDB_LOG
     26 #define ndb_debug(...) printf(__VA_ARGS__)
     27 #else
     28 #define ndb_debug(...) (void)0
     29 #endif
     30 
     31 #include "str_block.h"
     32 
     33 struct ndb_json_parser;
     34 struct ndb;
     35 struct ndb_blocks;
     36 struct ndb_block;
     37 struct ndb_note;
     38 struct ndb_tag;
     39 struct ndb_tags;
     40 struct ndb_lmdb;
     41 struct ndb_note_meta;
     42 struct ndb_note_meta_entry;
     43 struct ndb_note_meta_builder;
     44 union ndb_packed_str;
     45 struct bolt11;
     46 
     47 /* Types, standard types are multiplied by 2, since odd types are user defined.
     48  * We explicitly multiply by two in the enum to be unambiguous
     49  */
     50 enum ndb_metadata_type {
     51     NDB_NOTE_META_RESERVED = 0, /* not used */
     52     NDB_NOTE_META_COUNTS   = 100, /* replies, quotes, etc */
     53     NDB_NOTE_META_REACTION = 200, /* count of all the reactions on a post, grouped by different reaction strings */
     54 };
     55 
     56 // some bindings like swift needs help with forward declared pointers
     57 struct ndb_tag_ptr { struct ndb_tag *ptr; };
     58 struct ndb_tags_ptr { struct ndb_tags *ptr; };
     59 struct ndb_block_ptr { struct ndb_block *ptr; };
     60 struct ndb_blocks_ptr { struct ndb_blocks *ptr; };
     61 struct ndb_note_ptr { struct ndb_note *ptr; };
     62 
     63 struct ndb_t {
     64 	struct ndb *ndb;
     65 };
     66 
     67 /* Compact reaction strings for the metadata table.
     68  *
     69  * We compact all emojis into 64bits using binmojis (github.com/jb55/binmoji)
     70  *
     71  * 6-byte non-emoji strings are also supported in the same memory layout. This
     72  * is achieved by reserving the LSB byte of the compact string, which overlaps
     73  * with the binmojis user flag bit. If this flag is set, then we know its not
     74  * really a bitmoji, its a compact string.
     75  */
     76 union ndb_reaction_str {
     77 	uint64_t binmoji;
     78 	struct {
     79 		/* flag is at LSB, which aligns with our binmoji user flag */
     80 		uint8_t flag;
     81 		char str[7];
     82 	} packed;
     83 };
     84 STATIC_ASSERT(sizeof(union ndb_reaction_str) == 8, reaction_string_must_be_8_bytes);
     85 
     86 /* An ndb_note_meta builder. Maintains a cursor of a fixed sized buffer while adding
     87  * metadata entries.
     88  *
     89  */
     90 struct ndb_note_meta_builder {
     91 	struct cursor cursor;
     92 };
     93 
     94 struct ndb_str {
     95 	// NDB_PACKED_STR, NDB_PACKED_ID
     96 	unsigned char flag;
     97 	union {
     98 		const char *str;
     99 		unsigned char *id;
    100 	};
    101 };
    102 
    103 struct ndb_ingest_meta {
    104 	unsigned client;
    105 	const char *relay;
    106 };
    107 
    108 struct ndb_keypair {
    109 	unsigned char pubkey[32];
    110 	unsigned char secret[32];
    111 	
    112 	// this corresponds to secp256k1's keypair type. it's guaranteed to
    113 	// be 96 bytes according to their docs. I don't want to depend on
    114 	// the secp256k1 header here so we just use raw bytes.
    115 	unsigned char pair[96];
    116 };
    117 
    118 // function pointer for controlling what to do after we parse an id
    119 typedef enum ndb_idres (*ndb_id_fn)(void *, const char *);
    120 
    121 // callback function for when we receive new subscription results
    122 typedef void (*ndb_sub_fn)(void *, uint64_t subid);
    123 
    124 // id callback + closure data
    125 struct ndb_id_cb {
    126 	ndb_id_fn fn;
    127 	void *data;
    128 };
    129 
    130 // required to keep a read 
    131 struct ndb_txn {
    132 	struct ndb_lmdb *lmdb;
    133 	void *mdb_txn;
    134 };
    135 
    136 struct ndb_event {
    137 	struct ndb_note *note;
    138 };
    139 
    140 struct ndb_command_result {
    141 	int ok;
    142 	const char *msg;
    143 	int msglen;
    144 };
    145 
    146 // From-client event types
    147 enum fce_type {
    148 	NDB_FCE_EVENT = 0x1
    149 };
    150 
    151 // To-client event types
    152 enum tce_type {
    153 	NDB_TCE_EVENT  = 0x1,
    154 	NDB_TCE_OK     = 0x2,
    155 	NDB_TCE_NOTICE = 0x3,
    156 	NDB_TCE_EOSE   = 0x4,
    157 	NDB_TCE_AUTH   = 0x5,
    158 };
    159 
    160 enum ndb_ingest_filter_action {
    161 	NDB_INGEST_REJECT,
    162 	NDB_INGEST_ACCEPT,
    163 	NDB_INGEST_SKIP_VALIDATION
    164 };
    165 
    166 struct ndb_search_key
    167 {
    168 	char search[24];
    169 	unsigned char id[32];
    170 	uint64_t timestamp;
    171 };
    172 
    173 struct ndb_search {
    174 	struct ndb_search_key *key;
    175 	uint64_t profile_key;
    176 	void *cursor; // MDB_cursor *
    177 };
    178 
    179 // From-client event
    180 struct ndb_fce {
    181 	enum fce_type evtype;
    182 	union {
    183 		struct ndb_event event;
    184 	};
    185 };
    186 
    187 // To-client event
    188 struct ndb_tce {
    189 	enum tce_type evtype;
    190 	const char *subid;
    191 	int subid_len;
    192 
    193 	union {
    194 		struct ndb_event event;
    195 		struct ndb_command_result command_result;
    196 	};
    197 };
    198 
    199 typedef enum ndb_ingest_filter_action (*ndb_ingest_filter_fn)(void *, struct ndb_note *);
    200 
    201 enum ndb_filter_fieldtype {
    202 	NDB_FILTER_IDS     = 1,
    203 	NDB_FILTER_AUTHORS = 2,
    204 	NDB_FILTER_KINDS   = 3,
    205 	NDB_FILTER_TAGS    = 4,
    206 	NDB_FILTER_SINCE   = 5,
    207 	NDB_FILTER_UNTIL   = 6,
    208 	NDB_FILTER_LIMIT   = 7,
    209 	NDB_FILTER_SEARCH  = 8,
    210 	NDB_FILTER_RELAYS  = 9,
    211 	NDB_FILTER_CUSTOM  = 10,
    212 };
    213 #define NDB_NUM_FILTERS 10
    214 
    215 // when matching generic tags, we need to know if we're dealing with
    216 // a pointer to a 32-byte ID or a null terminated string
    217 enum ndb_generic_element_type {
    218 	NDB_ELEMENT_UNKNOWN = 0,
    219 	NDB_ELEMENT_STRING  = 1,
    220 	NDB_ELEMENT_ID      = 2,
    221 	NDB_ELEMENT_INT     = 3,
    222 	NDB_ELEMENT_CUSTOM  = 4,
    223 };
    224 
    225 enum ndb_search_order {
    226 	NDB_ORDER_DESCENDING,
    227 	NDB_ORDER_ASCENDING,
    228 };
    229 
    230 enum ndb_dbs {
    231 	NDB_DB_NOTE,
    232 	NDB_DB_META,
    233 	NDB_DB_PROFILE,
    234 	NDB_DB_NOTE_ID,
    235 	NDB_DB_PROFILE_PK, // profile pk index
    236 	NDB_DB_NDB_META,
    237 	NDB_DB_PROFILE_SEARCH,
    238 	NDB_DB_PROFILE_LAST_FETCH,
    239 	NDB_DB_NOTE_KIND, // note kind index
    240 	NDB_DB_NOTE_TEXT, // note fulltext index
    241 	NDB_DB_NOTE_BLOCKS, // parsed note blocks for rendering
    242 	NDB_DB_NOTE_TAGS,  // note tags index
    243 	NDB_DB_NOTE_PUBKEY, // note pubkey index
    244 	NDB_DB_NOTE_PUBKEY_KIND, // note pubkey kind index
    245 	NDB_DB_NOTE_RELAY_KIND, // relay+kind+created -> note_id
    246 	NDB_DB_NOTE_RELAYS, // note_id -> relays
    247 	NDB_DBS,
    248 };
    249 
    250 // common kinds. we collect stats on these in ndb_stat. mainly because I don't
    251 // want to deal with including a hashtable to the project.
    252 enum ndb_common_kind {
    253 	NDB_CKIND_PROFILE,
    254 	NDB_CKIND_TEXT,
    255 	NDB_CKIND_CONTACTS,
    256 	NDB_CKIND_DM,
    257 	NDB_CKIND_DELETE,
    258 	NDB_CKIND_REPOST,
    259 	NDB_CKIND_REACTION,
    260 	NDB_CKIND_ZAP,
    261 	NDB_CKIND_ZAP_REQUEST,
    262 	NDB_CKIND_NWC_REQUEST,
    263 	NDB_CKIND_NWC_RESPONSE,
    264 	NDB_CKIND_HTTP_AUTH,
    265 	NDB_CKIND_LIST,
    266 	NDB_CKIND_LONGFORM,
    267 	NDB_CKIND_STATUS,
    268 	NDB_CKIND_COUNT, // should always be last
    269 };
    270 
    271 struct ndb_builder {
    272 	struct cursor mem;
    273 	struct cursor note_cur;
    274 	struct cursor strings;
    275 	struct cursor str_indices;
    276 	struct ndb_note *note;
    277 	struct ndb_tag *current_tag;
    278 };
    279 
    280 struct ndb_note_relay_iterator {
    281 	struct ndb_txn *txn;
    282 	uint64_t note_key;
    283 	int cursor_op;
    284 	void *mdb_cur;
    285 };
    286 
    287 struct ndb_note_meta_iterator {
    288 	struct ndb_note_meta *header;
    289 	struct ndb_note_meta *cur;
    290 
    291 	// current outer index
    292 	int index;
    293 };
    294 
    295 struct ndb_iterator {
    296 	struct ndb_note *note;
    297 	struct ndb_tag *tag;
    298 
    299 	// current outer index
    300 	int index;
    301 };
    302 
    303 struct ndb_filter_string {
    304 	const char *string;
    305 	int len;
    306 };
    307 
    308 typedef bool ndb_filter_callback_fn(void *, struct ndb_note *);
    309 
    310 struct ndb_filter_custom {
    311 	void *ctx;
    312 	ndb_filter_callback_fn *cb;
    313 };
    314 
    315 union ndb_filter_element {
    316 	struct ndb_filter_string string;
    317 	const unsigned char *id;
    318 	uint64_t integer;
    319 	struct ndb_filter_custom custom_filter;
    320 };
    321 
    322 struct ndb_filter_field {
    323 	enum ndb_filter_fieldtype type;
    324 	enum ndb_generic_element_type elem_type;
    325 	char tag; // for generic queries like #t
    326 };
    327 
    328 struct ndb_filter_elements {
    329 	struct ndb_filter_field field;
    330 	int count;
    331 
    332 	// this needs to be pointer size for reasons
    333 	// FIXME: what about on 32bit systems??
    334 	uint64_t elements[0];
    335 };
    336 
    337 struct ndb_filter {
    338 	struct cursor elem_buf;
    339 	struct cursor data_buf;
    340 	int num_elements;
    341 	int finalized;
    342 	int current;
    343 
    344 	// struct ndb_filter_elements offsets into elem_buf
    345 	//
    346 	// TODO(jb55): this should probably be called fields. elements are
    347 	// the things within fields
    348 	int elements[NDB_NUM_FILTERS]; 
    349 };
    350 
    351 struct ndb_config {
    352 	int flags;
    353 	int ingester_threads;
    354 	int writer_scratch_buffer_size;
    355 	size_t mapsize;
    356 	void *filter_context;
    357 	ndb_ingest_filter_fn ingest_filter;
    358 	void *sub_cb_ctx;
    359 	ndb_sub_fn sub_cb;
    360 };
    361 
    362 struct ndb_text_search_config {
    363 	enum ndb_search_order order;
    364 	int limit;
    365 };
    366 
    367 struct ndb_stat_counts {
    368 	size_t key_size;
    369 	size_t value_size;
    370 	size_t count;
    371 };
    372 
    373 struct ndb_stat {
    374 	struct ndb_stat_counts dbs[NDB_DBS];
    375 	struct ndb_stat_counts common_kinds[NDB_CKIND_COUNT];
    376 	struct ndb_stat_counts other_kinds;
    377 };
    378 
    379 #define MAX_TEXT_SEARCH_RESULTS 128
    380 #define MAX_TEXT_SEARCH_WORDS 8
    381 
    382 // unpacked form of the actual lmdb fulltext search key
    383 // see `ndb_make_text_search_key` for how the packed version is constructed
    384 struct ndb_text_search_key
    385 {
    386 	int str_len;
    387 	const char *str;
    388 	uint64_t timestamp;
    389 	uint64_t note_id;
    390 	uint64_t word_index;
    391 };
    392 
    393 struct ndb_text_search_result {
    394 	struct ndb_text_search_key key;
    395 	int prefix_chars;
    396 
    397 	// This is only set if we passed a filter for nip50 searches
    398 	struct ndb_note *note;
    399 	uint64_t note_size;
    400 };
    401 
    402 struct ndb_text_search_results {
    403 	struct ndb_text_search_result results[MAX_TEXT_SEARCH_RESULTS];
    404 	int num_results;
    405 };
    406 
    407 enum ndb_block_type {
    408     BLOCK_HASHTAG        = 1,
    409     BLOCK_TEXT           = 2,
    410     BLOCK_MENTION_INDEX  = 3,
    411     BLOCK_MENTION_BECH32 = 4,
    412     BLOCK_URL            = 5,
    413     BLOCK_INVOICE        = 6,
    414 };
    415 #define NDB_NUM_BLOCK_TYPES 6
    416 #define NDB_MAX_RELAYS 24
    417 
    418 struct ndb_relays {
    419 	struct ndb_str_block relays[NDB_MAX_RELAYS];
    420 	int num_relays;
    421 };
    422 
    423 enum nostr_bech32_type {
    424 	NOSTR_BECH32_NOTE = 1,
    425 	NOSTR_BECH32_NPUB = 2,
    426 	NOSTR_BECH32_NPROFILE = 3,
    427 	NOSTR_BECH32_NEVENT = 4,
    428 	NOSTR_BECH32_NRELAY = 5,
    429 	NOSTR_BECH32_NADDR = 6,
    430 	NOSTR_BECH32_NSEC = 7,
    431 };
    432 #define NOSTR_BECH32_KNOWN_TYPES 7
    433 
    434 struct bech32_note {
    435 	const unsigned char *event_id;
    436 };
    437 
    438 struct bech32_npub {
    439 	const unsigned char *pubkey;
    440 };
    441 
    442 struct bech32_nsec {
    443 	const unsigned char *nsec;
    444 };
    445 
    446 struct bech32_nevent {
    447 	struct ndb_relays relays;
    448 	const unsigned char *event_id;
    449 	const unsigned char *pubkey; // optional
    450 };
    451 
    452 struct bech32_nprofile {
    453 	struct ndb_relays relays;
    454 	const unsigned char *pubkey;
    455 };
    456 
    457 struct bech32_naddr {
    458 	struct ndb_relays relays;
    459 	struct ndb_str_block identifier;
    460 	const unsigned char *pubkey;
    461 };
    462 
    463 struct bech32_nrelay {
    464 	struct ndb_str_block relay;
    465 };
    466 
    467 struct nostr_bech32 {
    468 	enum nostr_bech32_type type;
    469 
    470 	union {
    471 		struct bech32_note note;
    472 		struct bech32_npub npub;
    473 		struct bech32_nsec nsec;
    474 		struct bech32_nevent nevent;
    475 		struct bech32_nprofile nprofile;
    476 		struct bech32_naddr naddr;
    477 		struct bech32_nrelay nrelay;
    478 	};
    479 };
    480 
    481 
    482 struct ndb_mention_bech32_block {
    483 	struct ndb_str_block str;
    484 	struct nostr_bech32 bech32;
    485 };
    486 
    487 struct ndb_invoice {
    488 	unsigned char version;
    489 	uint64_t amount;
    490 	uint64_t timestamp;
    491 	uint64_t expiry;
    492 	char *description;
    493 	unsigned char *description_hash;
    494 };
    495 
    496 struct ndb_invoice_block {
    497 	struct ndb_str_block invstr;
    498 	struct ndb_invoice invoice;
    499 };
    500 
    501 struct ndb_block {
    502 	enum ndb_block_type type;
    503 	union {
    504 		struct ndb_str_block str;
    505 		struct ndb_invoice_block invoice;
    506 		struct ndb_mention_bech32_block mention_bech32;
    507 		uint32_t mention_index;
    508 	} block;
    509 };
    510 
    511 struct ndb_block_iterator {
    512 	const char *content;
    513 	struct ndb_blocks *blocks;
    514 	struct ndb_block block;
    515 	unsigned char *p;
    516 };
    517 
    518 struct ndb_query_result {
    519 	struct ndb_note *note;
    520 	uint64_t note_size;
    521 	uint64_t note_id;
    522 };
    523 
    524 struct ndb_query_results {
    525 	struct cursor cur;
    526 };
    527 
    528 // CONFIG
    529 void ndb_default_config(struct ndb_config *);
    530 void ndb_config_set_ingest_threads(struct ndb_config *config, int threads);
    531 void ndb_config_set_flags(struct ndb_config *config, int flags);
    532 void ndb_config_set_mapsize(struct ndb_config *config, size_t mapsize);
    533 void ndb_config_set_ingest_filter(struct ndb_config *config, ndb_ingest_filter_fn fn, void *);
    534 void ndb_config_set_subscription_callback(struct ndb_config *config, ndb_sub_fn fn, void *ctx);
    535 
    536 /// Configurable scratch buffer size for the writer thread. Default is 2MB. If you have smaller notes
    537 /// you can decrease this to reduce memory usage. If you have bigger notes you should increase this so
    538 /// that the writer thread can properly parse larger notes.
    539 void ndb_config_set_writer_scratch_buffer_size(struct ndb_config *config, int scratch_size);
    540 
    541 // HELPERS
    542 int ndb_calculate_id(struct ndb_note *note, unsigned char *buf, int buflen, unsigned char *id);
    543 int ndb_sign_id(struct ndb_keypair *keypair, unsigned char id[32], unsigned char sig[64]);
    544 int ndb_create_keypair(struct ndb_keypair *key);
    545 int ndb_decode_key(const char *secstr, struct ndb_keypair *keypair);
    546 int ndb_note_verify(void *secp_ctx, unsigned char *scratch, size_t scratch_size, struct ndb_note *note);
    547 
    548 // NDB
    549 int ndb_init(struct ndb **ndb, const char *dbdir, const struct ndb_config *);
    550 int ndb_db_version(struct ndb_txn *txn);
    551 
    552 // NOTE PROCESSING
    553 int ndb_process_event(struct ndb *, const char *json, int len);
    554 void ndb_ingest_meta_init(struct ndb_ingest_meta *meta, unsigned client, const char *relay);
    555 // Process an event, recording the relay where it came from.
    556 int ndb_process_event_with(struct ndb *, const char *json, int len, struct ndb_ingest_meta *meta);
    557 int ndb_process_events(struct ndb *, const char *ldjson, size_t len);
    558 int ndb_process_events_with(struct ndb *ndb, const char *ldjson, size_t json_len, struct ndb_ingest_meta *meta);
    559 #ifndef _WIN32
    560 // TODO: fix on windows
    561 int ndb_process_events_stream(struct ndb *, FILE* fp);
    562 #endif
    563 // deprecated: use ndb_ingest_event_with
    564 int ndb_process_client_event(struct ndb *, const char *json, int len);
    565 // deprecated: use ndb_ingest_events_with
    566 int ndb_process_client_events(struct ndb *, const char *json, size_t len);
    567 
    568 int ndb_begin_query(struct ndb *, struct ndb_txn *);
    569 int ndb_search_profile(struct ndb_txn *txn, struct ndb_search *search, const char *query);
    570 int ndb_search_profile_next(struct ndb_search *search);
    571 void ndb_search_profile_end(struct ndb_search *search);
    572 int ndb_end_query(struct ndb_txn *);
    573 int ndb_write_last_profile_fetch(struct ndb *ndb, const unsigned char *pubkey, uint64_t fetched_at);
    574 uint64_t ndb_read_last_profile_fetch(struct ndb_txn *txn, const unsigned char *pubkey);
    575 void *ndb_get_profile_by_pubkey(struct ndb_txn *txn, const unsigned char *pubkey, size_t *len, uint64_t *primkey);
    576 void *ndb_get_profile_by_key(struct ndb_txn *txn, uint64_t key, size_t *len);
    577 uint64_t ndb_get_notekey_by_id(struct ndb_txn *txn, const unsigned char *id);
    578 uint64_t ndb_get_profilekey_by_pubkey(struct ndb_txn *txn, const unsigned char *id);
    579 struct ndb_note *ndb_get_note_by_id(struct ndb_txn *txn, const unsigned char *id, size_t *len, uint64_t *primkey);
    580 struct ndb_note *ndb_get_note_by_key(struct ndb_txn *txn, uint64_t key, size_t *len);
    581 int ndb_note_seen_on_relay(struct ndb_txn *txn, uint64_t note_key, const char *relay);
    582 void ndb_destroy(struct ndb *);
    583 
    584 // BUILDER
    585 int ndb_parse_json_note(struct ndb_json_parser *, struct ndb_note **);
    586 int ndb_client_event_from_json(const char *json, int len, struct ndb_fce *fce, unsigned char *buf, int bufsize, struct ndb_id_cb *cb);
    587 int ndb_ws_event_from_json(const char *json, int len, struct ndb_tce *tce, unsigned char *buf, int bufsize, struct ndb_id_cb *);
    588 int ndb_note_from_json(const char *json, int len, struct ndb_note **, unsigned char *buf, int buflen);
    589 int ndb_builder_init(struct ndb_builder *builder, unsigned char *buf, size_t bufsize);
    590 int ndb_builder_finalize(struct ndb_builder *builder, struct ndb_note **note, struct ndb_keypair *privkey);
    591 int ndb_builder_set_content(struct ndb_builder *builder, const char *content, int len);
    592 void ndb_builder_set_created_at(struct ndb_builder *builder, uint64_t created_at);
    593 void ndb_builder_set_sig(struct ndb_builder *builder, unsigned char *sig);
    594 void ndb_builder_set_pubkey(struct ndb_builder *builder, unsigned char *pubkey);
    595 void ndb_builder_set_id(struct ndb_builder *builder, unsigned char *id);
    596 void ndb_builder_set_kind(struct ndb_builder *builder, uint32_t kind);
    597 int ndb_builder_new_tag(struct ndb_builder *builder);
    598 int ndb_builder_push_tag_str(struct ndb_builder *builder, const char *str, int len);
    599 int ndb_builder_push_tag_id(struct ndb_builder *builder, unsigned char *id);
    600 
    601 // FILTERS
    602 int ndb_filter_init(struct ndb_filter *);
    603 
    604 /// Allocate a filter with a fixed sized buffer (where pages is number of 4096-byte sized blocks)
    605 /// You can set pages to 1 if you know you are constructing small filters
    606 // TODO: replace this with passed-in buffers
    607 int ndb_filter_init_with(struct ndb_filter *filter, int pages);
    608 
    609 int ndb_filter_add_id_element(struct ndb_filter *, const unsigned char *id);
    610 int ndb_filter_add_int_element(struct ndb_filter *, uint64_t integer);
    611 int ndb_filter_add_str_element(struct ndb_filter *, const char *str);
    612 int ndb_filter_add_custom_filter_element(struct ndb_filter *filter, ndb_filter_callback_fn *cb, void *ctx);
    613 int ndb_filter_eq(const struct ndb_filter *, const struct ndb_filter *);
    614 
    615 /// is `a` a subset of `b`
    616 int ndb_filter_is_subset_of(const struct ndb_filter *a, const struct ndb_filter *b);
    617 
    618 // filters from json
    619 int ndb_filter_from_json(const char *, int len, struct ndb_filter *filter, unsigned char *buf, int bufsize);
    620 
    621 // getting field elements
    622 unsigned char *ndb_filter_get_id_element(const struct ndb_filter *, const struct ndb_filter_elements *, int index);
    623 const char *ndb_filter_get_string_element(const struct ndb_filter *, const struct ndb_filter_elements *, int index);
    624 uint64_t ndb_filter_get_int_element(const struct ndb_filter_elements *, int index);
    625 uint64_t *ndb_filter_get_int_element_ptr(struct ndb_filter_elements *, int index);
    626 
    627 struct ndb_filter_elements *ndb_filter_current_element(const struct ndb_filter *);
    628 struct ndb_filter_elements *ndb_filter_get_elements(const struct ndb_filter *, int);
    629 int ndb_filter_start_field(struct ndb_filter *, enum ndb_filter_fieldtype);
    630 int ndb_filter_start_tag_field(struct ndb_filter *, char tag);
    631 int ndb_filter_matches(struct ndb_filter *, struct ndb_note *);
    632 int ndb_filter_matches_with_relay(struct ndb_filter *, struct ndb_note *, struct ndb_note_relay_iterator *iter);
    633 int ndb_filter_clone(struct ndb_filter *dst, struct ndb_filter *src);
    634 int ndb_filter_end(struct ndb_filter *);
    635 void ndb_filter_end_field(struct ndb_filter *);
    636 void ndb_filter_destroy(struct ndb_filter *);
    637 int ndb_filter_json(const struct ndb_filter *, char *buf, int buflen);
    638 
    639 // SUBSCRIPTIONS
    640 uint64_t ndb_subscribe(struct ndb *, struct ndb_filter *, int num_filters);
    641 int ndb_wait_for_notes(struct ndb *, uint64_t subid, uint64_t *note_ids, int note_id_capacity);
    642 int ndb_poll_for_notes(struct ndb *, uint64_t subid, uint64_t *note_ids, int note_id_capacity);
    643 int ndb_unsubscribe(struct ndb *, uint64_t subid);
    644 int ndb_num_subscriptions(struct ndb *);
    645 
    646 // FULLTEXT SEARCH
    647 int ndb_text_search(struct ndb_txn *txn, const char *query, struct ndb_text_search_results *, struct ndb_text_search_config *);
    648 int ndb_text_search_with(struct ndb_txn *txn, const char *query, struct ndb_text_search_results *, struct ndb_text_search_config *, struct ndb_filter *filter);
    649 void ndb_default_text_search_config(struct ndb_text_search_config *);
    650 void ndb_text_search_config_set_order(struct ndb_text_search_config *, enum ndb_search_order);
    651 void ndb_text_search_config_set_limit(struct ndb_text_search_config *, int limit);
    652 
    653 // QUERY
    654 int ndb_query(struct ndb_txn *txn, struct ndb_filter *filters, int num_filters, struct ndb_query_result *results, int result_capacity, int *count);
    655 
    656 // NOTE METADATA
    657 int ndb_note_meta_builder_init(struct ndb_note_meta_builder *builder, unsigned char *, size_t);
    658 int ndb_set_note_meta(struct ndb *ndb, const unsigned char *id, struct ndb_note_meta *meta);
    659 size_t ndb_note_meta_total_size(struct ndb_note_meta *header);
    660 size_t ndb_note_meta_total_size(struct ndb_note_meta *meta);
    661 struct ndb_note_meta *ndb_get_note_meta(struct ndb_txn *txn, const unsigned char *id);
    662 struct ndb_note_meta_entry *ndb_note_meta_add_entry(struct ndb_note_meta_builder *builder);
    663 struct ndb_note_meta_entry *ndb_note_meta_builder_find_entry(struct ndb_note_meta_builder *builder, uint16_t type, uint64_t *payload);
    664 struct ndb_note_meta_entry *ndb_note_meta_entries(struct ndb_note_meta *meta);
    665 struct ndb_note_meta_entry *ndb_note_meta_entry_at(struct ndb_note_meta *meta, int ind);
    666 struct ndb_note_meta_entry *ndb_note_meta_find_entry(struct ndb_note_meta *meta, uint16_t type, uint64_t *payload);
    667 uint16_t *ndb_note_meta_counts_direct_replies(struct ndb_note_meta_entry *entry);
    668 uint16_t *ndb_note_meta_counts_quotes(struct ndb_note_meta_entry *entry);
    669 uint16_t *ndb_note_meta_counts_reposts(struct ndb_note_meta_entry *entry);
    670 uint16_t *ndb_note_meta_entry_type(struct ndb_note_meta_entry *entry);
    671 uint16_t ndb_note_meta_entries_count(struct ndb_note_meta *meta);
    672 uint32_t *ndb_note_meta_counts_thread_replies(struct ndb_note_meta_entry *entry);
    673 uint32_t *ndb_note_meta_counts_total_reactions(struct ndb_note_meta_entry *entry);
    674 uint32_t *ndb_note_meta_reaction_count(struct ndb_note_meta_entry *entry);
    675 uint64_t *ndb_note_meta_flags(struct ndb_note_meta *meta);
    676 void ndb_note_meta_build(struct ndb_note_meta_builder *builder, struct ndb_note_meta **meta);
    677 void ndb_note_meta_builder_resized(struct ndb_note_meta_builder *builder, unsigned char *buf, size_t bufsize);
    678 void ndb_note_meta_counts_set(struct ndb_note_meta_entry *entry, uint32_t total_reactions, uint16_t quotes, uint16_t direct_replies, uint32_t thread_replies, uint16_t reposts);
    679 void ndb_note_meta_header_init(struct ndb_note_meta *);
    680 void ndb_note_meta_reaction_set(struct ndb_note_meta_entry *entry, uint32_t count, union ndb_reaction_str str);
    681 void print_note_meta(struct ndb_note_meta *meta);
    682 
    683 // META STRINGS
    684 int ndb_reaction_set(union ndb_reaction_str *reaction, const char *str);
    685 int ndb_reaction_str_is_emoji(union ndb_reaction_str);
    686 const char *ndb_reaction_to_str(union ndb_reaction_str *str, char buf[128]);
    687 
    688 // STATS
    689 int ndb_stat(struct ndb *ndb, struct ndb_stat *stat);
    690 void ndb_stat_counts_init(struct ndb_stat_counts *counts);
    691 
    692 // NOTE
    693 const char *ndb_note_content(struct ndb_note *note);
    694 struct ndb_str ndb_note_str(struct ndb_note *note, union ndb_packed_str *pstr);
    695 uint32_t ndb_note_content_length(struct ndb_note *note);
    696 uint32_t ndb_note_created_at(struct ndb_note *note);
    697 uint32_t ndb_note_kind(struct ndb_note *note);
    698 unsigned char *ndb_note_id(struct ndb_note *note);
    699 unsigned char *ndb_note_pubkey(struct ndb_note *note);
    700 unsigned char *ndb_note_sig(struct ndb_note *note);
    701 void _ndb_note_set_kind(struct ndb_note *note, uint32_t kind);
    702 struct ndb_tags *ndb_note_tags(struct ndb_note *note);
    703 int ndb_str_len(struct ndb_str *str);
    704 
    705 /// write the note as json to a buffer
    706 int ndb_note_json(struct ndb_note *, char *buf, int buflen);
    707 
    708 // TAGS
    709 void ndb_tags_iterate_start(struct ndb_note *note, struct ndb_iterator *iter);
    710 uint16_t ndb_tags_count(struct ndb_tags *);
    711 uint16_t ndb_tag_count(struct ndb_tag *);
    712 
    713 // ITER
    714 int ndb_tags_iterate_next(struct ndb_iterator *iter);
    715 struct ndb_str ndb_iter_tag_str(struct ndb_iterator *iter, int ind);
    716 struct ndb_str ndb_tag_str(struct ndb_note *note, struct ndb_tag *tag, int ind);
    717 
    718 // RELAY ITER
    719 int ndb_note_relay_iterate_start(struct ndb_txn *txn, struct ndb_note_relay_iterator *iter, uint64_t note_key);
    720 const char *ndb_note_relay_iterate_next(struct ndb_note_relay_iterator *iter);
    721 void ndb_note_relay_iterate_close(struct ndb_note_relay_iterator *iter);
    722 
    723 // NAMES
    724 const char *ndb_db_name(enum ndb_dbs db);
    725 const char *ndb_kind_name(enum ndb_common_kind ck);
    726 enum ndb_common_kind ndb_kind_to_common_kind(int kind);
    727 
    728 // CONTENT PARSER
    729 int ndb_parse_content(unsigned char *buf, int buf_size,
    730 		      const char *content, int content_len,
    731 		      struct ndb_blocks **blocks_p);
    732 
    733 // BLOCKS
    734 enum ndb_block_type ndb_get_block_type(struct ndb_block *block);
    735 int ndb_blocks_flags(struct ndb_blocks *block);
    736 size_t ndb_blocks_total_size(struct ndb_blocks *blocks);
    737 int ndb_blocks_word_count(struct ndb_blocks *blocks);
    738 
    739 /// Free blocks if they are owned, safe to call on unowned blocks as well.
    740 void ndb_blocks_free(struct ndb_blocks *blocks);
    741 
    742 // BLOCK DB
    743 struct ndb_blocks *ndb_get_blocks_by_key(struct ndb *ndb, struct ndb_txn *txn, uint64_t note_key);
    744 
    745 // BLOCK ITERATORS
    746 void ndb_blocks_iterate_start(const char *, struct ndb_blocks *, struct ndb_block_iterator *);
    747 struct ndb_block *ndb_blocks_iterate_next(struct ndb_block_iterator *);
    748 
    749 // STR BLOCKS
    750 struct ndb_str_block *ndb_block_str(struct ndb_block *);
    751 const char *ndb_str_block_ptr(struct ndb_str_block *);
    752 uint32_t ndb_str_block_len(struct ndb_str_block *);
    753 
    754 // BECH32 BLOCKS
    755 struct nostr_bech32 *ndb_bech32_block(struct ndb_block *block);
    756 
    757 #endif