Create initial version of server
Just a very simple TCP echo server to get started with.
This commit is contained in:
parent
a66b817ba3
commit
bf5f517e85
2
server/.gitignore
vendored
Normal file
2
server/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
_build/*
|
||||||
|
*.beam
|
2
server/rebar.config
Normal file
2
server/rebar.config
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
{erl_opts, [debug_info]}.
|
||||||
|
{deps, []}.
|
1
server/rebar.lock
Normal file
1
server/rebar.lock
Normal file
@ -0,0 +1 @@
|
|||||||
|
[].
|
18
server/src/proto_sup.erl
Normal file
18
server/src/proto_sup.erl
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(proto_sup).
|
||||||
|
-behaviour(supervisor).
|
||||||
|
|
||||||
|
-export([start_link/1]).
|
||||||
|
-export([init/1]).
|
||||||
|
|
||||||
|
start_link(Port) ->
|
||||||
|
supervisor:start_link({local, ?MODULE}, ?MODULE, [Port]).
|
||||||
|
|
||||||
|
init([Port]) ->
|
||||||
|
SupFlags = #{stragegy => one_for_all,
|
||||||
|
intensity => 1,
|
||||||
|
period => 5},
|
||||||
|
ChildSpecs = [tcp_server:child_spec(Port)],
|
||||||
|
{ok, {SupFlags, ChildSpecs}}.
|
10
server/src/study_system_server.app.src
Normal file
10
server/src/study_system_server.app.src
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{application, study_system_server,
|
||||||
|
[{description, "Study System Server"},
|
||||||
|
{vsn, "0.1.0"},
|
||||||
|
{registered, []},
|
||||||
|
{mod, {study_system_server_app, []}},
|
||||||
|
{applications, [kernel, stdlib]},
|
||||||
|
{env, []},
|
||||||
|
{modules, []},
|
||||||
|
{licenses, ["AGPL-3.0-only"]},
|
||||||
|
{links, []}]}.
|
14
server/src/study_system_server_app.erl
Normal file
14
server/src/study_system_server_app.erl
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(study_system_server_app).
|
||||||
|
-behaviour(application).
|
||||||
|
|
||||||
|
-export([start/2, stop/1]).
|
||||||
|
|
||||||
|
start(_StartType, _StartArgs) ->
|
||||||
|
Port = application:get_env(study_system_server, port, 12888),
|
||||||
|
proto_sup:start_link(Port).
|
||||||
|
|
||||||
|
stop(_State) ->
|
||||||
|
ok.
|
65
server/src/tcp_server.erl
Normal file
65
server/src/tcp_server.erl
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
% Copyright (c) Camden Dixie O'Brien
|
||||||
|
% SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
-module(tcp_server).
|
||||||
|
-behaviour(gen_server).
|
||||||
|
|
||||||
|
-export([start_link/1, child_spec/1]).
|
||||||
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
|
terminate/2, code_change/3]).
|
||||||
|
|
||||||
|
-record(state, {socket, acceptor}).
|
||||||
|
|
||||||
|
start_link(Port) ->
|
||||||
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [Port], []).
|
||||||
|
|
||||||
|
child_spec(Port) ->
|
||||||
|
#{id => ?MODULE,
|
||||||
|
start => {?MODULE, start_link, [Port]},
|
||||||
|
restart => permanent,
|
||||||
|
shutdown => 5000,
|
||||||
|
type => worker,
|
||||||
|
modules => [?MODULE]}.
|
||||||
|
|
||||||
|
init([Port]) ->
|
||||||
|
{ok, Socket} = gen_tcp:listen(Port, [binary, {active, true}]),
|
||||||
|
Pid = spawn_link(fun() -> acceptor_loop(Socket) end),
|
||||||
|
{ok, #state{socket = Socket, acceptor = Pid}}.
|
||||||
|
|
||||||
|
handle_call(_Request, _From, State) ->
|
||||||
|
{reply, ok, State}.
|
||||||
|
|
||||||
|
handle_cast(_Msg, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
handle_info({'EXIT', Pid, Reason}, State = #state{acceptor = Pid}) ->
|
||||||
|
{stop, {acceptor_died, Reason}, State};
|
||||||
|
handle_info(_Info, State) ->
|
||||||
|
{noreply, State}.
|
||||||
|
|
||||||
|
terminate(_Reason, #state{socket = Socket}) ->
|
||||||
|
gen_tcp:close(Socket),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
code_change(_OldVsn, State, _Extra) ->
|
||||||
|
{ok, State}.
|
||||||
|
|
||||||
|
acceptor_loop(Socket) ->
|
||||||
|
case gen_tcp:accept(Socket) of
|
||||||
|
{ok, ClientSocket} ->
|
||||||
|
gen_tcp:controlling_process(
|
||||||
|
ClientSocket,
|
||||||
|
spawn(fun() -> handle_connection(ClientSocket) end)),
|
||||||
|
acceptor_loop(Socket);
|
||||||
|
{error, closed} ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
handle_connection(Socket) ->
|
||||||
|
receive
|
||||||
|
{tcp, Socket, Data} ->
|
||||||
|
gen_tcp:send(Socket, Data),
|
||||||
|
handle_connection(Socket);
|
||||||
|
{tcp_closed, Socket} ->
|
||||||
|
ok
|
||||||
|
end.
|
Loading…
x
Reference in New Issue
Block a user