D++ Library Documentation

repository·master·Indexed 23 days ago

https://github.com/brainboxdotcc/dpp

A lightweight, high-performance C++ library for building Discord bots with support for Discord API v10. D++ features efficient caching, sharding and clustering, slash commands, and voice support with DAVE End-To-End Encryption. It is cross-platform, supporting Linux, Windows, macOS, FreeBSD, OpenBSD, and Raspberry Pi, and is designed for high scalability with a small memory footprint.

Tokens
18.9K
Snippets
54
Records
130
Agent score
80%

What's inside D++

  1. Overview of D++ (DPP)

    master

    D++ (DPP) is a lightweight, high-performance C++ library designed for interacting with the Discord API (v10). It is optimized for a minimal memory footprint and high scalability, making it suitable for bots managing large numbers of guilds and users.

    Key features include:

    • Efficient Caching: Optimized systems for guilds, channels, members, roles, and users.
    • High Throughput: Uses highly optimized Erlang Term Format (ETF) support for fast WebSocket communication.
    • Scalability: Built-in support for sharding and clustering.
    • Feature Completeness: Supports Slash Commands/Interactions and full Voice support (sending and receiving audio).
    • Cross-Platform: Stable support for Linux, Windows, macOS, FreeBSD, and OpenBSD, with prebuilt packages for Raspberry Pi.
  2. Overview of D++ Library Features

    master

    D++ is a lightweight, efficient C++ library for interacting with the Discord API (v10). It is designed for high scalability and a small memory footprint, even when caching large amounts of data.

    Key Features:

    • Discord API v10 Support: Full coverage of the API specification.
    • Efficient Caching: Optimized caching for guilds, channels, guild members, roles, and users.
    • Sharding & Clustering: Supports multiple shards within a single process (manual or automatic).
    • High Throughput: Optimized ETF (Erlang Term Format) support for fast websocket communication.
    • Slash Commands: Full support for interactions and slash commands.
    • Voice Support: Ability to send and receive audio with DAVE End-To-End Encryption.
    • Cross-Platform: Stable support for Linux, Windows, macOS, FreeBSD, OpenBSD, and Raspberry Pi.
  3. How to use the library on OpenBSD

    master

    On OpenBSD, once the library is installed to /usr/local, you should use CMake to manage your project and link to the library.

    Important Limitation: Direct linking via clang++ or g++ is currently broken on OpenBSD. You must use CMake for your build system to ensure correct integration.

  4. Compare role hierarchy using comparison operators

    master

    When checking if one role is higher than another in the hierarchy, do not compare position numbers directly, as multiple roles can share the same position. Instead, use the comparison operators (<, >) directly on dpp::role objects. This is the recommended way to ensure correct hierarchy logic.

    // Example: Ensuring target_role is not higher than issuer_role
    if (target_role > issuer_role) {
        event.reply("You can't ban someone whose role is higher than yours!");
        return;
    }
  5. Large Bot Sharding and Connection Concurrency

    master

    Discord imposes connection limits: you can only connect to one shard every five seconds unless your bot is in at least 150,000 guilds.

    Once a bot reaches the 150,000 guild threshold, Discord allows higher concurrency. D++ automatically handles this by attempting to connect 16 shards in parallel, waiting for them to connect, and then proceeding to the next batch of 16. You do not need to manually configure large bot sharding or connection concurrency; the library handles this automatically.

  6. Follow D++ naming conventions for classes, functions, and enums

    master

    When contributing to the D++ library, use snake_case for all class, variable/member, function, and method names to match the C++ standard library style.

    For enums, use snake_case for both the enum name and its values. Since enum class is not used, you must prefix enum values with a unique prefix to avoid collisions and ensure they are grouped correctly in IDEs (e.g., ll_debug, ll_trace).

  7. Maintain internal dependencies and avoid platform-specific code

    master

    When using external dependencies (like opus or libssl):

    • Do not include their headers or reference their types directly in D++ header files. This prevents them from becoming public dependencies.
    • Instead, use opaque classes or forward-declare the structs.

    Avoid platform-specific code (e.g., Windows-only functions or direct libc calls). If platform-specific logic is required, wrap it in #ifdef _WIN32 (or appropriate macros) and provide a cross-platform alternative.

  8. How the Discord voice connection lifecycle works

    master

    Connecting to a voice server in D++ involves a multi-step handshake between your bot and Discord:

    1. Request Voice Details: The library requests voice server details via the websocket for the relevant shard. Discord responds with a secondary websocket URI and an ephemeral token.
    2. Establish Secondary Connection: A new websocket connection is established using the provided URI and token.
    3. Protocol Negotiation: The library negotiates supported protocols and encryption. If DAVE (Discord's end-to-end encryption) is enabled, an MLS (Message Layer Security) group is joined or created.
    4. Encryption Setup: The secondary websocket provides a shared encryption secret and an RTP server hostname. The library uses libssl to prepare for RTP packet encryption.
    5. IP Detection: The library sends an initial packet to the RTP server to detect the bot's public IP.
    6. Initialization: Once the RTP server replies and encryption protocols are declared, the library enters an initialized state.

    Note on Events: Voice initialization typically occurs only after both voice_state_update and voice_server_update events have fired.

  9. Understand the D++ scaling model: Clusters, Shards, and Guilds

    master

    D++ uses a three-tiered hierarchy to scale bots efficiently:

    1. Clusters: The top-level abstraction. A cluster manages command queues (outgoing to Discord) and reply queues (incoming from Discord). It contains one or more shards. Clusters are independent and do not communicate with each other, preventing a single point of failure. Most small bots use a single cluster.
    2. Shards: Contained within a cluster, each shard maintains a persistent WebSocket connection to Discord to receive events (messages, channel edits, etc.). API requests are sent via separate HTTP requests.
    3. Guilds: Discord's term for servers. A single shard can handle up to 2500 guilds. If a bot exceeds 2500 guilds, Discord requires sharding; D++ will automatically create additional shards if you haven't explicitly configured a specific number.

    Relationship Summary:

    • A Bot consists of one or more Processes.
    • Each Process typically hosts one Cluster.
    • Each Cluster contains multiple Shards.
    • Each Shard manages multiple Guilds.
  10. Understand the DPP Thread Model

    master

    The DPP thread model separates user code from the cluster's internal management. The architecture follows three main layers:

    1. User Code: DPP makes no assumptions about how your program is threaded. You can use your own threading model alongside DPP.
    2. The Event Loop: This manages all socket I/O for the cluster. It uses poll, epoll, or kqueue depending on your operating system.
      • Threading: If you start the cluster with dpp::st_return, the event loop runs in its own thread. If you use dpp::st_wait, it runs in the same thread as the caller of dpp::cluster::start.
      • Forking Warning: You should always start a cluster after forking. IO loops cannot be inherited by a forked process.
    3. The Thread Pool: This pool handles the execution of every callback and every completed coroutine. It uses a priority queue for task management.

    Important Note on Forking: To avoid I/O loop inheritance issues, ensure dpp::cluster::start is called in the child process after a fork.