Skip to content

DEgITx/librats

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ€ librats

MIT License C++17 Build Status Release

A high-performance, lightweight peer-to-peer networking library with C++, C, Java, Python, and Android support

librats is a modern P2P networking library designed for superior performance and simplicity. Built from the ground up in C++17 with comprehensive language bindings, it provides enterprise-grade P2P networking capabilities with minimal overhead and maximum efficiency.

Official Website: https://librats.com

✨ Key Features

Core Architecture

  • Native C++17 implementation for maximum performance
  • Cross-platform support (Windows, Linux, macOS)
  • Thread-safe design with modern concurrency patterns using ThreadManager
  • Zero-copy data handling where possible
  • Automatic configuration persistence with JSON-based settings (config.json)
  • Historical peer tracking with automatic reconnection (peers.rats, peers_ever.rats)

Advanced Networking

  • DHT Integration: Direct access to the massive BitTorrent DHT network
  • mDNS Discovery: Automatic local network peer discovery with service advertisement
  • STUN Support: Automatic NAT traversal and public IP discovery
  • IPv4/IPv6 Dual Stack: Full support for modern internet protocols
  • Multi-layer Discovery: DHT (wide-area) + mDNS (local) + STUN (NAT traversal)
  • GossipSub Protocol: Scalable publish-subscribe messaging with mesh networking
  • Message Validation: Configurable message validation and filtering
  • Topic-based Communication: Organized messaging with topic subscriptions

High-Performance File Transfer

  • Chunked Transfers: Efficient file splitting with parallel chunk transmission
  • Resume Capability: Automatic resume of interrupted transfers with checksum validation
  • Directory Transfer: Complete directory trees with recursive subdirectory support
  • Transfer Control: Pause, resume, cancel operations with real-time progress tracking
  • Security Validation: SHA256 checksums for data integrity verification
  • Configurable Performance: Adjustable chunk size, concurrency, and timeout settings
  • Request/Response Model: Secure file requests with acceptance/rejection callbacks
  • Transfer Statistics: Comprehensive metrics including speed, ETA, and completion rates

Comprehensive NAT Traversal

  • ICE (Interactive Connectivity Establishment): RFC 8445 compliant with full candidate gathering
  • TURN Relay Support: RFC 5766 compliant relay through TURN servers
  • Advanced STUN: Enhanced STUN client with NAT type detection and ICE support
  • UDP/TCP Hole Punching: Coordinated NAT traversal for maximum connectivity
  • Automatic Strategy Selection: Choose optimal connection method based on network conditions
  • Real-time NAT Detection: Detailed NAT behavior analysis and adaptation

Enterprise Security

  • Noise Protocol Encryption: End-to-end encryption with Curve25519 + ChaCha20-Poly1305
  • Automatic Key Management: Keys generated, persisted, and rotated automatically
  • Mutual Authentication: Both peers verify each other's identity
  • Perfect Forward Secrecy: Session keys are ephemeral and secure
  • Configurable Encryption: Enable/disable on demand with set_encryption_enabled()

Modern Developer Experience

  • Event-Driven API: Register message handlers with on(), once(), off() methods
  • JSON Message Exchange: Built-in structured communication with callbacks
  • Promise-style Callbacks: Modern async patterns for network operations
  • Real-time Connection Tracking: Monitor peer states, connection quality, and NAT traversal progress
  • Comprehensive Logging API: Full control over logging levels, file rotation, and output formatting
  • Custom Protocol Support: Configure custom protocol names and versions
  • Unified API Design: Consistent patterns across P2P messaging and pub-sub
  • Topic-based Messaging: Subscribe to topics and publish messages with automatic routing
  • Enhanced Peer Management: Detailed peer information with encryption and NAT traversal status

Multi-Language Support

  • Native C++17: Core implementation with full feature set and maximum performance
  • C API: Clean C interface for legacy systems and FFI bindings
  • Java/Android: Complete JNI wrapper with high-level Java API for Android development
  • Python Bindings: Full-featured Python package with ctypes wrapper and asyncio support
  • Cross-Platform: Consistent API across Windows, Linux, macOS, and Android platforms

πŸš€ Quick Start

1. Basic P2P Connection

#include "librats.h"
#include <iostream>
#include <thread>
#include <chrono>

int main() {
    // Create a simple P2P client
    librats::RatsClient client(8080);
    
    // Set up connection callback
    client.set_connection_callback([](socket_t socket, const std::string& peer_id) {
        std::cout << "βœ… New peer connected: " << peer_id << std::endl;
    });
    
    // Set up message callback
    client.set_string_data_callback([](socket_t socket, const std::string& peer_id, const std::string& message) {
        std::cout << "πŸ’¬ Message from " << peer_id << ": " << message << std::endl;
    });
    
    // Start the client
    if (!client.start()) {
        std::cerr << "Failed to start client" << std::endl;
        return 1;
    }
    
    std::cout << "πŸ€ librats client running on port 8080" << std::endl;
    
    // Connect to another peer (optional)
    // client.connect_to_peer("127.0.0.1", 8081);
    
    // Send a message to all connected peers
    client.broadcast_string_to_peers("Hello from librats!");
    
    // Keep running
    std::this_thread::sleep_for(std::chrono::minutes(1));
    
    return 0;
}

