{"id":19752752,"url":"https://github.com/spoorn/durian","last_synced_at":"2025-07-02T14:36:38.575Z","repository":{"id":64431317,"uuid":"575286450","full_name":"spoorn/durian","owner":"spoorn","description":"General purpose client/server networking library written in Rust, built on top of the QUIC protocol which is implemented by quinn","archived":false,"fork":false,"pushed_at":"2023-09-06T09:29:31.000Z","size":287,"stargazers_count":108,"open_issues_count":1,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-20T06:05:59.044Z","etag":null,"topics":["game-development","gamedev","netcode","networking","rust","rust-library"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spoorn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-12-07T07:00:28.000Z","updated_at":"2025-05-09T17:35:03.000Z","dependencies_parsed_at":"2024-12-25T01:11:39.701Z","dependency_job_id":"c576391d-66ac-4ef5-8558-d17f8366dea5","html_url":"https://github.com/spoorn/durian","commit_stats":{"total_commits":63,"total_committers":2,"mean_commits":31.5,"dds":"0.015873015873015928","last_synced_commit":"0ea9e092d29d457070c840b8605b75ab24452f98"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/spoorn/durian","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spoorn%2Fdurian","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spoorn%2Fdurian/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spoorn%2Fdurian/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spoorn%2Fdurian/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spoorn","download_url":"https://codeload.github.com/spoorn/durian/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spoorn%2Fdurian/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263157467,"owners_count":23422632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["game-development","gamedev","netcode","networking","rust","rust-library"],"created_at":"2024-11-12T02:49:54.272Z","updated_at":"2025-07-02T14:36:38.551Z","avatar_url":"https://github.com/spoorn.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Overview\n_\"This library stinks!\" ... \"Unless you like durian\"_\n\n`durian` is a client-server networking library built on top of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol which is\nimplemented in Rust by [quinn](https://github.com/quinn-rs/quinn).\n\nIt provides a thin abstraction layer above the lower-level details of connection management, byte management,\nframing, and more, to make writing netcode easier and allow the user to focus on the messaging\ncontents instead.  Serialization and deserialization are built into the APIs so you can send and receive exact\nPackets as structs for ease of development.\n\n`durian` is a general purpose library, but was made primarily for me to dabble in game development.  It has been\ntested and working with the [Bevy](https://bevyengine.org/) game engine.\n\nFull documentation can be found at https://docs.rs/durian/latest/durian/\n\nCrates.io: https://crates.io/crates/durian/\n\n### Disclaimer\nThis library is in very early (but very active!) development, meaning a LOT of it will change rapidly.  \nIn its current state, it's usable to create a quick multiplayer demo.  I use it myself to learn [game\ndevelopment](https://github.com/spoorn/multisnakegame).\n\nThis __is not production ready__, and is missing a lot of features to make it production ready (see [Features](#features) list below).\n\nHowever, if you are trying to build something and want to avoid a lot of the headache of lower-level netcode details,\nand don't need the \"production\" features, such as a multiplayer game demo, LAN sandbox applications, etc., then feel\nfree to try it out!\n\n`durian`'s goal is to make it as simple as possible to setup netcode (See the examples below).\n\n## Features\n\n* [x] Simultaneous basic Client/Server connection management and operations\n* [x] Both async and sync APIs for different caller contexts\n* [x] Multiplexing without head of line blocking (QUIC feature)\n    * Dedicated stream for each Packet type and multi-threaded\n* [x] Reliable packets: guaranteed delivery of all messages\n* [x] Ordered packets: packets are received in the same order they are sent on each stream\n* [x] Packet Fragmentation and re-assembly automatically for you\n* [x] Macros to ease creation of Packets\n* [x] Send and receive packets simultaneously\n* [x] Various Client/Server configurations\n    * keep-alive-intervals\n    * idle-timeout\n    * ALPN Protocol\n\n### Not yet done\n\n* [ ] Certificate authentication between client-server\n* [ ] More complex connection configurations such as:\n    * Pluggable cryptography\n* [ ] Handshake protocol\n* [ ] Connection/streams re-establishment\n* [ ] Reusing an Endpoint across multiple PacketManagers (for client connected to multiple servers, or having different Packet contracts)\n* [ ] Better Error handling/messaging\n* [ ] Unreliable packets\n* [ ] Unordered packets\n* [ ] Probably lots more\n\n\n# Cargo.toml Dependency\n\nAdd `durian` to your Cargo.toml via `cargo add durian` or manually:\n\n```toml\n[dependencies]\ndurian = \"0.3\"\n```\n\n# Packet/PacketBuilder\n\nThere are 2 steps needed to create a [`Packet`](https://docs.rs/durian/latest/durian/trait.Packet.html) to be used with `durian`:\n\n1. `durian` allows for structuring [`Packets`](https://docs.rs/durian/latest/durian/trait.Packet.html) as simple structs.  The structs must implement\n   Trait [`Packet`](https://docs.rs/durian/latest/durian/trait.Packet.html), which has a single function [`Packet::as_bytes()`](https://docs.rs/durian/latest/durian/trait.Packet.html#tymethod.as_bytes) which will be called for\n   serializing the [`Packet`](https://docs.rs/durian/latest/durian/trait.Packet.html) into bytes to be sent over the wire between client and server.\n\n2. There also needs to be a struct that implements [`PacketBuilder`](https://docs.rs/durian/latest/durian/trait.PacketBuilder.html) which is used to\n   deserialize from bytes back into your [`Packet`](https://docs.rs/durian/latest/durian/trait.Packet.html) struct via the `PacketBuilder::read()`\n   function.\n\nFor your convenience, `durian` is bundled with [`durian_macros`](https://docs.rs/durian_macros/latest/durian_macros/index.html) which contains a few macros that\nhelp autogenerate Impl blocks for a struct for both [`Packet`](https://docs.rs/durian/latest/durian/trait.Packet.html) and [`PacketBuilder`](https://docs.rs/durian/latest/durian/trait.PacketBuilder.html).  The only\nrequirement is the struct must be de/serializable, meaning all nested fields also need to be\nde/serializable.\n\n[`#[bincode_packet]`](https://docs.rs/durian/latest/durian/attr.bincode_packet.html) will de/serialize your Packet using [bincode](https://github.com/bincode-org/bincode) and applies necessary derive\nmacros automatically for you.\n```rust\nuse durian::bincode_packet;\n\n// Automatically implements Packet, and generates a PositionPacketBuilder that implements \n// PacketBuilder.  You can also add other macros such as derive macros so long as they don't\n// conflict with what #[bincode_packet] adds (See bincode_packet documentation).\n#[bincode_packet]\n#[derive(Debug)]\nstruct Position {\n    x: i32,\n    y: i32\n}\n\n// Works for Unit (empty) structs as well\n#[bincode_packet]\nstruct Ack;\n```\n\nYou can also use the derive macros ([`BinPacket`](https://docs.rs/durian/latest/durian/derive.BinPacket.html) and [`UnitPacket`](https://docs.rs/durian/latest/durian/derive.UnitPacket.html)) manually:\n\n```rust\nuse durian::serde::{Deserialize, Serialize};\nuse durian::{BinPacket, UnitPacket};\n\n#[derive(Serialize, Deserialize, BinPacket)]\n#[serde(crate = \"durian::serde\")]\nstruct Position { x: i32, y: i32 }\n\n#[derive(UnitPacket)]\nstruct Ack;\n```\n\n\n# PacketManager\n\n[`PacketManager`](https://docs.rs/durian/latest/durian/struct.PacketManager.html) is what you will use to initiate connections between clients/servers, and\nsend/receive [`Packets`](https://docs.rs/durian/latest/durian/trait.Packet.html).\n\nA [`PacketManager`](https://docs.rs/durian/latest/durian/struct.PacketManager.html) would be created on each client to connect to a\nsingle server, and one created on the server to connect to multiple clients. It contains both\nsynchronous and asynchronous APIs, so you can call the functions both from a synchronous\ncontext, or within an async runtime (_Note: the synchronous path will create a separate\nisolated async runtime context per [`PacketManager`](https://docs.rs/durian/latest/durian/struct.PacketManager.html) instance._)\n\nThere are 4 basic steps to using the [`PacketManager`](https://docs.rs/durian/latest/durian/struct.PacketManager.html), which would be done on both the client\nand server side:\n\n1. Create a [`PacketManager`](https://docs.rs/durian/latest/durian/struct.PacketManager.html) via [`new()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.new) or, if calling from an async context, [`new_for_async()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.new_for_async)\n\n2. Register the [`Packets`](https://docs.rs/durian/latest/durian/trait.Packet.html) and [`PacketBuilders`](https://docs.rs/durian/latest/durian/trait.PacketBuilder.html) that the [`PacketManager`](https://docs.rs/durian/latest/durian/struct.PacketManager.html) will __receive__\n   and __send__ using [`register_receive_packet()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.register_receive_packet) and [`register_send_packet()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.register_send_packet).  \n   The ordering of [`Packet`](https://docs.rs/durian/latest/durian/trait.Packet.html) registration matters for the `receive` channel and\n   `send` channel each - the client and server must register the same packets in the same order,\n   for the opposite channels.\n    - In other words, the client must register `receive` packets in the\n      same order the server registers the same as `send` packets, and vice versa, the client must\n      register `send` packets in the same order the server registers the same as `receive` packets.\n      This helps to ensure the client and servers are in sync on what Packets to send/receive, almost\n      like ensuring they are on the same \"version\" so to speak, and is used to properly identify\n      Packets.\n\n3. Initiate connection(s) with [`init_client()`](`PacketManager::init_client()`) (or the async variant [`async_init_client()`](`PacketManager::async_init_client()`)\n   if on the client side, else use [`init_server()`](`PacketManager::init_server()`) (or the async variant [`async_init_server)`](`PacketManager::async_init_server()`)\n   if on the server side.\n\n4. Send packets using any of [`broadcast()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.broadcast), [`send()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.send), [`send_to()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.send_to)\n   or the respective `async` variants if calling from an async context already.  Receive packets\n   using any of [`received_all()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.received_all) , [`received()`](https://docs.rs/durian/latest/durian/struct.PacketManager.html#method.received), or the respective\n   `async` variants.\n\nPutting these together:\n\n```rust\nuse durian::PacketManager;\nuse durian_macros::bincode_packet;\n\n#[bincode_packet]\nstruct Position { x: i32, y: i32 }\n#[bincode_packet]\nstruct ServerAck;\n#[bincode_packet]\nstruct ClientAck;\n#[bincode_packet]\nstruct InputMovement { direction: String }\n\nfn packet_manager_example() {\n    // Create PacketManager\n    let mut manager = PacketManager::new();\n\n    // Register send and receive packets\n    manager.register_receive_packet::\u003cPosition\u003e(PositionPacketBuilder).unwrap();\n    manager.register_receive_packet::\u003cServerAck\u003e(ServerAckPacketBuilder).unwrap();\n    manager.register_send_packet::\u003cClientAck\u003e().unwrap();\n    manager.register_send_packet::\u003cInputMovement\u003e().unwrap();\n\n    // Initialize connection to an address\n    manager.init_connections(true, 2, 2, \"127.0.0.1:5000\", Some(\"127.0.0.1:5001\"), 0, None).unwrap();\n\n    // Send and receive packets\n    manager.broadcast(InputMovement { direction: \"North\".to_string() }).unwrap();\n    manager.received_all::\u003cPosition, PositionPacketBuilder\u003e(false).unwrap();\n\n    // The above PacketManager is for the client.  Server side is similar except the packets\n    // are swapped between receive vs send channels.\n\n    // Create PacketManager\n    let mut server_manager = PacketManager::new();\n\n    // Register send and receive packets\n    server_manager.register_receive_packet::\u003cClientAck\u003e(ClientAckPacketBuilder).unwrap();\n    server_manager.register_receive_packet::\u003cInputMovement\u003e(InputMovementPacketBuilder).unwrap();\n    server_manager.register_send_packet::\u003cPosition\u003e().unwrap();\n    server_manager.register_send_packet::\u003cServerAck\u003e().unwrap();\n\n    // Initialize a client\n    let client_config = ClientConfig::new(\"127.0.0.1:5001\", \"127.0.0.1:5000\", 2, 2);\n    server_manager.init_client(client_config).unwrap();\n\n    // Send and receive packets\n    server_manager.broadcast(Position { x: 1, y: 3 }).unwrap();\n    server_manager.received_all::\u003cInputMovement, InputMovementPacketBuilder\u003e(false).unwrap();\n}\n```\n\n\n# Examples\n\nFor beginners, creating packets to be sent between clients/server should be extremely straight-forward\nand the above examples should cover most of what you'd need.  For more complex scenarios, such as\nserializing/deserializing packets in a custom way, can be done by implementing the various Traits\nyourself, or through extra configurations in the [`PacketManager`](PacketManager).\n\nFor a comprehensive minimal example, see the [example crate](https://github.com/spoorn/durian/tree/main/example).\n\nI also use this library myself for simple game development.  See the [multisnakegame repo](https://github.com/spoorn/multisnakegame).\n\n# Debugging\n\n`durian` uses the `log` API with debug and trace logs.  Enable debug logging to see update logs\nfrom `durian`, and enable trace logging to see packet byte transmissions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspoorn%2Fdurian","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspoorn%2Fdurian","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspoorn%2Fdurian/lists"}