diff --git a/src/cowboy_bridge_modules/cowboy_simple_bridge_sup.erl b/src/cowboy_bridge_modules/cowboy_simple_bridge_sup.erl index 5a64df3..313dce9 100644 --- a/src/cowboy_bridge_modules/cowboy_simple_bridge_sup.erl +++ b/src/cowboy_bridge_modules/cowboy_simple_bridge_sup.erl @@ -7,7 +7,7 @@ start_link/0, init/1, get_dispatch_info/2 -]). + ]). %% =================================================================== %% API functions @@ -24,54 +24,69 @@ init([]) -> application:ensure_all_started(cowboy), {Address, Port} = simple_bridge_util:get_address_and_port(cowboy), IP = simple_bridge_util:parse_ip(Address), - + io:format("Starting Cowboy Server on ~p:~p~n", - [IP, Port]), - + [IP, Port]), + Dispatch = generate_dispatch(), io:format("Using Cowboy Dispatch Table:~n ~p~n",[Dispatch]), - + Opts = #{env => #{dispatch => Dispatch}, - max_keepalive => 100}, - + max_keepalive => 100}, + %% TODO: This should be cowboy:start_tls ir using TLS. cowboy:start_clear(http, [{ip, IP}, {port, Port}], Opts), - + {ok, { {one_for_one, 5, 10}, []}}. %% @doc Generates the dispatch based on the desired environment -%% 1) First it checks if there's a cowboy_dispatch config, if there is, it uses +%% 1) First get dispatch strategy, that can be override or merge +%% 2) Then it checks if there's a cowboy_dispatch config, if there is, it uses %% that. -%% 2) Then it checks for cowboy_dispatch_fun, which is a tuple +%% 3) Then it checks for cowboy_dispatch_fun, which is a tuple %% {Module,Function} and uses the result of calling Module:Function() -%% 3) Finally, if all else fails, it uses the provided document_root and +%% 4) Finally, if all else fails, it uses the provided document_root and %% static_paths config values standard to simple_bridge to generate a %% cowboy-specific dispatch table. -generate_dispatch() -> - case application:get_env(simple_bridge, cowboy_dispatch) of - {ok, Dispatch} -> Dispatch; +generate_dispatch() -> + DispatchStrategy = case application:get_env(simple_bridge, dispatch_strategy) of + {ok, override} -> override; + {ok, merge} -> merge; + _ -> override + end, + Dispatches = case application:get_env(simple_bridge, cowboy_dispatch) of + {ok, CustomDispatches} -> + if + DispatchStrategy =:= override -> CustomDispatches; + true -> make_default_dispatch(CustomDispatches) + end; undefined -> case application:get_env(simple_bridge, cowboy_dispatch_fun) of {ok, {M,F}} -> - M:F(); + CustomDispatches = M:F(), + if + DispatchStrategy =:= override -> CustomDispatches; + true -> make_default_dispatch(CustomDispatches) + end; undefined -> - build_dispatch() + make_default_dispatch([]) end - end. + end, + build_dispatch(Dispatches). + %% @doc Gets the environment variables document_root and static_paths, and %% generates dispatches from them -build_dispatch() -> +make_default_dispatch(CustomRoutes) -> {DocRoot, StaticPaths} = simple_bridge_util:get_docroot_and_static_paths(cowboy), - io:format("Static Paths: ~p~nDocument Root for Static: ~s~n", - [StaticPaths, DocRoot]), - build_dispatch(DocRoot, StaticPaths). - -%% @doc Generate the dispatch tables -build_dispatch(DocRoot,StaticPaths) -> + io:format("Static Paths: ~p~nDocument Root for Static: ~s~nCustom Routes: ~p~n", + [StaticPaths, DocRoot, CustomRoutes]), {StaticDispatches,HandlerModule,HandlerOpts} = get_dispatch_info(DocRoot,StaticPaths), + StaticDispatches ++ CustomRoutes ++ [{'_', HandlerModule , HandlerOpts}]. +%% @doc Generate the dispatch items +build_dispatch(Dispatches) -> %% Start Cowboy... %% NOTE: According to Loic, there's no way to pass the buck back to cowboy %% to handle static dispatch files so we want to make sure that any large @@ -81,33 +96,30 @@ build_dispatch(DocRoot,StaticPaths) -> %% %% Simple Bridge will do its best to efficiently handle static files, if %% necessary but it's recommended to just make sure you properly use the - %% static_paths, or rewrite cowboy's dispatch table + %% static_paths, or rewrite cowboy's dispatch table BaseDispatch=[ - %% Nitrogen will handle everything that's not handled in the StaticDispatches - {'_', StaticDispatches ++ [{'_', HandlerModule , HandlerOpts}]} - ], - cowboy_router:compile(BaseDispatch). + %% Nitrogen will handle everything that's not handled in the StaticDispatches + {'_', Dispatches} + ], + cowboy_router:compile(BaseDispatch). %% @doc Return base, Nitrogen-specific dispatch information (potentially %% reusable by third-parties get_dispatch_info(DocRoot,StaticPaths) -> StaticDispatches = lists:map(fun(Dir) -> - Path = reformat_path(Dir), - {StaticType, StaticFileDir} = localized_dir_file(DocRoot, Dir), - Opts = [{mimetypes, cow_mimetypes, all}], - %% This will end up being something like: - %% { [<<"js">>,'...'], cowboy_static, {dir, "./priv/static/js", Opts}} - {Path, cowboy_static, {StaticType, StaticFileDir, Opts}} - end,StaticPaths), - + Path = reformat_path(Dir), + {StaticType, StaticFileDir} = localized_dir_file(DocRoot, Dir), + Opts = [{mimetypes, cow_mimetypes, all}], + %% This will end up being something like: + %% { [<<"js">>,'...'], cowboy_static, {dir, "./priv/static/js", Opts}} + {Path, cowboy_static, {StaticType, StaticFileDir, Opts}} + end,StaticPaths), + %% HandlerModule will end up calling HandlerModule:handle(Req,HandlerOpts) HandlerModule = simple_bridge_util:get_anchor_module(cowboy), - HandlerOpts = [], - + HandlerOpts = [], {StaticDispatches,HandlerModule,HandlerOpts}. - - localized_dir_file(DocRoot,Path) -> NewPath = case hd(Path) of $/ -> DocRoot ++ Path; diff --git a/src/webmachine_bridge_modules/webmachine_simple_bridge_sup.erl b/src/webmachine_bridge_modules/webmachine_simple_bridge_sup.erl index 22bfe3e..b3e0f03 100644 --- a/src/webmachine_bridge_modules/webmachine_simple_bridge_sup.erl +++ b/src/webmachine_bridge_modules/webmachine_simple_bridge_sup.erl @@ -5,7 +5,7 @@ -export([ start_link/0, init/1 -]). + ]). %% Helper macro for declaring children of supervisor -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). @@ -25,17 +25,17 @@ init([]) -> application:start(inets), application:start(crypto), application:load(webmachine), - + {Address, Port} = simple_bridge_util:get_address_and_port(webmachine), Dispatch = generate_dispatch(), - + io:format("Starting Webmachine Server on ~p:~p~n", [Address, Port]), - + Options = [ - {ip, Address}, - {port, Port}, - {dispatch, Dispatch} - ], + {ip, Address}, + {port, Port}, + {dispatch, Dispatch} + ], Web = {webmachine_mochiweb, {webmachine_mochiweb, start, [Options]}, permanent, 5000, worker, [mochiweb_socket_server]}, @@ -43,36 +43,49 @@ init([]) -> {ok, _} = application:ensure_all_started(webmachine), {ok, { {one_for_one, 5, 10}, Processes} }. -generate_dispatch() -> - case application:get_env(simple_bridge, webmachine_dispatch) of - {ok, Dispatch} -> Dispatch; +generate_dispatch() -> + DispatchStrategy = case application:get_env(simple_bridge, dispatch_strategy) of + {ok, override} -> override; + {ok, merge} -> merge; + _ -> override + end, + Dispatches = case application:get_env(simple_bridge, webmachine_dispatch) of + {ok, CustomDispatches} -> + if + DispatchStrategy =:= override -> CustomDispatches; + true -> make_default_dispatch(CustomDispatches) + end; undefined -> case application:get_env(simple_bridge, webmachine_dispatch_fun) of {ok, {M,F}} -> - M:F(); + CustomDispatches = M:F(), + if + DispatchStrategy =:= override -> CustomDispatches; + true -> make_default_dispatch(CustomDispatches) + end; undefined -> - build_dispatch() + make_default_dispatch([]) end - end. + end, + build_dispatch(Dispatches). -build_dispatch() -> +make_default_dispatch(CustomRoutes) -> {DocRoot, StaticPaths} = simple_bridge_util:get_docroot_and_static_paths(webmachine), - io:format("Static Paths: ~p~nDocument Root for Static: ~s~n", - [StaticPaths, DocRoot]), - build_dispatch(DocRoot, StaticPaths). - - -build_dispatch(DocRoot, StaticPaths) -> - Handler = simple_bridge_util:get_env(handler), + io:format("Static Paths: ~p~nDocument Root for Static: ~s~nCustom Routes: ~p~n", + [StaticPaths, DocRoot, CustomRoutes]), + %% Static content handlers can be defined manually like so: + %% {["js", '*'], webmachine_simple_bridge_static, [{root, "./site/static/js"}]}, + %% {["css", '*'], webmachine_simple_bridge_static, [{root, "./site/static/css"}]}, + %% {["images", '*'], webmachine_simple_bridge_static, [{root, "./site/static/images"}]}, + %% + %% But instead of doing it manually, we'll load it from the configuration StaticDispatches = [make_static_dispatch(DocRoot, StaticPath) || StaticPath <- StaticPaths], - StaticDispatches ++ [ - %% Static content handlers can be defined manually like so: - %% {["js", '*'], webmachine_simple_bridge_static, [{root, "./site/static/js"}]}, - %% {["css", '*'], webmachine_simple_bridge_static, [{root, "./site/static/css"}]}, - %% {["images", '*'], webmachine_simple_bridge_static, [{root, "./site/static/images"}]}, - %% - %% But instead of doing it manually, we'll load it from the configuration + StaticDispatches ++ CustomRoutes. + +build_dispatch(Dispatches) -> + Handler = simple_bridge_util:get_env(handler), + Dispatches ++ [ %% Add routes to your modules here. The last entry makes the %% system use simple_bridge's handler, which is a generic handler for %% all non-static requests, and uses the `handler` configuration @@ -85,7 +98,7 @@ build_dispatch(DocRoot, StaticPaths) -> %% {["path","to","module2",'*'], HandlerModule2, InitialState2} %% {["path","to","module3",'*'], HandlerModule3, InitialState3} {['*'], simple_bridge_util:get_anchor_module(webmachine), Handler} - ]. + ]. join_path(Root,Path) when is_binary(Root) orelse is_binary(Path) -> join_path(wf:to_list(Root),wf:to_list(Path));