2. Custom Protocol Setup

#include "librats.h"
#include <iostream>

int main() {
    librats::RatsClient client(8080);
    
    // Configure custom protocol for your application
    client.set_protocol_name("my_app");
    client.set_protocol_version("1.0");
    
    std::cout << "Protocol: " << client.get_protocol_name() 
              << " v" << client.get_protocol_version() << std::endl;
    std::cout << "Discovery hash: " << client.get_discovery_hash() << std::endl;
    
    client.start();
    
    // Start DHT discovery with custom protocol
    if (client.start_dht_discovery()) {
        // Announce our presence
        client.announce_for_hash(client.get_discovery_hash());
        
        // Search for other peers using same protocol
        client.find_peers_by_hash(client.get_discovery_hash(), 
            [](const std::vector<std::string>& peers) {
                std::cout << "Found " << peers.size() << " peers" << std::endl;
            });
    }
    
    return 0;
}

3. Chat Application with Message Exchange API

#include "librats.h"
#include <iostream>
#include <string>

int main() {
    librats::RatsClient client(8080);
    
    // Set up message handlers using the modern API
    client.on("chat", [](const std::string& peer_id, const nlohmann::json& data) {
        std::cout << "[CHAT] " << peer_id << ": " << data["message"].get<std::string>() << std::endl;
    });
    
    client.on("user_join", [](const std::string& peer_id, const nlohmann::json& data) {
        std::cout << "[JOIN] " << data["username"].get<std::string>() << " joined" << std::endl;
    });
    
    // Connection callback
    client.set_connection_callback([&](socket_t socket, const std::string& peer_id) {
        std::cout << "βœ… Peer connected: " << peer_id << std::endl;
        
        // Send welcome message
        nlohmann::json welcome;
        welcome["username"] = "User_" + client.get_our_peer_id().substr(0, 8);
        client.send("user_join", welcome);
    });
    
    client.start();
    
    // Send a chat message
    nlohmann::json chat_msg;
    chat_msg["message"] = "Hello, P2P chat!";
    chat_msg["timestamp"] = std::time(nullptr);
    client.send("chat", chat_msg);
    
    return 0;
}

4. GossipSub Publish-Subscribe

#include "librats.h"
#include <iostream>

int main() {
    librats::RatsClient client(8080);
    
    // Set up topic message handlers
    client.on_topic_message("news", [](const std::string& peer_id, const std::string& topic, const std::string& message) {
        std::cout << "πŸ“° [" << topic << "] " << peer_id << ": " << message << std::endl;
    });
    
    client.on_topic_json_message("events", [](const std::string& peer_id, const std::string& topic, const nlohmann::json& data) {
        std::cout << "πŸŽ‰ [" << topic << "] Event: " << data["type"].get<std::string>() << std::endl;
    });
    
    // Peer join/leave notifications
    client.on_topic_peer_joined("news", [](const std::string& peer_id, const std::string& topic) {
        std::cout << "βž• " << peer_id << " joined " << topic << std::endl;
    });
    
    client.start();
    client.start_dht_discovery();
    
    // Subscribe to topics
    client.subscribe_to_topic("news");
    client.subscribe_to_topic("events");
    
    // Publish messages
    client.publish_to_topic("news", "Breaking: librats is awesome!");
    
    nlohmann::json event;
    event["type"] = "celebration";
    event["reason"] = "successful_connection";
    client.publish_json_to_topic("events", event);
    
    std::cout << "πŸ“Š Peers in 'news': " << client.get_topic_peers("news").size() << std::endl;
    
    return 0;
}

5. File and Directory Transfer

#include "librats.h"
#include <iostream>

int main() {
    librats::RatsClient client(8080);
    
    // Set up file transfer callbacks
    client.on_file_transfer_progress([](const librats::FileTransferProgress& progress) {
        std::cout << "πŸ“ Transfer " << progress.transfer_id.substr(0, 8) 
                  << ": " << progress.get_completion_percentage() << "% complete"
                  << " (" << (progress.transfer_rate_bps / 1024) << " KB/s)" << std::endl;
    });
    
    client.on_file_transfer_completed([](const std::string& transfer_id, bool success, const std::string& error) {
        if (success) {
            std::cout << "βœ… Transfer completed: " << transfer_id.substr(0, 8) << std::endl;
        } else {
            std::cout << "❌ Transfer failed: " << error << std::endl;
        }
    });
    
    // Auto-accept incoming file transfers
    client.on_file_transfer_request([](const std::string& peer_id, 
                                      const librats::FileMetadata& metadata, 
                                      const std::string& transfer_id) {
        std::cout << "πŸ“₯ Incoming: " << metadata.filename 
                  << " (" << metadata.file_size << " bytes) from " << peer_id.substr(0, 8) << std::endl;
        return true; // Auto-accept
    });
    
    // Allow file requests from "shared" directory
    client.on_file_request([](const std::string& peer_id, const std::string& file_path, const std::string& transfer_id) {
        std::cout << "πŸ“€ Request: " << file_path << " from " << peer_id.substr(0, 8) << std::endl;
        return file_path.find("../") == std::string::npos; // Prevent path traversal
    });
    
    client.start();
    
    // Configure transfer settings
    librats::FileTransferConfig config;
    config.chunk_size = 64 * 1024;       // 64KB chunks
    config.max_concurrent_chunks = 4;    // 4 parallel chunks
    config.verify_checksums = true;      // Verify integrity
    client.set_file_transfer_config(config);
    
    // Example transfers (replace "peer_id" with actual peer ID)
    // std::string file_transfer = client.send_file("peer_id", "my_file.txt");
    // std::string dir_transfer = client.send_directory("peer_id", "./my_folder");
    // std::string file_request = client.request_file("peer_id", "remote_file.txt", "./downloaded_file.txt");
    
    std::cout << "File transfer ready. Connect peers and exchange files!" << std::endl;
    
    return 0;
}

