Skip to content

Instantly share code, notes, and snippets.

@AntonRich
Last active September 10, 2021 16:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AntonRich/ccfb68861d2222d36121c695c37a491b to your computer and use it in GitHub Desktop.
Save AntonRich/ccfb68861d2222d36121c695c37a491b to your computer and use it in GitHub Desktop.
Very basic HTTP server in Elixir. Trying to learn the concept of Supervision.
defmodule HttpServer do
require Logger # because Logger built in part with macros
@port 8000
@http_options [active: false, packet: :http_bin, reuseaddr: true]
def start_link() do
spawn_link(HttpServer, :init, [])
end
def init() do
Process.flag(:trap_exit, true)
start_listener()
|> supervise()
end
def supervise(socket) do
receive do
{:EXIT, pid, reason} ->
Logger.error("Listener process (#{inspect(pid)}) Crashed. #{reason}")
:gen_tcp.close(socket)
start_listener()
|> supervise()
end
end
def start_listener() do
{:ok, socket} = :gen_tcp.listen(@port, @http_options)
IO.inspect socket, label: "START_LISTENER SOCKET :: :"
pid = spawn_link(HttpServer, :accept, [socket])
Logger.info("Listener started #{inspect(pid)}")
socket
end
def accept(socket) do
IO.inspect socket, label: "ACCEPT SOCKET :: :"
{:ok, client} = :gen_tcp.accept(socket)
IO.inspect client, label: "CLIENT :: :: :"
pid = spawn(HttpServer, :handle, [client])
:ok = :gen_tcp.controlling_process(client, pid)
accept(socket)
end
def handle(client) do
Logger.info("Servicing a new request on pid #{inspect(self())}")
body = "Hello from Elixir #{inspect(self())}"
:gen_tcp.send(client, view(body))
:gen_tcp.close(client)
end
def view(body) do
[
"HTTP/1.1 200\n",
"Content-Type: text/html\n",
"Content-Length: ",
"#{byte_size(body)}",
"\n\n",
body
]
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment