-module(ehttpd). -compile(export_all). -record(counter, {id, value}). start() -> start(8889). start(Port) -> erlang:process_flag(trap_exit, true), application:start(mnesia), Args = [{attributes, record_info(fields, counter)}], {atomic, ok} = mnesia:create_table(counter, Args), Write = fun(N) -> ok = mnesia:dirty_write(#counter{id = N, value = 0}) end, lists:foreach(Write, lists:seq(0, 99999)), N = erlang:system_info(schedulers), listen(Port, N), io:format("ready with ~b schedulers on port ~b~n", [N, Port]), receive Any -> io:format("~p~n", [Any]) end. listen(Port, N) -> Opts = [{active, false}, binary, {backlog, 100}, {packet, http}, {reuseaddr, true}], {ok, S} = gen_tcp:listen(Port, Opts), Spawn = fun(_) -> spawn_link(?MODULE, accept, [S]) end, lists:foreach(Spawn, lists:seq(1, N)). accept(S) -> case gen_tcp:accept(S) of {ok, CS} -> spawn(?MODULE, loop, [CS]); Error -> erlang:error(Error) end, accept(S). loop(S) -> case gen_tcp:recv(S, 0) of {ok, http_eoh} -> {atomic, N} = mnesia:transaction(fun update_counter/0), Value = integer_to_list(N), Length = integer_to_list(length(Value)), Response = ["HTTP/1.1 200 OK\r\n" "Content-Length: ", Length, "\r\n", "\r\n", Value], gen_tcp:send(S, Response), gen_tcp:close(S); {ok, _Data} -> loop(S); Error -> Error end. update_counter() -> Id = element(3, erlang:now()) div 10, [#counter{value = V} = C] = mnesia:read(counter, Id, write), mnesia:write(C#counter{value = V + 1}), V.