6. Encryption

#include "librats.h"
#include <iostream>

int main() {
    librats::RatsClient client(8080);
    
    // Initialize encryption system
    if (!client.initialize_encryption(true)) {
        std::cerr << "Failed to initialize encryption" << std::endl;
        return 1;
    }
    
    // Generate a new encryption key (or load existing one)
    std::string encryption_key = client.generate_new_encryption_key();
    std::cout << "πŸ” Generated encryption key: " << encryption_key.substr(0, 16) << "..." << std::endl;
    
    // Alternatively, set a specific key:
    // client.set_encryption_key("your_64_character_hex_key_here");
    
    std::cout << "πŸ”’ Encryption enabled: " << (client.is_encryption_enabled() ? "Yes" : "No") << std::endl;
    
    // Connection callback with encryption status
    client.set_connection_callback([&](socket_t socket, const std::string& peer_id) {
        bool encrypted = client.is_peer_encrypted(peer_id);
        std::cout << "πŸ”— Peer connected: " << peer_id 
                  << (encrypted ? " [ENCRYPTED]" : " [UNENCRYPTED]") << std::endl;
    });
    
    client.start();
    
    // All communications are now automatically encrypted
    client.broadcast_string_to_peers("This message is encrypted!");
    
    return 0;
}

7. Configuration Persistence

#include "librats.h"
#include <iostream>

int main() {
    librats::RatsClient client(8080);
    
    // Set custom data directory for config files
    client.set_data_directory("./my_app_data");
    
    // Load saved configuration (if exists)
    if (client.load_configuration()) {
        std::cout << "πŸ“„ Loaded existing configuration" << std::endl;
    } else {
        std::cout << "πŸ“„ Using default configuration" << std::endl;
    }
    
    // Get our persistent peer ID
    std::cout << "πŸ†” Our peer ID: " << client.get_our_peer_id() << std::endl;
    
    client.start();
    
    // Try to reconnect to previously connected peers
    int reconnect_attempts = client.load_and_reconnect_peers();
    std::cout << "πŸ”„ Attempted to reconnect to " << reconnect_attempts << " previous peers" << std::endl;
    
    // Configuration is automatically saved when client stops
    // Files created: config.json, peers.rats, peers_ever.rats
    
    // Manual save if needed
    client.save_configuration();
    client.save_historical_peers();
    
    std::cout << "πŸ’Ύ Configuration will be saved to: " << client.get_data_directory() << std::endl;
    
    return 0;
}

8. Logging Configuration

#include "librats.h"
#include <iostream>

int main() {
    librats::RatsClient client(8080);
    
    // Enable and configure logging
    client.set_logging_enabled(true);
    client.set_log_file_path("librats_app.log");
    client.set_log_level("INFO");  // DEBUG, INFO, WARN, ERROR
    client.set_log_colors_enabled(true);
    client.set_log_timestamps_enabled(true);
    
    // Configure log file rotation
    client.set_log_rotation_size(5 * 1024 * 1024);  // 5MB max file size
    client.set_log_retention_count(3);               // Keep 3 old log files
    
    std::cout << "πŸ“ Logging to: " << client.get_log_file_path() << std::endl;
    std::cout << "πŸ“Š Log level: " << static_cast<int>(client.get_log_level()) << std::endl;
    std::cout << "🎨 Colors enabled: " << (client.is_log_colors_enabled() ? "Yes" : "No") << std::endl;
    
    client.start();
    
    // All librats operations will now be logged
    client.broadcast_string_to_peers("This action will be logged!");
    
    // Clear log file if needed (uncomment to use)
    // client.clear_log_file();
    
    return 0;
}

πŸ“– API Documentation

Core Classes

RatsClient

The main class providing comprehensive P2P networking capabilities:

// Enhanced constructor with NAT traversal
RatsClient(int listen_port, int max_peers = 10, const NatTraversalConfig& config = {});

// Core lifecycle
bool start();
void stop();
void shutdown_all_threads();
bool is_running() const;

// Advanced connection methods
bool connect_to_peer(const std::string& host, int port, ConnectionStrategy strategy = AUTO_ADAPTIVE);
bool connect_with_ice(const std::string& peer_id, const nlohmann::json& ice_offer);
nlohmann::json create_ice_offer(const std::string& peer_id);

