#ifndef LLARP_NODEDB_HPP #define LLARP_NODEDB_HPP #include #include #include #include #include #include #include #include #include /** * nodedb.hpp * * persistent storage API for router contacts */ namespace llarp { class Logic; } // namespace llarp struct llarp_nodedb { using DiskJob_t = std::function; using DiskCaller_t = std::function; using WorkJob_t = std::function; using WorkCaller_t = std::function; explicit llarp_nodedb(const std::string rootdir, DiskCaller_t diskCaller) : disk(std::move(diskCaller)), nodePath(rootdir) {} ~llarp_nodedb() { Clear(); } const DiskCaller_t disk; mutable llarp::util::Mutex access; // protects entries /// time for next save to disk event, 0 if never happened llarp_time_t m_NextSaveToDisk = 0s; /// how often to save to disk const llarp_time_t m_SaveInterval = 5min; struct NetDBEntry { const llarp::RouterContact rc; llarp_time_t inserted; NetDBEntry(llarp::RouterContact data); }; using NetDBMap_t = std::unordered_map; NetDBMap_t entries GUARDED_BY(access); fs::path nodePath; llarp::RouterContact FindClosestTo(const llarp::dht::Key_t& location); /// find the $numRouters closest routers to the given DHT key std::vector FindClosestTo(const llarp::dht::Key_t& location, uint32_t numRouters); /// return true if we should save our nodedb to disk bool ShouldSaveToDisk(llarp_time_t now = 0s) const; bool Remove(const llarp::RouterID& pk) EXCLUDES(access); void RemoveIf(std::function filter) EXCLUDES(access); void Clear() EXCLUDES(access); bool Get(const llarp::RouterID& pk, llarp::RouterContact& result) EXCLUDES(access); bool Has(const llarp::RouterID& pk) EXCLUDES(access); std::string getRCFilePath(const llarp::RouterID& pubkey) const; /// insert without writing to disk bool Insert(const llarp::RouterContact& rc) EXCLUDES(access); /// invokes Insert() asynchronously with an optional completion /// callback void InsertAsync( llarp::RouterContact rc, std::shared_ptr l = nullptr, std::function completionHandler = nullptr); /// update rc if newer /// return true if we started to put this rc in the database /// retur false if not newer bool UpdateAsyncIfNewer( llarp::RouterContact rc, std::shared_ptr l = nullptr, std::function completionHandler = nullptr) EXCLUDES(access); ssize_t Load(const fs::path& path); ssize_t loadSubdir(const fs::path& dir); /// save all entries to disk async void AsyncFlushToDisk(); bool loadfile(const fs::path& fpath) EXCLUDES(access); void visit(std::function visit) EXCLUDES(access); void set_dir(const char* dir); ssize_t LoadAll(); ssize_t store_dir(const char* dir); /// visit all entries inserted into nodedb cache before a timestamp void VisitInsertedBefore( std::function visit, llarp_time_t insertedAfter) EXCLUDES(access); void RemoveStaleRCs(const std::set& keep, llarp_time_t cutoff); size_t num_loaded() const EXCLUDES(access); bool select_random_exit(llarp::RouterContact& rc) EXCLUDES(access); bool select_random_hop_excluding( llarp::RouterContact& result, const std::set& exclude) EXCLUDES(access); /// Ensures that the given nodedb 'dir' exists /// /// @param nodedbDir should be the desired nodedb directory /// @throws on any filesistem error or if `nodedbDir` exists and is not a directory static void ensure_dir(const fs::path& nodedbDir); void SaveAll() EXCLUDES(access); }; /// struct for async rc verification struct llarp_async_verify_rc; using llarp_async_verify_rc_hook_func = std::function; /// verify rc request struct llarp_async_verify_rc { /// async_verify_context void* user; /// nodedb storage llarp_nodedb* nodedb; // llarp::Logic for queue_job std::shared_ptr logic; llarp_nodedb::WorkCaller_t worker; llarp_nodedb::DiskCaller_t disk; /// router contact llarp::RouterContact rc; /// result bool valid; /// hook llarp_async_verify_rc_hook_func hook; }; /** struct for async rc verification data is loaded in disk io threadpool crypto is done on the crypto worker threadpool result is called on the logic thread */ void llarp_nodedb_async_verify(struct llarp_async_verify_rc* job); struct llarp_async_load_rc; using llarp_async_load_rc_hook_func = std::function; struct llarp_async_load_rc { /// async_verify_context void* user; /// nodedb storage llarp_nodedb* nodedb; /// llarp::Logic for calling hook llarp::Logic* logic; /// disk worker threadpool llarp_nodedb::DiskCaller_t disk; /// target pubkey llarp::PubKey pubkey; /// router contact result llarp::RouterContact result; /// set to true if we loaded the rc bool loaded; /// hook function called in logic thread llarp_async_load_rc_hook_func hook; }; /// asynchronously load an rc from disk void llarp_nodedb_async_load_rc(struct llarp_async_load_rc* job); #endif