glisten

This is a gleam wrapper around gen_tcp loosely based on ThousandIsland.

It uses the gleam_otp library to handle the supervisor and child processes.

The general structure is similar to ThousandIsland. There is a supervisor that manages a pool of acceptors. Each acceptor will block on accept until a connection is opened. The acceptor will then spawn a handler process and then block again on accept.

The handler function loops on messages received from the socket. You can define a handler with a function of the following type:

fn(HandlerMessage, Socket) -> actor.Next(Socket)

This gives you access to the socket if you want to send to it in response. I think right now I don’t have this set up where you can send to the socket unprovoked? So that seems like something I’ll need to change… imminently.

Examples

Just some basic handler examples that do also exist in this repo, but probably won’t once it’s actually in better shape.

HTTP Hello World

pub fn ok(_msg: HandlerMessage, sock: Socket) -> actor.Next(Socket) {
  assert Ok(resp) =
    "hello, world!"
    |> bit_string.from_string
    |> http_response(200, _)
    |> bit_string.to_string

  resp
  |> charlist.from_string
  |> send(sock, _)

  actor.Stop(process.Normal)
}

Full HTTP echo handler

pub fn handler(req: Request(BitString)) -> Response(BitString) {
  response.new(200)
  |> response.set_body(req.body)
}
pub fn main() {
  assert Ok(socket) = tcp.do_listen_tcp(8000, [])
  try _ = tcp.start_acceptor_pool(socket, make_handler(handler), 10)

  Ok(erlang.sleep_forever())
}

Notes

This is still very rough. There are no tests, and as noted above you can’t just send where you implement it.

In some not-very-scientific benchmarking, it seemed to do roughly as well as ThousandIsland. I am just using that as a reference point, certainly not trying to draw any comparisons any time soon!