mirror of
https://github.com/lux-tel/libsession-util.git
synced 2026-10-30 20:25:11 +00:00
151 lines
5.6 KiB
C++
151 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <chrono>
|
|
#include <filesystem>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <vector>
|
|
|
|
#include "session/network/key_types.hpp"
|
|
#include "session/network/network_config.hpp"
|
|
#include "session/network/service_node.hpp"
|
|
#include "swarm.hpp"
|
|
|
|
namespace session::network {
|
|
|
|
namespace config {
|
|
struct SnodePool {
|
|
std::optional<std::filesystem::path> cache_directory;
|
|
std::optional<std::filesystem::path> fallback_snode_pool_path;
|
|
std::chrono::minutes cache_expiration;
|
|
std::chrono::milliseconds cache_min_lifetime;
|
|
bool enforce_subnet_diversity;
|
|
network::opt::retry_delay retry_delay;
|
|
|
|
opt::netid::Target netid;
|
|
std::vector<service_node> seed_nodes;
|
|
|
|
size_t cache_min_size;
|
|
size_t cache_min_swarm_size;
|
|
uint8_t cache_num_nodes_to_use_for_refresh;
|
|
uint8_t cache_min_num_refresh_presence_to_include_node;
|
|
uint16_t cache_node_strike_threshold;
|
|
};
|
|
} // namespace config
|
|
|
|
class empty_file_exception : public std::runtime_error {
|
|
public:
|
|
empty_file_exception() : std::runtime_error{"Empty file"} {}
|
|
};
|
|
|
|
class SnodePool : public std::enable_shared_from_this<SnodePool> {
|
|
public:
|
|
using network_fetcher_t = std::function<void(Request, network_response_callback_t)>;
|
|
using fetcher_connectivity_check_t = std::function<bool()>;
|
|
|
|
SnodePool(
|
|
config::SnodePool config,
|
|
std::shared_ptr<oxen::quic::Loop> loop,
|
|
std::shared_ptr<oxen::quic::Loop> disk_loop,
|
|
network_fetcher_t direct_fetcher);
|
|
~SnodePool() = default;
|
|
|
|
void suspend();
|
|
void resume();
|
|
|
|
// Sets the network fetcher which should be used once the snode cache exists
|
|
void set_routed_fetcher(
|
|
network_fetcher_t routed_fetcher, fetcher_connectivity_check_t connectivity_check);
|
|
|
|
// Returns the number of nodes currently in the pool
|
|
size_t size();
|
|
|
|
// Forcibly clears the cache from memory and disk
|
|
void clear_cache();
|
|
|
|
// Records that a specific node has failed a request
|
|
virtual void record_node_failure(const service_node& node, bool permanent = false);
|
|
virtual void record_node_failure(const ed25519_pubkey& key, bool permanent = false);
|
|
uint16_t node_strike_count(const service_node& node);
|
|
uint16_t node_strike_count(const ed25519_pubkey& key);
|
|
void clear_node_strikes();
|
|
|
|
// Checks if the pool is empty or stale and triggers a refresh if needed
|
|
virtual void refresh_if_needed(
|
|
const std::vector<service_node>& in_use_nodes,
|
|
std::function<void()> on_refresh_complete = nullptr);
|
|
|
|
virtual void get_swarm(
|
|
session::network::x25519_pubkey swarm_pubkey,
|
|
bool ignore_strike_count,
|
|
std::function<void(swarm::swarm_id_t, std::vector<service_node>)> callback);
|
|
|
|
virtual std::vector<service_node> get_unused_nodes(
|
|
size_t count, const std::vector<service_node>& exclude = {});
|
|
|
|
private:
|
|
friend class TestSnodePool;
|
|
|
|
bool _suspended = false;
|
|
config::SnodePool _config;
|
|
std::shared_ptr<oxen::quic::Loop> _loop;
|
|
std::shared_ptr<oxen::quic::Loop> _disk_loop;
|
|
network_fetcher_t _direct_fetcher;
|
|
std::optional<network_fetcher_t> _routed_fetcher;
|
|
std::optional<fetcher_connectivity_check_t> _routed_fetcher_connectivity_check;
|
|
|
|
// Data
|
|
std::vector<service_node> _snode_cache;
|
|
std::vector<std::pair<swarm::swarm_id_t, std::vector<service_node>>> _all_swarms;
|
|
std::unordered_map<x25519_pubkey, std::pair<swarm::swarm_id_t, std::vector<service_node>>>
|
|
_swarm_cache;
|
|
std::map<ed25519_pubkey, std::vector<std::chrono::sys_seconds>> _snode_strikes;
|
|
bool _strikes_flush_scheduled = false;
|
|
|
|
// Disk I/O
|
|
std::filesystem::path _snode_cache_file_path;
|
|
std::filesystem::path _strikes_file_path;
|
|
|
|
// Refresh logic
|
|
std::chrono::system_clock::time_point _last_snode_cache_update;
|
|
std::optional<std::string> _current_snode_cache_refresh_id;
|
|
int _snode_cache_refresh_failure_count = 0;
|
|
std::vector<service_node> _refresh_candidate_nodes;
|
|
std::vector<std::vector<std::byte>> _snode_refresh_results;
|
|
std::vector<std::function<void()>> _after_snode_cache_refresh;
|
|
|
|
// Disk I/O functions
|
|
void _load_from_disk();
|
|
static void _clear_disk_cache(const std::filesystem::path& path);
|
|
static void _perform_cache_write(
|
|
const std::filesystem::path& path, const std::vector<service_node>& cache);
|
|
static void _perform_strikes_write(
|
|
const std::filesystem::path& path,
|
|
const std::map<ed25519_pubkey, std::vector<std::chrono::sys_seconds>>& strikes);
|
|
|
|
// Refresh functions
|
|
void _refresh_snode_cache(std::optional<std::string> request_id = std::nullopt);
|
|
void _launch_next_refresh_request(
|
|
const std::string& request_id,
|
|
const uint8_t index,
|
|
const bool refreshing_from_seed_nodes,
|
|
const bool use_direct_fetcher,
|
|
const uint8_t total_requests);
|
|
void _retry_refresh_request(
|
|
const std::string& request_id,
|
|
const uint8_t index,
|
|
const bool refreshing_from_seed_nodes,
|
|
const bool use_direct_fetcher,
|
|
const uint8_t total_requests);
|
|
void _on_refresh_complete(
|
|
std::string refresh_id,
|
|
std::vector<std::vector<std::byte>> raw_results,
|
|
const bool refreshing_from_seed_nodes,
|
|
const bool use_direct_fetcher,
|
|
const uint8_t total_requests);
|
|
void _update_cache(std::string refresh_id, std::vector<service_node> nodes);
|
|
};
|
|
|
|
} // namespace session::network
|