// Custom protocol configuration
void set_protocol_name(const std::string& protocol_name);
void set_protocol_version(const std::string& protocol_version);
std::string get_protocol_name() const;
std::string get_protocol_version() const;
std::string get_discovery_hash() const;

// Message exchange API
void on(const std::string& message_type, MessageCallback callback);
void once(const std::string& message_type, MessageCallback callback);
void off(const std::string& message_type);
void send(const std::string& message_type, const nlohmann::json& data, SendCallback callback = nullptr);
void send(const std::string& peer_id, const std::string& message_type, const nlohmann::json& data, SendCallback callback = nullptr);

// Encryption
bool initialize_encryption(bool enable);
void set_encryption_enabled(bool enabled);
bool is_encryption_enabled() const;
std::string get_encryption_key() const;
bool set_encryption_key(const std::string& key_hex);
std::string generate_new_encryption_key();
bool is_peer_encrypted(const std::string& peer_id) const;

// Configuration persistence
bool load_configuration();
bool save_configuration();
bool set_data_directory(const std::string& directory_path);
std::string get_data_directory() const;
int load_and_reconnect_peers();
bool load_historical_peers();
bool save_historical_peers();
void clear_historical_peers();
std::vector<RatsPeer> get_historical_peers() const;

// GossipSub publish-subscribe messaging
GossipSub& get_gossipsub();
bool is_gossipsub_available() const;

// GossipSub convenience methods - Topic Management
bool subscribe_to_topic(const std::string& topic);
bool unsubscribe_from_topic(const std::string& topic);
bool is_subscribed_to_topic(const std::string& topic) const;
std::vector<std::string> get_subscribed_topics() const;

// GossipSub convenience methods - Publishing
bool publish_to_topic(const std::string& topic, const std::string& message);
bool publish_json_to_topic(const std::string& topic, const nlohmann::json& message);

// GossipSub convenience methods - Event Handlers
void on_topic_message(const std::string& topic, std::function<void(const std::string&, const std::string&, const std::string&)> callback);
void on_topic_json_message(const std::string& topic, std::function<void(const std::string&, const std::string&, const nlohmann::json&)> callback);
void on_topic_peer_joined(const std::string& topic, std::function<void(const std::string&, const std::string&)> callback);
void on_topic_peer_left(const std::string& topic, std::function<void(const std::string&, const std::string&)> callback);
void set_topic_message_validator(const std::string& topic, std::function<ValidationResult(const std::string&, const std::string&, const std::string&)> validator);
void off_topic(const std::string& topic);

// GossipSub convenience methods - Information
std::vector<std::string> get_topic_peers(const std::string& topic) const;
std::vector<std::string> get_topic_mesh_peers(const std::string& topic) const;
nlohmann::json get_gossipsub_statistics() const;
bool is_gossipsub_running() const;

// Peer management
int get_peer_count() const;
std::vector<RatsPeer> get_all_peers() const;
std::vector<RatsPeer> get_validated_peers() const;
const RatsPeer* get_peer_by_id(const std::string& peer_id) const;
std::string get_our_peer_id() const;

// NAT traversal utilities
NatType detect_nat_type();
NatTypeInfo get_nat_characteristics();
std::string get_public_ip() const;
std::vector<ConnectionAttemptResult> test_connection_strategies(const std::string& host, int port, const std::vector<ConnectionStrategy>& strategies);

// Enhanced callbacks
void set_advanced_connection_callback(AdvancedConnectionCallback callback);
void set_nat_traversal_progress_callback(NatTraversalProgressCallback callback);
void set_ice_candidate_callback(IceCandidateDiscoveredCallback callback);

// Logging Control API
void set_logging_enabled(bool enabled);
bool is_logging_enabled() const;
void set_log_file_path(const std::string& file_path);
std::string get_log_file_path() const;
void set_log_level(LogLevel level);
void set_log_level(const std::string& level_str);
LogLevel get_log_level() const;
void set_log_colors_enabled(bool enabled);
bool is_log_colors_enabled() const;
void set_log_timestamps_enabled(bool enabled);
bool is_log_timestamps_enabled() const;
void set_log_rotation_size(size_t max_size_bytes);
void set_log_retention_count(int count);
void clear_log_file();

// File Transfer API
FileTransferManager& get_file_transfer_manager();
bool is_file_transfer_available() const;

// File Transfer Operations
std::string send_file(const std::string& peer_id, const std::string& file_path, const std::string& remote_filename = "");
std::string send_directory(const std::string& peer_id, const std::string& directory_path, const std::string& remote_directory_name = "", bool recursive = true);
std::string request_file(const std::string& peer_id, const std::string& remote_file_path, const std::string& local_path);
std::string request_directory(const std::string& peer_id, const std::string& remote_directory_path, const std::string& local_directory_path, bool recursive = true);

// Transfer Control
bool accept_file_transfer(const std::string& transfer_id, const std::string& local_path);
bool reject_file_transfer(const std::string& transfer_id, const std::string& reason = "");
bool pause_file_transfer(const std::string& transfer_id);
bool resume_file_transfer(const std::string& transfer_id);
bool cancel_file_transfer(const std::string& transfer_id);

