defmodule Satellite do @behaviour :gen_statem defstruct [:socket, :config, :conn, pipeline: [], request: %{}] def start_link(socket, opts) do :gen_statem.start_link(__MODULE__, {socket, opts}, []) end @impl true def callback_mode(), do: :handle_event_function @impl true def init({socket, config}) do {:ok, :waiting, %__MODULE__{socket: socket, config: config}, [{:next_event, :internal, :wait}]} end @impl true def handle_event(:internal, :wait, :waiting, %{socket: socket} = data) do {:ok, conn} = :gen_tcp.accept(socket) :gen_tcp.controlling_process(conn, self()) {:next_state, :parsing, %{data | conn: conn}, [{:next_event, :internal, :read}]} end def handle_event(:internal, :read, :parsing, %{conn: conn} = data) do case :gen_tcp.recv(conn, 0, 1000) do {:ok, packet} -> IO.inspect(packet, label: "received") n_data = %{data | request: packet} {:next_state, :response, n_data, [{:next_event, :internal, :send_response}]} {:error, reason} -> IO.inspect(reason, label: "error on recv") {:keep_state, data, [{:next_event, :internal, :close}]} end end def handle_event(:internal, :send_response, :response, %{conn: conn, request: request} = data) do b = :erlang.iolist_to_binary(request) response = :io_lib.fwrite( "HTTP/1.0 200 OK\nContent-Type: text/html\nContent-Length: ~p\n\n~s", [:erlang.size(b), b] ) :gen_tcp.send(conn, response) {:keep_state, data, [{:next_event, :internal, :close}]} end def handle_event(:internal, :close, _, %{conn: conn} = data) do :gen_tcp.close(conn) {:next_state, :waiting, %{data | conn: nil, request: %{}}, [{:next_event, :internal, :wait}]} end end