defmodule CaaS do
use GenServer
def start_link(args) do
# GenServer.start_link(__MODULE__, :init, [socket])
pid = spawn(__MODULE__, :init, [args])
{:ok, pid}
end
def init(args = %{password: _}) do
socket =
receive do
{:pass_socket, socket} -> socket
end
:inet.setopts(socket, packet: 4)
auth = "auth:" <> args.password
case :gen_tcp.recv(socket, 0) do
{:ok, ^auth} ->
:gen_tcp.send(socket,"auth ok\r\n")
worker(socket, [])
{:ok, unk} ->
:gen_tcp.send(socket, "auth error\r\n")
:gen_tcp.close(socket)
end
end
def worker(socket, context) do
{:ok, data} = :gen_tcp.recv(socket, 0)
IO.puts("received #{inspect(data)}")
context =
try do
{res, context} = Code.eval_string(data, context)
# IO.inspect(context)
:gen_tcp.send(socket, inspect(res))
IO.inspect(res)
context
catch
a, b ->
IO.puts("error #{inspect(a)} #{inspect(b)}")
IO.puts("#{inspect(__STACKTRACE__)}")
:gen_tcp.send(socket, "error\r\n#{inspect(b)}")
context
end
__MODULE__.worker(socket, context)
end
end
defmodule CaaS.Acceptor do
use GenServer
def start_link(%{port: port} = args) do
GenServer.start_link(__MODULE__, args, [])
end
def init(%{port: port, password: password} = args) do
params = %{
password: password
}
IO.puts("caas listen on port #{port}")
{:ok, listenSocket} =
:gen_tcp.listen(port, [
{:ip, {0, 0, 0, 0}},
{:active, false},
{:reuseaddr, true},
{:nodelay, true},
:binary
])
{:ok, _} = :prim_inet.async_accept(listenSocket, -1)
{:ok, %{listen_socket: listenSocket, clients: [], params: params}}
end
def handle_info(
{:inet_async, listenSocket, _, {:ok, clientSocket}},
state = %{params: %{} = params}
) do
:prim_inet.async_accept(listenSocket, -1)
{:ok, pid} = CaaS.start_link(params)
:inet_db.register_socket(clientSocket, :inet_tcp)
:gen_tcp.controlling_process(clientSocket, pid)
send(pid, {:pass_socket, clientSocket})
Process.monitor(pid)
{:noreply, %{state | clients: [pid | state.clients]}}
end
def handle_info({:inet_async, _listenSocket, _, error}, state) do
IO.puts(
"#{inspect(__MODULE__)}: Error in inet_async accept, shutting down. #{inspect(error)}"
)
{:stop, error, state}
end
def handle_info(_, state) do
{:noreply, state}
end
def handle_call(:get_clients, _from, state) do
{:reply, state.clients, state}
end
end