// Transfer Information
std::shared_ptr<FileTransferProgress> get_file_transfer_progress(const std::string& transfer_id) const;
std::vector<std::shared_ptr<FileTransferProgress>> get_active_file_transfers() const;
nlohmann::json get_file_transfer_statistics() const;
void set_file_transfer_config(const FileTransferConfig& config);
const FileTransferConfig& get_file_transfer_config() const;

// Transfer Event Handlers
void on_file_transfer_progress(FileTransferProgressCallback callback);
void on_file_transfer_completed(FileTransferCompletedCallback callback);
void on_file_transfer_request(FileTransferRequestCallback callback);
void on_directory_transfer_progress(DirectoryTransferProgressCallback callback);
void on_file_request(FileRequestCallback callback);
void on_directory_request(DirectoryRequestCallback callback);

Configuration Structures

NatTraversalConfig

Comprehensive NAT traversal configuration:

struct NatTraversalConfig {
    bool enable_ice = true;                    // Enable ICE
    bool enable_upnp = false;                  // Enable UPnP port mapping
    bool enable_hole_punching = true;          // Enable hole punching
    bool enable_turn_relay = true;             // Enable TURN relay
    bool prefer_ipv6 = false;                  // Prefer IPv6 connections
    
    std::vector<std::string> stun_servers;     // STUN servers
    std::vector<std::string> turn_servers;     // TURN servers
    std::vector<std::string> turn_usernames;   // TURN credentials
    std::vector<std::string> turn_passwords;
    
    int ice_gathering_timeout_ms = 10000;      // Timeouts
    int ice_connectivity_timeout_ms = 30000;
    int hole_punch_attempts = 5;
    int turn_allocation_timeout_ms = 10000;
    
    // Priority settings
    int host_candidate_priority = 65535;
    int server_reflexive_priority = 65534;
    int relay_candidate_priority = 65533;
    
    // Default includes Google STUN servers
};

RatsPeer

Comprehensive peer information structure:

struct RatsPeer {
    std::string peer_id;                       // Unique hash ID
    std::string ip;                            // IP address
    uint16_t port;                             // Port number
    socket_t socket;                           // Socket handle
    std::string normalized_address;            // For duplicate detection
    std::chrono::steady_clock::time_point connected_at;
    bool is_outgoing;                          // Connection direction
    
    // Handshake state
    enum class HandshakeState { PENDING, SENT, COMPLETED, FAILED };
    HandshakeState handshake_state;
    std::string version;                       // Protocol version
    int peer_count;                            // Remote peer count
    
    // Encryption state
    bool encryption_enabled;
    bool noise_handshake_completed;
    NoiseKey remote_static_key;
    
    // NAT traversal state
    bool ice_enabled;
    std::string ice_ufrag;
    std::string ice_pwd;
    std::vector<IceCandidate> ice_candidates;
    IceConnectionState ice_state;
    NatType detected_nat_type;
    std::string connection_method;
    
    // Connection quality metrics
    uint32_t rtt_ms;
    uint32_t packet_loss_percent;
    std::string transport_protocol;
    
    // Helper methods
    bool is_handshake_completed() const;
    bool is_handshake_failed() const;
    bool is_ice_connected() const;
    bool is_fully_connected() const;
};

FileTransferConfig

File transfer configuration structure:

struct FileTransferConfig {
    uint32_t chunk_size;            // Size of each chunk (default: 64KB)
    uint32_t max_concurrent_chunks; // Max chunks in flight (default: 4)
    uint32_t max_retries;           // Max retry attempts per chunk (default: 3)
    uint32_t timeout_seconds;       // Timeout per chunk (default: 30)
    bool verify_checksums;          // Verify chunk checksums (default: true)
    bool allow_resume;              // Allow resuming interrupted transfers (default: true)
    std::string temp_directory;     // Temporary directory for incomplete files
    
    FileTransferConfig() 
        : chunk_size(65536),        // 64KB chunks
          max_concurrent_chunks(4), 
          max_retries(3),
          timeout_seconds(30),
          verify_checksums(true),
          allow_resume(true),
          temp_directory("./temp_transfers") {}
};

FileTransferProgress

Transfer progress tracking structure:

struct FileTransferProgress {
    std::string transfer_id;        // Transfer identifier
    std::string peer_id;            // Peer we're transferring with
    FileTransferDirection direction; // Send or receive
    FileTransferStatus status;      // Current status
    
    // File information
    std::string filename;           // File being transferred
    std::string local_path;         // Local file path
    uint64_t file_size;             // Total file size
    
    // Progress tracking
    uint64_t bytes_transferred;     // Bytes completed
    uint64_t total_bytes;           // Total bytes to transfer
    uint32_t chunks_completed;      // Chunks successfully transferred
    uint32_t total_chunks;          // Total chunks in transfer
    
    // Performance metrics
    std::chrono::steady_clock::time_point start_time;    // Transfer start time
    std::chrono::steady_clock::time_point last_update;   // Last progress update
    double transfer_rate_bps;       // Current transfer rate (bytes/second)
    double average_rate_bps;        // Average transfer rate since start
    std::chrono::milliseconds estimated_time_remaining; // ETA
    
