{"id":16418540,"url":"https://github.com/nitely/nim-hyperx","last_synced_at":"2025-02-24T11:26:52.023Z","repository":{"id":191820035,"uuid":"685445851","full_name":"nitely/nim-hyperx","owner":"nitely","description":"Pure Nim http2 client and server 🖖","archived":false,"fork":false,"pushed_at":"2024-05-22T15:13:22.000Z","size":463,"stargazers_count":22,"open_issues_count":5,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-05-22T16:00:36.792Z","etag":null,"topics":["client","http","http-client","http-server","http2","nim","nim-lang","server","web"],"latest_commit_sha":null,"homepage":"","language":"Nim","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/nitely.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":"nitely_","tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"custom":null}},"created_at":"2023-08-31T08:45:47.000Z","updated_at":"2024-08-02T08:00:38.374Z","dependencies_parsed_at":"2023-08-31T23:41:57.214Z","dependency_job_id":"9a388e09-d9d3-494d-a4b7-96c125db3bea","html_url":"https://github.com/nitely/nim-hyperx","commit_stats":null,"previous_names":["nitely/nim-hyperx"],"tags_count":43,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitely%2Fnim-hyperx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitely%2Fnim-hyperx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitely%2Fnim-hyperx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitely%2Fnim-hyperx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nitely","download_url":"https://codeload.github.com/nitely/nim-hyperx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240468147,"owners_count":19806124,"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":["client","http","http-client","http-server","http2","nim","nim-lang","server","web"],"created_at":"2024-10-11T07:14:25.069Z","updated_at":"2025-02-24T11:26:52.018Z","avatar_url":"https://github.com/nitely.png","language":"Nim","funding_links":["https://ko-fi.com/nitely_"],"categories":[],"sub_categories":[],"readme":"# HyperX\n\nPure Nim Http2 client/server implementation. Tested with [h2spec](https://github.com/summerwind/h2spec), and [h2load](https://nghttp2.org/documentation/h2load-howto.html).\n\n\u003e [!NOTE]\n\u003e This library supports HTTP/2 only. Not HTTP/1, nor HTTP/3.\n\n## Install\n\n```\nnimble install hyperx\n```\n\n## Compatibility\n\n\u003e Nim +2.0\n\n## Requirements\n\n- OpenSSL\n\n## Client\n\n```nim\n\n# this define needs to be in the main nim file\n# or pass it as a compiler parameter `-d:ssl`\n# or define it in the nim.cfg file\n{.define: ssl.}\n\nimport std/asyncdispatch\nimport pkg/hyperx/client\n\nproc main {.async.} =\n  let client = newClient(\"www.google.com\")\n  with client:\n    let queries = [\"john+wick\", \"winston\", \"ms+perkins\"]\n    var tasks = newSeq[Future[Response]]()\n    for q in queries:\n      tasks.add client.get(\"/search?q=\" \u0026 q)\n    let responses = await all(tasks)\n    for r in responses:\n      doAssert \":status: 200\" in r.headers\n      doAssert \"doctype\" in r.text\nwaitFor main()\necho \"ok\"\n```\n\n## Server\n\n```nim\n{.define: ssl.}\n\nimport std/asyncdispatch\nimport pkg/hyperx/server\n\nconst\n  localHost = \"127.0.0.1\"\n  localPort = Port 8888\n  certFile = \"/usr/src/app/example.com+5.pem\"\n  keyFile = \"/usr/src/app/example.com+5-key.pem\"\n\nproc processStream(strm: ClientStream) {.async.} =\n  ## Consume the stream and send hello world!.\n  let data = new string\n  await strm.recvHeaders(data)\n  while not strm.recvEnded:\n    data[].setLen 0\n    await strm.recvBody(data)\n  await strm.sendHeaders(\n    @[(\":status\", \"200\")], finish = false\n  )\n  data[] = \"Hello world!\"\n  await strm.sendBody(data, finish = true)\n\nproc main {.async.} =\n  echo \"Serving forever\"\n  let server = newServer(\n    localHost, localPort, certFile, keyFile\n  )\n  await server.serve(processStream)\n\nwaitFor main()\necho \"ok\"\n```\n\nBeware HTTP/2 requires TLS, so if you want to test the server locally you'll need a local cert. I used [mkcert](https://github.com/FiloSottile/mkcert) to generate mine.\n\nYou may disable SSL by passing `ssl = false` to `newServer/newClient` for local testing.\n\n## Usage\n\nRead the [examples](https://github.com/nitely/nim-hyperx/blob/master/examples/).\n\n## Debugging\n\nThis will print received frames, and some other debugging messages\n\n```\nnim c -r -d:hyperxDebug client.nim\n```\n\n## Notes\n\n### Why?\n\nHttp/2 supports high concurrency over a single connection through stream multiplexing.\n\nHttp/1 can only compete by enabling [pipelining](https://en.wikipedia.org/wiki/HTTP_pipelining), which is what most http/1 benchmarks do. But web-browsers do not enable it, and you may not want to enable it for good reasons. It produces [head of line blocking](https://en.wikipedia.org/wiki/Head-of-line_blocking) at the application level.\n\n### Serving http/1 and http/3 traffic\n\nYou may use a reverse proxy such as [Caddy](https://github.com/caddyserver/caddy) or a cloud offering such as AWS ALB for this. Look for a service that can receive http/1, 2, 3 traffic and forward it as http/2 to hyperx.\n\n### Data streaming\n\nBoth server and client support data streaming. The [data stream example](https://github.com/nitely/nim-hyperx/blob/master/examples/dataStream.nim) shows how to transfer 1GB of total data with minimal memory usage. Increasing the data size won't increase the memory usage.\n\n### Backpressure\n\nBackpressure is based on the http2 spec flow-control. The amount of data a connection can process at a time is bounded by the flow-control window size. The initial window size is set to 256KB. Not calling recv in time will buffer up to window size of data.\n\nThe window size can be set using the `hyperxWindowSize` define. For example `-d:hyperxWindowSize:65536` will set the size to the http/2 spec default of 64KB. Setting a window smaller than 64KB is not well supported.\n\nThere is built-in backpressure based on bounded queues for the rest of non-data frames.\n\n### Using http/2 in place of WebSockets\n\nHttp/2 allows full-duplex data communication over a single stream. If you plan to only ever use this client and server, you won't need websockets.\n\nHowever, web-browsers do not support full-duplex streaming. So http/2 cannot be used in place of websockets there.\n\n### Benchmarks\n\nThe CI runs h2load on it, but it only starts a single server instance. Proper benchmarking would start a server per CPU, and run a few combinations of load. See [issue #5](https://github.com/nitely/nim-hyperx/issues/5#issuecomment-2480527542).\n\nAlso try:\n\n- release: `-d:release` always compile in release mode.\n- refc: `--mm:refc` use refc GC instead of ORC.\n- orc: use orc in Nim +2.2.2.\n- h2c: disable TLS `newServer(..., ssl = false)` and use h2load `-ph2c` parameter\n- localServer.nim: it will respond \"hello world\" or any data it receives. You may want to tweak it to not send any data.\n- start a server instance per CPU and use `taskset` to set the process CPU affinity.\n- make sure the bench tool is hitting all server instances, not just one.\n- using [yasync](https://github.com/yglukhov/yasync) shows higher throughput and lower latency.\n\n### ORC\n\nNim's stdlib async creates cycles, and the ORC cycle collector does not run often enough. If you want to use orc, you'll need to call `GC_runOrc()` at some point, for example on client close or stream close. Related [nim issue](https://github.com/nim-lang/Nim/issues/21631). `--mm:refc` does not have this issue.\n\nThis has been fixed in Nim +2.2.2.\n\n### Related libs\n\n- [nim-grpc](https://github.com/nitely/nim-grpc)\n\n## LICENSE\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitely%2Fnim-hyperx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitely%2Fnim-hyperx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitely%2Fnim-hyperx/lists"}