{"id":13626677,"url":"https://github.com/lithdew/snow","last_synced_at":"2026-03-04T05:01:57.623Z","repository":{"id":55838311,"uuid":"318803057","full_name":"lithdew/snow","owner":"lithdew","description":"A small, fast, cross-platform, async Zig networking framework built on top of lithdew/pike.","archived":false,"fork":false,"pushed_at":"2022-11-19T21:15:57.000Z","size":94,"stargazers_count":38,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-23T22:04:03.149Z","etag":null,"topics":["async","networking","pike","tcp","zig"],"latest_commit_sha":null,"homepage":"","language":"Zig","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/lithdew.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}},"created_at":"2020-12-05T14:03:29.000Z","updated_at":"2024-08-31T21:01:41.000Z","dependencies_parsed_at":"2023-01-22T17:15:45.720Z","dependency_job_id":null,"html_url":"https://github.com/lithdew/snow","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lithdew/snow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lithdew%2Fsnow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lithdew%2Fsnow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lithdew%2Fsnow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lithdew%2Fsnow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lithdew","download_url":"https://codeload.github.com/lithdew/snow/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lithdew%2Fsnow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30071895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T03:25:38.285Z","status":"ssl_error","status_checked_at":"2026-03-04T03:25:05.086Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["async","networking","pike","tcp","zig"],"created_at":"2024-08-01T21:02:26.249Z","updated_at":"2026-03-04T05:01:57.600Z","avatar_url":"https://github.com/lithdew.png","language":"Zig","funding_links":[],"categories":["Zig","Libraries"],"sub_categories":[],"readme":"# snow\n\nA small, fast, cross-platform, async Zig networking framework built on top of [lithdew/pike](https://github.com/lithdew/pike).\n\nIt automatically handles:\n1. buffering/framing data coming in and out of a socket,\n2. managing the lifecycle of incoming / outgoing connections, and \n3. representing a singular `Client` / `Server` as a bounded adaptive pool of outgoing / incoming connections.\n\nIt also allows you to specify:\n1. how messages are framed (`\\n` suffixed to each message, message length prefixed to each message, etc.),\n2. a sequence of steps to be performed before successfully establishing a connection (a handshake protocol), and\n3. an upper bound to the maximum number of connections a `Client` / `Server` may pool in total.\n\n## Usage\n\nIn your `build.zig`:\n\n```zig\nconst std = @import(\"std\");\n\nconst Builder = std.build.Builder;\n\nconst pkgs = struct {\n    const pike = std.build.Pkg{\n        .name = \"pike\",\n        .path = \"pike/pike.zig\",\n    };\n\n    const snow = std.build.Pkg{\n        .name = \"snow\",\n        .path = \"snow/snow.zig\",\n        .dependencies = \u0026[_]std.build.Pkg{\n            pike,\n        }\n    };\n};\n\npub fn build(b: *Builder) void {\n    // Given a build step...\n    step.addPackage(pkgs.pike);\n    step.addPackage(pkgs.snow);\n}\n```\n\n## Protocol\n\nApplications written with _snow_ provide a `Protocol` implementation which specifies how message are encoded / decoded into frames.\n\nHelpers (`io.Reader` / `io.Writer`) are provided to assist developers in specifying how frame encoding / decoding is to be performed.\n\nGiven a `Protocol` implementation, a `Client` / `Server` may be instantiated.\n\nHere is an example of a `Protocol` that frames messages based on an End-of-Line character ('\\n') suffixed at the end of each message:\n\n```zig\nconst std = @import(\"std\");\nconst snow = @import(\"snow\");\n\nconst mem = std.mem;\n\nconst Protocol = struct {\n    const Self = @This();\n\n    // This gets called right before a connection is marked to be successfully established!\n    //\n    // Unlike the rest of the callbacks below, 'socket' is a raw 'pike.Socket'. Feel free to\n    // read / write as much data as you wish, or to return an error to prevent a connection\n    // from being marked as being successfully established.\n    //\n    // Rather than 'void', snow.Options.context_type may be set and returned from 'handshake'\n    // to bootstrap a connection with additional fields and methods under 'socket.context'.\n    pub fn handshake(self: *Self, comptime side: snow.Side, socket: anytype) !void {\n        return {};\n    }\n\n    // This gets called before a connection is closed!\n    pub fn close(self: *Self, comptime side: snow.Side, socket: anytype) void {\n        return {};\n    }\n\n    // This gets called when a connection's resources is ready to be de-allocated!\n    //\n    // A slice of remaining items in the socket's write queue is passed to purge() to be\n    // optionally deallocated.\n    pub fn purge(self: *Self, comptime side: snow.Side, socket: anytype, items: []const []const u8) void {\n        return {};\n    }\n\n    // This gets called when data is ready to be read from a connection!\n    pub fn read(self: *Self, comptime side: snow.Side, socket: anytype, reader: anytype) !void {\n        while (true) {\n            const line = try reader.readLine();\n            defer reader.shift(line.len);\n\n            // Do something with the frame here!\n        }\n    }\n\n    // This gets called when data is queued and ready to be encoded and written to\n    // a connection!\n    //\n    // Rather than '[]const u8', custom message types may be set to be queuable to the\n    // connections write queue by setting snow.Options.message_type.\n    pub fn write(self: *Self, comptime side: snow.Side, socket: anytype, writer: anytype, items: [][]const u8) !void {\n        for (items) |message| {\n            if (mem.indexOfScalar(u8, message, '\\n') != null) {\n                return error.UnexpectedDelimiter;\n            }\n\n            const frame = try writer.peek(message.len + 1);\n            mem.copy(u8, frame[0..message.len], message);\n            frame[message.len..][0] = '\\n';\n        }\n\n        try writer.flush();\n    }\n};\n```\n\n## Client\n\nA `Client` comprises of a bounded adaptive pool of outgoing connections that are to be connected to a single IPv4/IPv6 endpoint.\n\nWhen writing a message to an endpoint with a `Client`, a connection is initially grabbed from the pool. The message is then queued to be written to the connection's underlying socket.\n\nA policy is specified for selecting which connection to grab from a `Client`'s pool. The policy goes as follows:\n\nThere exists a configurable maximum number of connections that may belong to a `Client`'s pool (defaulting to 16). If all existing connections in a `Client`'s pool contain queued messages that have yet to be flushed and written, a new connection is created and registered to the pool up to a maximum number of connections.\n\nIf the pool's maximum number of connections limit is reached, the connection in the pool with the smallest number of queued messages is returned. Otherwise, a new connection is created and registered to the pool and returned.\n\n## Server\n\nA `Server` comprises of a bounded adaptive pool of incoming connections accepted from a single bounded IPv4/IPv6 endpoint. There exists a configurable maximum number of connections that may belong to a `Server`'s pool (defaulting to 128).\n\nShould an incoming connection be established and the pool underlying a `Server` appears to be full, the connection will be declined and de-initialized.\n\n## Socket\n\nAll sockets comprise of two coroutines: a reader coroutine, and a writer coroutine. The reader and writer coroutine are responsible for framing and buffering messages received from / written to a single socket instance, and for executing logic specified under a `Protocol` implementation.\n\nAn interesting detail to note is that the writer coroutine is entirely lock-free.\n\n## Performance\n\n_snow_ was written with performance in mind: zero heap allocations occur in all hot paths. Heap allocations only ever occur when establishing a new incoming / outgoing connection.\n\nAll other underlying components are stack-allocated and recycled as much as possible.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flithdew%2Fsnow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flithdew%2Fsnow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flithdew%2Fsnow/lists"}