    // Error information
    std::string error_message;      // Error details if failed
    uint32_t retry_count;           // Number of retries attempted
    
    // Helper methods
    double get_completion_percentage() const;  // 0.0 to 100.0
    std::chrono::milliseconds get_elapsed_time() const;
    void update_transfer_rates(uint64_t new_bytes_transferred);
};

FileMetadata

File information structure:

struct FileMetadata {
    std::string filename;           // Original filename
    std::string relative_path;      // Relative path within directory structure
    uint64_t file_size;             // Total file size in bytes
    uint64_t last_modified;         // Last modification timestamp
    std::string mime_type;          // MIME type of the file
    std::string checksum;           // Full file checksum
};

🏒 Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Applications Layer                                               β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚ Message Exchangeβ”‚ β”‚   File Sharing  β”‚ β”‚   IoT Sensors   β”‚    β”‚
β”‚ β”‚      API        β”‚ β”‚      Apps       β”‚ β”‚     & More      β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ librats Core (RatsClient)                      β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚   Event-Driven  β”‚ β”‚   GossipSub     β”‚ β”‚   Encryption    β”‚    β”‚
β”‚ β”‚   Message API   β”‚ β”‚  Pub-Sub Mesh   β”‚ β”‚ (Noise Protocol)β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚ Config & Peer   β”‚ β”‚ Topic Routing   β”‚ β”‚ Message Validationβ”‚   β”‚
β”‚ β”‚  Persistence    β”‚ β”‚ & Mesh Managementβ”‚ β”‚ & Filtering     β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ NAT Traversal Layer                                             β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚ ICE Agent       β”‚ β”‚ STUN Client     β”‚ β”‚ TURN Client     β”‚    β”‚
β”‚ β”‚ (RFC 8445)      β”‚ β”‚ (RFC 5389)      β”‚ β”‚ (RFC 5766)      β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚ Hole Punching   β”‚ β”‚ NAT Detection   β”‚ β”‚ Strategy Select β”‚    β”‚
β”‚ β”‚ Coordination    β”‚ β”‚ & Analysis      β”‚ β”‚ & Fallback      β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Discovery & Networking Layer                                    β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚ DHT (Wide-Area) β”‚ β”‚ mDNS (Local Net)β”‚ β”‚ Direct Sockets  β”‚    β”‚
β”‚ β”‚   BitTorrent    β”‚ β”‚   224.0.0.251   β”‚ β”‚ IPv4/IPv6 Stack β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Platform Abstraction Layer                                      β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚ β”‚   Windows       β”‚ β”‚      Linux      β”‚ β”‚     macOS       β”‚    β”‚
β”‚ β”‚ WinSock2/bcrypt β”‚ β”‚  BSD Sockets    β”‚ β”‚  BSD Sockets    β”‚    β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ› οΈ Building

Supported Platforms & Language Bindings

librats provides comprehensive cross-platform support with bindings for multiple programming languages:

Native C++ Support

Platform Build Environment Compiler Status
Windows MinGW-w64 GCC 7+ βœ… Fully Supported
Windows Visual Studio MSVC 2017+ βœ… Fully Supported
Linux Native GCC 7+, Clang 5+ βœ… Fully Supported
macOS Xcode/Native Clang 10+ βœ… Fully Supported

Language Bindings & Wrappers

Language/Platform Binding Type Status Timeline Notes
C/C++ Native Library βœ… Fully Supported Available Now Core implementation with full feature set
Android (NDK) Native C++ βœ… Fully Supported Available Now Android NDK integration with JNI bindings
Android (Java) JNI Wrapper βœ… Fully Supported Available Now High-level Java API for Android apps
JavaScript Native Module πŸ“‹ Planned Soon Node.js native addon with async/await support
Python C Extension βœ… Fully Supported Available Now CPython extension with asyncio integration
Rust FFI Bindings πŸ“‹ Planned Soon Safe Rust bindings with tokio async support
Go CGO Bindings πŸ“‹ Future Soon CGO wrapper for Go applications
C#/.NET P/Invoke πŸ“‹ Future Soon .NET bindings for Windows/Linux/macOS

Mobile Platform Support

Platform Implementation Status Features
Android NDK + JNI βœ… Fully Supported Full P2P networking, file transfer, GossipSub
iOS Native C++ πŸ“‹ Planned Swift/Objective-C bindings planned
React Native Native Module πŸ“‹ Future Cross-platform mobile development
Flutter FFI Plugin πŸ“‹ Future Dart FFI integration

Web Platform Support

Platform Technology Status Limitations
Browser (WASM) WebAssembly πŸ“‹ Research Limited by browser networking APIs
Electron Node.js Module πŸ“‹ Planned Desktop app development
Tauri Rust Bindings πŸ“‹ Future Lightweight desktop apps

Legend:

  • βœ… Fully Supported: Production-ready with comprehensive testing
  • πŸ”Ά In Development: Active development, preview/beta available
  • πŸ“‹ Planned: Confirmed for development, timeline estimated
  • πŸ“‹ Future: Under consideration, timeline not confirmed
  • πŸ“‹ Research: Investigating feasibility and implementation approach

