Awesome
Catflap
This is a small CLI tool for unix-likes that creates a TCP socket at the address you tell it to, then passes its FD index to a child process using an environment variable. The child (or any descendants) can then bind the socket.
The idea is for tools that reload servers, for instance cargo watch:
$ catflap cargo watch
[Catflap listening at 127.0.0.1:5000]
[Running 'cargo run']
Compiling sample-server v0.1.0 (file:///home/code/rust/test)
Finished dev [unoptimized + debuginfo] target(s) in 0.71 secs
Running `target/debug/sample-server`
Binding to socket FD 3
Serving requests...
[[ Some file is changed so the server is reloaded ]]
[Running 'cargo run']
Compiling sample-server v0.1.0 (file:///home/code/rust/test)
Finished dev [unoptimized + debuginfo] target(s) in 0.84 secs
Running `target/debug/sample-server`
Binding to socket FD 3
Serving requests...
[[ etc ]]
Servers that bind to ports might encounter EADDRINUSE and similar errors, as they attempt to listen on the same address but before the OS has freed them. Additionally, because the socket is always bound, requests simply wait for the program to answer them instead of failing when the server is restarting, leading to a better development experience.
Often, process supervisors implement this functionality, for example systemd, lithos, or the Flask dev server. Catflap is a single-purpose tool that does this and only this, so it can be used without all the configuration or dependence on a particular framework, and it can thus be plugged into your development workspace at very little cost.
Install
You should probably use systemfd instead! It does the same thing but follows systemd semantics closely.
The usual way:
$ cargo install catflap
Or, to upgrade:
$ cargo install --force catflap
Usage
$ catflap [options] [--] <command> [args...]
$ catflap -e LISTEN_FDS -- <command> [args...]
$ catflap -h 0.0.0.0 [--] <command> [args...]
$ catflap -p 8000 [--] <command> [args...]
Option | Default | Description |
---|---|---|
-e , --env | LISTEN_FD | Environment variable that will hold the socket's FD. |
-h , --host | 127.0.0.1 | IP address (IPv4 or IPv6, no domain names) to bind the socket to. |
-p , --port | 5000 | Port to bind the socket to. |
Command specifics
The <command>
is executed directly, without passing through a shell, so
shellisms cannot be used directly. Additionally, you'll want to use --
to
separate catflap options from program options:
$ catflap 'foo && bar'
# Will error because 'foo && bar' doesn't exist in PATH
$ catflap sh -c 'foo && bar'
# Will error because '-c' is not a catflap option
$ catflap -- sh -c 'foo && bar'
# Will work!
Port zero
If you specify port zero, the system will pick an unused high port at random. Catflap prints the socket's actual address right before it execs the given command, so you can find the right port to connect to.
$ catflap -p 0 cargo watch
[Catflap listening at 127.0.0.1:55917]
Example servers
These can be built and run directly in the respective folder.
Then simply: $ curl -i http://localhost:5000
.
Etc
Licensed under MIT. Made by Félix Saparelli.
The name is both because it's a small door that you install so that you don't
have to constantly open and close and open and close a bigger door for your
furry companion, and as a play on the netcat
tool.