#sockets #server #reload #tcp-socket #child-process #env-var

app catflap

Creates a TCP socket and passes its descriptor as an env variable

3 stable releases

Uses old Rust 2015

1.2.0 May 28, 2020
1.1.0 May 11, 2017
1.0.0 May 8, 2017

#20 in #reload

MIT license

10KB
114 lines

Catflap

Crate release version Crate license: MIT Crate download count Build status (Travis)

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

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.

Dependencies

~3MB
~58K SLoC