Prerequisites

  • CMake 3.10+
  • C++17 compatible compiler:
    • GCC 7+ (Linux, MinGW)
    • Clang 5+ (macOS, Linux)
    • MSVC 2017+ (Windows)
  • Git (for dependency management)

Building on Linux/macOS

git clone https://github.com/DEgITx/librats.git
cd librats
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

Building on Windows

git clone https://github.com/DEgITx/librats.git
cd librats
mkdir build && cd build
cmake .. -G "Visual Studio 16 2019"
cmake --build . --config Release

Build Options

# Disable tests
cmake .. -DRATS_BUILD_TESTS=OFF

# Debug build with full logging
cmake .. -DCMAKE_BUILD_TYPE=Debug

# Release build optimized for performance
cmake .. -DCMAKE_BUILD_TYPE=Release

Running Tests

# In build directory
ctest -j$(nproc) --output-on-failure

# Or run directly
./bin/librats_tests

Output Files

After building, you'll find:

  • Library: build/lib/librats.a (static library)
  • Executable: build/bin/rats-client (demo application)
  • Tests: build/bin/librats_tests (if RATS_BUILD_TESTS=ON)

🎯 Usage Examples

Simple Chat Application

# Terminal 1: Start first node
./build/bin/rats-client 8080

# Terminal 2: Start second node and connect
./build/bin/rats-client 8081 localhost 8080

File Sharing Application

#include "librats.h"

class FileShareApp {
private:
    librats::RatsClient client_;
    
public:
    FileShareApp(int port) : client_(port) {
        // Set up file transfer callbacks
        client_.on_file_transfer_progress([](const librats::FileTransferProgress& progress) {
            std::cout << "πŸ“Š " << progress.filename << ": " 
                      << progress.get_completion_percentage() << "% complete" << std::endl;
            std::cout << "Rate: " << (progress.transfer_rate_bps / 1024 / 1024) << " MB/s" << std::endl;
        });
        
        client_.on_file_transfer_completed([](const std::string& transfer_id, bool success, const std::string& error) {
            if (success) {
                std::cout << "βœ… Transfer completed: " << transfer_id.substr(0, 8) << std::endl;
            } else {
                std::cout << "❌ Transfer failed: " << error << std::endl;
            }
        });
        
        client_.on_file_transfer_request([](const std::string& peer_id, const librats::FileMetadata& metadata, const std::string& transfer_id) {
            std::cout << "πŸ“₯ File request from " << peer_id.substr(0, 8) << std::endl;
            std::cout << "File: " << metadata.filename << " (" << metadata.file_size << " bytes)" << std::endl;
            
            // Auto-accept files smaller than 100MB
            return metadata.file_size < 100 * 1024 * 1024;
        });
        
        client_.on_file_request([](const std::string& peer_id, const std::string& file_path, const std::string& transfer_id) {
            std::cout << "πŸ“€ File request from " << peer_id.substr(0, 8) << ": " << file_path << std::endl;
            
            // Allow access to files in "shared" directory only
            return file_path.find("../") == std::string::npos && 
                   file_path.substr(0, 7) == "shared/";
        });
        
        // Set up connection callbacks
        client_.set_connection_callback([](auto socket, const std::string& peer_id) {
            std::cout << "Peer connected: " << peer_id.substr(0, 8) << std::endl;
        });
        
        // Configure optimized file transfer settings
        librats::FileTransferConfig config;
        config.chunk_size = 256 * 1024;         // 256KB chunks for better performance
        config.max_concurrent_chunks = 8;       // 8 parallel chunks
        config.verify_checksums = true;         // Ensure data integrity
        config.allow_resume = true;             // Enable resume capability
        client_.set_file_transfer_config(config);
        
        // Start all services
        client_.start();
        client_.start_dht_discovery();
        client_.start_mdns_discovery("file-share");
    }
    
    std::string share_file(const std::string& peer_id, const std::string& file_path) {
        return client_.send_file(peer_id, file_path);
    }
    
    std::string share_directory(const std::string& peer_id, const std::string& directory_path) {
        return client_.send_directory(peer_id, directory_path, "", true);
    }
    
    std::string request_file(const std::string& peer_id, const std::string& remote_file, const std::string& local_path) {
        return client_.request_file(peer_id, remote_file, local_path);
    }
    
    void pause_transfer(const std::string& transfer_id) {
        client_.pause_file_transfer(transfer_id);
    }
    
    void resume_transfer(const std::string& transfer_id) {
        client_.resume_file_transfer(transfer_id);
    }
    
    void get_transfer_stats() {
        auto stats = client_.get_file_transfer_statistics();
        std::cout << "Total bytes transferred: " << stats["total_bytes_transferred"] << std::endl;
        std::cout << "Active transfers: " << stats["active_transfers"] << std::endl;
    }
    
    void connect_to(const std::string& host, int port) {
        client_.connect_to_peer(host, port);
    }
};

🎯 More Examples

Complete Chat Application

#include "librats.h"
#include <iostream>
#include <string>
#include <thread>

