{"id":13587076,"url":"https://github.com/passcod/catflap","last_synced_at":"2025-04-07T19:30:41.105Z","repository":{"id":54214066,"uuid":"89670931","full_name":"passcod/catflap","owner":"passcod","description":"🐈🚪 Creates listening sockets and passes their FDs to a child process. You should probably use systemfd instead!","archived":true,"fork":false,"pushed_at":"2021-03-03T03:59:02.000Z","size":72,"stargazers_count":142,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-28T02:22:40.953Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/passcod.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-04-28T05:32:39.000Z","updated_at":"2024-08-19T14:15:39.000Z","dependencies_parsed_at":"2022-08-13T09:20:39.082Z","dependency_job_id":null,"html_url":"https://github.com/passcod/catflap","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passcod%2Fcatflap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passcod%2Fcatflap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passcod%2Fcatflap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/passcod%2Fcatflap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/passcod","download_url":"https://codeload.github.com/passcod/catflap/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247716069,"owners_count":20984168,"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":[],"created_at":"2024-08-01T15:06:00.386Z","updated_at":"2025-04-07T19:30:40.672Z","avatar_url":"https://github.com/passcod.png","language":"Rust","readme":"# Catflap\n\n[![Crate release version](https://img.shields.io/crates/v/catflap.svg?style=flat-square)](https://crates.io/crates/catflap)\n[![Crate license: MIT](https://img.shields.io/crates/l/catflap.svg?style=flat-square)](https://passcod.mit-license.org)\n[![Crate download count](https://img.shields.io/crates/d/catflap.svg?style=flat-square)](https://crates.io/crates/catflap#crate-downloads)\n[![Build status (Travis)](https://img.shields.io/travis/passcod/catflap.svg?style=flat-square)](https://travis-ci.org/passcod/cargo-watch)\n\nThis is a small CLI tool for unix-likes that creates a TCP socket at the\naddress you tell it to, then passes its FD index to a child process using an\nenvironment variable. The child (or any descendants) can then bind the socket.\n\nThe idea is for tools that reload servers, for instance [cargo watch]:\n\n[cargo watch]: https://github.com/passcod/cargo-watch\n\n```\n$ catflap cargo watch\n[Catflap listening at 127.0.0.1:5000]\n[Running 'cargo run']\n   Compiling sample-server v0.1.0 (file:///home/code/rust/test)\n    Finished dev [unoptimized + debuginfo] target(s) in 0.71 secs\n     Running `target/debug/sample-server`\nBinding to socket FD 3\nServing requests...\n\n[[ Some file is changed so the server is reloaded ]]\n\n[Running 'cargo run']\n   Compiling sample-server v0.1.0 (file:///home/code/rust/test)\n    Finished dev [unoptimized + debuginfo] target(s) in 0.84 secs\n     Running `target/debug/sample-server`\nBinding to socket FD 3\nServing requests...\n\n[[ etc ]]\n```\n\nServers that bind to _ports_ might encounter EADDRINUSE and similar errors, as\nthey attempt to listen on the same address but before the OS has freed them.\nAdditionally, because the socket is always bound, requests simply wait for the\nprogram to answer them instead of failing when the server is restarting,\nleading to a better development experience.\n\nOften, process supervisors implement this functionality, for example [systemd],\n[lithos], or the [Flask dev server][werkzeug]. Catflap is a single-purpose tool\nthat does this and only this, so it can be used without all the configuration\nor dependence on a particular framework, and it can thus be plugged into your\ndevelopment workspace at very little cost.\n\n[lithos]: https://lithos.readthedocs.io/en/latest/tips/tcp-ports.html\n[systemd]: http://0pointer.de/blog/projects/socket-activation.html\n[werkzeug]: https://github.com/pallets/werkzeug/blob/a2a5f5a4c04c5b1fb33709bc2cdc297cd8fb46a3/werkzeug/serving.py#L649-L660\n\n## Install\n\n**You should probably use [systemfd](https://github.com/mitsuhiko/systemfd) instead!** It does the same thing but follows systemd semantics closely.\n\nThe usual way:\n\n```\n$ cargo install catflap\n```\n\nOr, to upgrade:\n\n```\n$ cargo install --force catflap\n```\n\n## Usage\n\n```\n$ catflap [options] [--] \u003ccommand\u003e [args...]\n\n$ catflap -e LISTEN_FDS -- \u003ccommand\u003e [args...]\n$ catflap -h 0.0.0.0 [--] \u003ccommand\u003e [args...]\n$ catflap -p 8000 [--] \u003ccommand\u003e [args...]\n```\n\n|Option|Default|Description|\n|---|---|---|\n|`-e`, `--env`|`LISTEN_FD`|Environment variable that will hold the socket's FD.|\n|`-h`, `--host`|`127.0.0.1`|IP address (IPv4 or IPv6, no domain names) to bind the socket to.|\n|`-p`, `--port`|`5000`|Port to bind the socket to.|\n\n### Command specifics\n\nThe `\u003ccommand\u003e` is executed directly, without passing through a shell, so\nshellisms cannot be used directly. Additionally, you'll want to use `--` to\nseparate catflap options from program options:\n\n```\n$ catflap 'foo \u0026\u0026 bar'\n# Will error because 'foo \u0026\u0026 bar' doesn't exist in PATH\n\n$ catflap sh -c 'foo \u0026\u0026 bar'\n# Will error because '-c' is not a catflap option\n\n$ catflap -- sh -c 'foo \u0026\u0026 bar'\n# Will work!\n```\n\n### Port zero\n\nIf you specify port zero, the system will pick an unused high port at random.\nCatflap prints the socket's actual address right before it execs the given\ncommand, so you can find the right port to connect to.\n\n```\n$ catflap -p 0 cargo watch\n[Catflap listening at 127.0.0.1:55917]\n```\n\n## Example servers\n\nThese can be built and run directly in the respective folder.\nThen simply: `$ curl -i http://localhost:5000`.\n\n- [Hyper only](./integrations/hyper).\n- [Using Iron](./integrations/iron).\n- [Express on Node.js](./integrations/express).\n\n## Etc\n\nLicensed under [MIT](https://passcod.mit-license.org).\nMade by [Félix Saparelli](https://passcod.name).\n\nThe name is both because it's a small door that you install so that you don't\nhave to constantly open and close and open and close a bigger door for your\nfurry companion, and as a play on the `netcat` tool. \n","funding_links":[],"categories":["Rust","Networking"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpasscod%2Fcatflap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpasscod%2Fcatflap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpasscod%2Fcatflap/lists"}