Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

refactoring and documentation

  • Loading branch information...
commit 23400f879f8b28810feaf8fc9070c4c85831acbe 1 parent f914ee7
@davebryson authored
View
91 src/beepbeep.erl
@@ -1,15 +1,37 @@
+%% @author Dave Bryson [http://weblog.miceda.org]
+%% @copyright Dave Bryson 2008-2009
%%
-%% Dispatcher called from the mochiweb server
+%% @doc BeepBeep Dispatcher
+%%
+%% This is called from the MochiWeb server to dispatch
+%% requests. Requests are mapped to modules (controllers) and
+%% functions (actions) based on path components in the Url. For
+%% example, the request:
+%%
+%% '/feed/show'
+%%
+%% would get mapped to the module (controller) 'feed' and the function
+%% (action) 'show'.
+%% By default the root request:
+%%
+%% '/'
+%%
+%% is automatically mapped to the module 'home' and the function 'index'
%% Maps Urls to controllers and their views
%%
-module(beepbeep).
-author('Dave Bryson <http://weblog.miceda.org>').
--export([dispatch/1,get_view_file/1]).
+-export([dispatch/1,render_template/3]).
+%%
+%% @doc Dispatches the incoming request to the proper module
+%% and function and returns the tuple() from the controller.
+%%
+%% @spec dispatch(Env::record()) -> tuple()
+%%
dispatch(Env) ->
PathComponents = beepbeep_args:path_components(Env),
- %% Map the request to our app
{ControllerName,ActionName,Args} = case PathComponents of
[] ->
{"home","index",[]};
@@ -22,38 +44,26 @@ dispatch(Env) ->
{ok,Controller} ->
process_request(Env,Controller,ActionName,Args);
no_controller ->
- %% Try static
+ %% Try static content using the PATH_INFO
F = beepbeep_args:path(Env),
{static, F}
end.
-
-get_view_file(ViewFile) ->
- %%filename:join([get_base_dir()|["views",ViewFile]]),
- beepbeep_router:get_view(ViewFile).
-
-
-%%get_static_path() ->
-%% filename:join([get_base_dir()|["www"]]).
-
-
-%%% Internal below
-%%get_base_dir() ->
-%% {file, Here} = code:is_loaded(?MODULE),
-%% filename:dirname(filename:dirname(Here)).
-
process_request(Env,ControllerName,ActionName,Args) ->
Env1 = beepbeep_args:set_action(Env,ActionName),
- error_logger:info_report(Env1),
Controller = ControllerName:new(Env1),
+ %%
+ %% First try the before_filter. If the call returns 'ok', then try the
+ %% action call. If the action call returns any kind of exit, return
+ %% {error,no_action}. Otherwise return the response from the Controller
+ %%
case try_filter(Controller) of
ok ->
case catch(Controller:handle_request(ActionName,Args)) of
{'EXIT',_} ->
{error,no_action};
- Response ->
- handle_response(Response)
+ Response -> Response
end;
Any ->
Any
@@ -61,38 +71,15 @@ process_request(Env,ControllerName,ActionName,Args) ->
try_filter(ControllerName) ->
case catch(ControllerName:before_filter()) of
- {'EXIT', {undef,_}} ->
- ok;
- Any ->
- Any
+ {'EXIT', {undef,_}} -> ok;
+ Any -> Any
end.
-%% Handle all responses from controller
-handle_response({render,View,Data}) ->
- {ok,Content} = render_template(View,Data),
- {ok,200,"text/html",[],Content};
-
-handle_response({render,View,Data,Options}) ->
- {ok,Content} = render_template(View,Data),
- {ok,
- proplists:get_value(status,Options,200),
- proplists:get_value(content_type,Options,"text/html"),
- proplists:get_value(headers,Options,[]),
- Content};
-
-handle_response({text,Data}) ->
- {ok,200,"text/plain",[],Data};
-
-%% This seems stupid...better way??
-handle_response({redirect,Url}) ->
- {redirect,Url};
-
-handle_response({static,File}) ->
- {static,File}.
-
-render_template(ViewFile,Data) ->
- FullPathToFile = get_view_file(ViewFile),
- error_logger:info_msg("Trying file: ~s~n",[FullPathToFile]),
+%%
+%% @doc Render the template with the given data.
+%% This is called from YOUR_APP_web.erl automatically.
+%%
+render_template(FullPathToFile,ViewFile,Data) ->
Pieces = string:tokens(ViewFile,"/"),
Name = string:join(Pieces,"_"),
Name1 = filename:basename(Name,".html"),
View
126 src/beepbeep_args.erl
@@ -1,50 +1,94 @@
+%% @author Dave Bryson [http://weblog.miceda.org]
+%% @copyright Dave Bryson 2008-2009
%%
-%% Main BeepBeep API to use in Controllers
+%% @doc Helper functions for accessing request and session information
+%% in your controllers.
%%
-module(beepbeep_args).
--compile(export_all).
+-export([path/1,
+ path_components/1,
+ server_software/1,
+ server_name/1,
+ server_protocol/1,
+ server_port/1,
+ method/1,
+ content_type/1,
+ content_length/1,
+ remote_addr/1,
+ get_all_headers/1,
+ get_param/2,
+ get_session_id/1,
+ set_session_id/2,
+ set_session_data/3,
+ get_session_data/2,
+ get_all_session_data/1,
+ get_action/1,
+ set_action/2]).
-author('Dave Bryson <http://weblog.miceda.org>').
-%% @spec path(Env) -> Path
-%% @doc return the path
+%%
+%% @doc Return the Path
+%%
path(Env) ->
proplists:get_value("PATH_INFO",Env).
-%% @spec path_components(Env) -> []
-%% @doc return the path as an array parsed on the "/"
+%%
+%% @doc Return the Path as an array parsed on the "/"
+%%
path_components(Env) ->
string:tokens(path(Env),"/").
-%% @spec server_software(Env) -> ServerSoftware
-%% @doc return the name of the server
+%%
+%% @doc Return the name of the server
+%%
server_software(Env) ->
proplists:get_value("SERVER_SOFTWARE", Env).
-%% @spec server_name(Env) -> ServerName
-%% @doc return the hostname of the server
+%%
+%% @doc Return the hostname of the server
+%%
server_name(Env) ->
proplists:get_value("SERVER_NAME", Env).
-%% @spec server_protocol(Env) -> ServerProtocol
-%% @doc return the protocol i.e. http
+%%
+%% @doc Return the protocol
+%%
server_protocol(Env) ->
proplists:get_value("SERVER_PROTOCOL", Env).
+%%
+%% @doc Return the Server port
+%%
server_port(Env) ->
proplists:get_value("SERVER_PORT", Env).
+%%
+%% @doc Return the request method: GET,PUT,POST,DELETE
+%%
method(Env) ->
proplists:get_value("REQUEST_METHOD", Env).
+%%
+%% @doc Return the content-type
+%%
content_type(Env) ->
proplists:get_value("CONTENT_TYPE", Env).
+%%
+%% @doc Return the content_length
+%%
content_length(Env) ->
proplists:get_value("CONTENT_LENGTH", Env).
+%%
+%% @doc Return the Remote address of the client
+%%
remote_addr(Env) ->
proplists:get_value("REMOTE_ADDR", Env).
+%%
+%% @doc Return all Headers
+%%
get_all_headers(Env) ->
lists:foldl(fun({"HTTP_" ++ _, _}=Pair, Hdrs) ->
[Pair|Hdrs];
@@ -52,13 +96,25 @@ get_all_headers(Env) ->
Hdrs
end, [], Env).
+%%
+%% @doc Return a request Value for a given Key. This contains information
+%% from a form POST OR GET query string
+%%
get_param(Key,Env) ->
Params = proplists:get_value("beepbeep.data",Env),
proplists:get_value(Key,Params,"?").
+%%
+%% @doc Get the current session id
+%%
get_session_id(Env) ->
proplists:get_value("beepbeep_sid",Env).
+%%
+%% Sets the session id. This is done internally
+%% and should not be used manually
+%% @hidden
+%%
set_session_id(Value,Env) ->
case lists:keysearch("beepbeep_sid",1,Env) of
{value,_} ->
@@ -67,18 +123,37 @@ set_session_id(Value,Env) ->
[proplists:property({"beepbeep_sid", Value})|Env]
end.
-%% Helpers for accessing Session Data
-set_session_data(Env,Key,Value) ->
+%%
+%% @doc Set a Key,Value in the session
+%%
+set_session_data(Key,Value,Env) ->
Sid = get_session_id(Env),
beepbeep_session_server:set_session_data(Sid,Key,Value).
-get_session_data(Env) ->
+%%
+%% @doc Return all session data
+%%
+get_all_session_data(Env) ->
Sid = get_session_id(Env),
beepbeep_session_server:get_session_data(Sid).
+%%
+%% @doc Get the session data for a given key
+%%
+get_session_data(Key,Env) ->
+ proplists:get_value(Key,get_all_session_data(Env)).
+
+%%
+%% @doc Return the current requested action
+%%
get_action(Env) ->
proplists:get_value("action_name",Env).
+%%
+%% @doc Warning! Should not be set manually. This is
+%% done automatically in the dispather.
+%% @hidden
+%%
set_action(Env,Value) ->
case lists:keysearch("action_name",1,Env) of
{value,_} ->
@@ -87,14 +162,19 @@ set_action(Env,Value) ->
[proplists:property({"action_name", Value})|Env]
end.
-get_value(Key, Env) ->
- proplists:get_value(Key, Env).
+%%
+%% @doc Set an Key,Value in the environment.
+%% Used internally
+%% @hidden
+set_value(Key, Val, Env) ->
+ lists:keyreplace(Key, 1, Env, {Key, Val}).
+
+%% get_value(Key, Env) ->
+%% proplists:get_value(Key, Env).
-get_value(Key, Env, Default) ->
- proplists:get_value(Key, Env, Default).
+%% get_value(Key, Env, Default) ->
+%% proplists:get_value(Key, Env, Default).
-get_all_values(Key, Env) ->
- proplists:get_all_values(Key, Env).
+%% get_all_values(Key, Env) ->
+%% proplists:get_all_values(Key, Env).
-set_value(Key, Val, Env) ->
- lists:keyreplace(Key, 1, Env, {Key, Val}).
View
82 src/beepbeep_router.erl
@@ -1,63 +1,63 @@
-%%%-------------------------------------------------------------------
-%%% Author : Dave Bryson <http://weblog.mitre.org>
-%%%
-%%% Description : Maps the path of the controller to the actual controller
-%%% name as an atom. Prevents calling list_to_atom in the dispatcher which
-%%% could lead to a potential DOS attack. Thanks to Ville for catching that
-%%%
-%%%-------------------------------------------------------------------
+%% @author Dave Bryson [http://weblog.miceda.org]
+%% @copyright Dave Bryson 2008-2009
+%%
+%% @doc On start up, this module builds a mapping of the legal Controller
+%% requests based on the actually files with names ending in '_controller'
+%% in the src directory. For example, if you created two controllers:
+%%
+%% 'feed_controller' and 'login_controller'
+%%
+%% the mapping:
+%%
+%% feed -> feed_controller
+%%
+%% login -> login_controller
+%%
+%% is created. This prevents creating an atom() for every incoming
+%% request which could lead to a potential DoS attack by filling the global
+%% atom() table.
+%%
-module(beepbeep_router).
-author('Dave Bryson <http://weblog.miceda.org>').
-behaviour(gen_server).
%% API
--export([start/1,get_controller/1,view_map/0,get_view/1]).
+-export([start/1,get_controller/1,controller_map/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
--record(state,{view_path,controllers}).
-
%%
-%% Start the app with the Basedir of the application
-%% Basedir is determined in the webapp supervisor
+%% @doc Start the app with the Basedir of the application.
+%% Basedir is determined in the supervisor
%%
start(BaseDir) ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, BaseDir, []).
+ gen_server:start_link({local, ?MODULE}, ?MODULE,BaseDir,[]).
%%
-%% Given the name of the controller called in the URL
-%% return the module name
+%% @doc Given the name of the controller in the URL
+%% return the module name in the mapping
%%
get_controller(Controller) ->
gen_server:call(?MODULE,{get_controller,Controller}).
%%
-%% Return the fullpath and name of the requested template
+%% @doc Simple helper to view the name-controller mapping
%%
-get_view(Name) ->
- gen_server:call(?MODULE,{get_view,Name}).
-
-%%
-%% Simple helper to view the name-controller mapping
-%%
-view_map() ->
+controller_map() ->
gen_server:call(?MODULE,view).
+%% @hidden
init(BaseDir) ->
- %% Get the base directory for views
- ViewPath = filename:join([BaseDir,"views"]),
- %% Load the controllers
- Controllers = load_controllers(BaseDir),
- State = #state{view_path=ViewPath,controllers=Controllers},
- {ok, State}.
+ {ok, load_controllers(BaseDir)}.
%% ---------Callbacks------------------------------
+
+%% @hidden
handle_call({get_controller,Controller},_From, State) ->
- ControllerList = State#state.controllers,
- Reply = case lists:keysearch(Controller,1,ControllerList) of
+ Reply = case lists:keysearch(Controller,1,State) of
{value,{_,C}} ->
{ok,C};
false ->
@@ -65,24 +65,21 @@ handle_call({get_controller,Controller},_From, State) ->
end,
{reply, Reply, State};
-handle_call({get_view,Name},_From,State) ->
- Base = State#state.view_path,
- TemplatePath = filename:join([Base,Name]),
- {reply,TemplatePath,State};
-
+%% @hidden
handle_call(view,_From,State) ->
- ControllerList = State#state.controllers,
- io:format("~p~n",[ControllerList]),
+ error_logger:info_msg("Controller Map:~n~p~n",[State]),
{reply,ok,State}.
+%% @hidden
handle_cast(_Msg, State) ->
{noreply, State}.
-
+%% @hidden
handle_info(_Info, State) ->
{noreply, State}.
-
+%% @hidden
terminate(_Reason, _State) ->
ok.
+%% @hidden
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -90,12 +87,9 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%--------------------------------------------------------------------
list_controllers(BaseDir) ->
- %%{file, Here} = code:is_loaded(?MODULE),
- %%BaseDir = filename:dirname(filename:dirname(Here)),
Path = filename:join([BaseDir,"src","*_controller.erl"]),
filelib:wildcard(Path).
-
load_controllers(BaseDir) ->
lists:foldl(fun(File,Acc) ->
OrgName = filename:basename(File,".erl"),
View
15 src/beepbeep_session_server.erl
@@ -1,9 +1,12 @@
-%%%-------------------------------------------------------------------
-%%% Description : Maintains session information for the client. All data is stored
-%%% on the server. Only a unique session id is exchanged with the client.
-%%% Inspired by the Yaws Session Server.
-%%%
-%%%-------------------------------------------------------------------
+%% @author Dave Bryson [http://weblog.miceda.org]
+%% @copyright Dave Bryson 2008-2009
+%% @hidden
+%%-------------------------------------------------------------------
+%% Description : Maintains session information for the client. All data is stored
+%% on the server. Only a unique session id is exchanged with the client.
+%% Inspired by the Yaws Session Server.
+%%
+%%-------------------------------------------------------------------
-module(beepbeep_session_server).
-author('Dave Bryson <http://weblog.miceda.org>').
View
5 src/beepbeep_skel.erl
@@ -1,9 +1,8 @@
--module(beepbeep_skel).
-
-
%% This is a direct copy of mochiweb_skel I've only changed a few
%% things for my purposes
+%% @hidden
+-module(beepbeep_skel).
-export([skelcopy/2]).
-include_lib("kernel/include/file.hrl").
View
3  src/mochiweb_env.erl
@@ -1,7 +1,8 @@
-%% This code is adapted from the ewgi project:
+%% @doc This code is adapted from the ewgi project:
%% http://code.google.com/p/ewgi/
%% In the future BeepBeep may use the ewgi interface
%% to support both mochiweb and yaws
+%% @hidden
-module(mochiweb_env).
-export([setup_environment/1]).
Please sign in to comment.
Something went wrong with that request. Please try again.