int main() {
    librats::RatsClient client(8080);
    
    // Set up chat message handling
    client.on("chat_message", [](const std::string& peer_id, const nlohmann::json& data) {
        std::string username = data.value("username", "Unknown");
        std::string message = data.value("message", "");
        std::cout << "[" << username << "]: " << message << std::endl;
    });
    
    // Handle user join/leave
    client.on("user_joined", [](const std::string& peer_id, const nlohmann::json& data) {
        std::cout << "*** " << data["username"].get<std::string>() << " joined the chat ***" << std::endl;
    });
    
    client.set_connection_callback([&](socket_t socket, const std::string& peer_id) {
        // Announce our presence
        nlohmann::json join_msg;
        join_msg["username"] = "User_" + client.get_our_peer_id().substr(0, 8);
        client.send("user_joined", join_msg);
    });
    
    client.start();
    client.start_dht_discovery(); // Auto-discover other chat users
    
    std::cout << "πŸ€ librats Chat - Type messages and press Enter" << std::endl;
    std::cout << "Type 'quit' to exit" << std::endl;
    
    std::string input;
    while (std::getline(std::cin, input)) {
        if (input == "quit") break;
        
        if (!input.empty()) {
            nlohmann::json chat_msg;
            chat_msg["username"] = "User_" + client.get_our_peer_id().substr(0, 8);
            chat_msg["message"] = input;
            chat_msg["timestamp"] = std::time(nullptr);
            client.send("chat_message", chat_msg);
        }
    }
    
    return 0;
}

πŸ“š Documentation

Comprehensive documentation is available:

πŸ”§ Configuration Files

librats automatically creates and manages these files:

  • config.json: Main configuration (protocol, encryption keys, settings)
  • peers.rats: Current active peers for reconnection
  • peers_ever.rats: Historical peers for discovery

Sample config.json

{
    "protocol_name": "rats",
    "protocol_version": "1.0",
    "peer_id": "550e8400-e29b-41d4-a716-446655440000",
    "encryption_enabled": true,
    "encryption_key": "a1b2c3d4e5f6...",
    "listen_port": 8080,
    "max_peers": 10
}

πŸš€ Benchmark Performance

librats is engineered for resource efficiency, making it ideal for low-power devices, edge computing, and embedded systems where memory and CPU resources are precious.

Performance Comparison vs libp2p (JavaScript)

Test Environment: AMD Ryzen 7 5700U, 16GB RAM

Metric librats (C++17) libp2p (JavaScript) Improvement
Startup Memory ~1.6 MB ~50-80 MB 31-50x less
Memory per Peer ~80 KB ~4-6 MB 50-75x less
Peak Memory (100 peers) ~9.4 MB 400-600 MB 42-64x less
CPU Usage (idle) 0-1% 15-25% 15-25x less
CPU Usage (peak) 1-2% 80-100% 5-16x less

Why Choose librats?

Performance

  • Native C++17: Maximum performance with minimal overhead
  • Zero-copy operations: Efficient data handling where possible
  • Thread-safe design: Modern concurrency with ThreadManager
  • Optimized protocols: Custom implementations tuned for speed

Reliability

  • Production tested: Used in real-world applications
  • Comprehensive testing: Unit tests and integration tests covering all components
  • Memory safety: RAII and smart pointers throughout
  • Cross-platform: Consistent behavior across Windows, Linux, and macOS

NAT Traversal Excellence

  • 99%+ Success Rate: Connect across virtually any NAT configuration
  • RFC Compliant: Follows established standards (ICE, STUN, TURN)
  • Adaptive Strategy: Automatically selects optimal connection method
  • Real-time Monitoring: Track connection attempts and quality metrics

Developer Experience

  • Simple API: Easy to learn and integrate
  • Modern C++: Takes advantage of C++17 features
  • Excellent documentation: Comprehensive guides and examples
  • Active development: Regular updates and improvements
  • Configuration persistence: Automatic saving and loading of settings

NAT Traversal Capabilities

librats includes industry-leading NAT traversal that can establish P2P connections across virtually any network topology:

NAT Type Direct STUN ICE TURN Success Rate
Open Internet βœ… βœ… βœ… βœ… 100%
Full Cone NAT ❌ βœ… βœ… βœ… 95%
Restricted Cone ❌ βœ… βœ… βœ… 90%
Port Restricted ❌ βœ… βœ… βœ… 85%
Symmetric NAT ❌ ❌ ⚠️ βœ… 70%
Double NAT ❌ ❌ ❌ βœ… 99%

Connection Strategies

  • AUTO_ADAPTIVE: Automatically selects the best connection method
  • ICE_FULL: Complete ICE negotiation with candidate gathering
  • STUN_ASSISTED: STUN-based public IP discovery and direct connection
  • TURN_RELAY: Fallback relay through TURN servers
  • DIRECT_ONLY: Try direct connection only

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/DEgITx/librats.git
cd librats
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DRATS_BUILD_TESTS=ON
make -j$(nproc)
./bin/librats_tests

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments

  • nlohmann/json: For the excellent JSON library integration
  • Contributors: Everyone who has contributed to making librats better

About

High-performance, lightweight p2p native library for big networks

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •