nostrdb

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

nostrdb.h (20418B)


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