I’m trying to create a simple app in Crystal that is basically a TCP proxy (opens a TCP port and forwards connections to another port), and the proxy also accepts some simple commands on the STDIN while running, like:
- drop the current connection and don’t accept any other while otherwise told,
- start listening for incoming connections again,
- change the listen port to N,
- change the connect port to M, etc.
I know how to parse the STDIN commands, how to listen for TCP connections (TCPServer listen, accept) and how to open TCP connections to others (TCPSocket), but cannot figure out how to organize my code in order to be able to wait for events from any of the input channgels: STDIN, the accepted TCP connection (it’s fine to handle only 1 accepted connection on the input side at the same time), and the forward TCP connection. Is there a way to select/poll/epoll on these 3 at the same time? The
select ... end construct is a nice one, but only works for channels, right?
Putting these things in separate Fibers seemd like a good idea (that brings
select .. end back to the game), but then the fibers have to communicate over channels. Isn’t that going to be slow?
If I go with Fibers: let’s say the incoming TCP connection handler Fiber is sitting in an accept indefinitely. What if a command arrives that asks to change the listen port? How can I stop the acceptor Fiber in this case? As far as I know there’s no way to kill a Fiber from outside, but also impossible to wake a Fiber up when it is in a TCPServer
accept and no client connect to the TCP port.
Do you have any suggestions on how to to this?
By the way, do you think that Crystal is not the right tool for this problem?