-module(web_server). -behaviour(gen_server). -define(SERVER, ?MODULE). -define(OK, <<"ok">>). %% API -export([start_link/1, dispatch_requests/1, stop/0]). %% gen_server callbacks %% (Same old, same old. You can skip down to the handle/2 function...) -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). start_link(Port) -> gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []). init([Port]) -> mochiweb_http:start( [{port, Port}, {loop, fun(Req) -> dispatch_requests(Req) end}]), erlang:monitor(process, mochiweb_http), {ok, []}. stop() -> gen_server:cast(?SERVER, stop). dispatch_requests(Req) -> Path = Req:get(path), Action = clean_path(Path), handle(Action, Req). handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. handle_cast(stop, State) -> {stop, normal, State}; handle_cast(_Msg, State) -> {noreply, State}. handle_info({'DOWN', _, _, {mochiweb_http, _}, _}, State) -> {stop, normal, State}; handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> mochiweb_http:stop(), ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. %% This was ripped off from the following blog: %% http://willcodeforfoo.com/2009/07/29/using-mochiweb-to-create-a-webframework-in-erlang/ handle(Path, Req) -> CleanPath = clean_path(Path), CAtom = erlang:list_to_atom(top_level_request(CleanPath)), ControllerPath = parse_controller_path(CleanPath), case CAtom of home -> IndexContents = case file:read_file("www/index.html") of {ok, Contents} -> Contents; _ -> "Error

Uh oh

" end, Req:ok({"text/html", IndexContents}); assets -> Req:ok(assets:get(ControllerPath)); ControllerAtom -> Body = case Req:get(method) of 'GET' -> ControllerAtom:get(ControllerPath); 'POST' -> ControllerAtom:post(ControllerPath, decode_data_from_request(Req)); 'PUT' -> ControllerAtom:put(ControllerPath, decode_data_from_request(Req)); 'DELETE' -> ControllerAtom:delete(ControllerPath, decode_data_from_request(Req)); Other -> subst("Other ~p on: ~s~n", [users, Other]) end, Req:ok({"text/html", Body}) end. %% Helper methods: %% Parse the request body as JSON decode_data_from_request(Req) -> RecvBody = Req:recv_body(), Data = case RecvBody of <<>> -> erlang:list_to_binary("{}"); Bin -> Bin end, {struct, Struct} = mochijson2:decode(Data), Struct. % Parse the URL path parse_controller_path(CleanPath) -> case string:tokens(CleanPath, "/") of [] -> []; [_RootPath|Rest] -> Rest end. %% Strip off the query string off the URL clean_path(Path) -> case string:str(Path, "?") of 0 -> Path; N -> string:substr(Path, 1, string:len(Path) - (N+1)) end. top_level_request(Path) -> case string:tokens(Path, "/") of [CleanPath|_Others] -> CleanPath; [] -> "home" end.