%% -*- mode: nitrogen -*- %% vim: ts=4 sw=4 et -module(cowboy_simple_bridge_sup). -behaviour(supervisor). -include("simple_bridge.hrl"). -export([ start_link/0, init/1, get_dispatch_info/2 ]). %% =================================================================== %% API functions %% =================================================================== start_link() -> supervisor:start_link({local, ?MODULE}, ?MODULE, []). %% =================================================================== %% Supervisor callbacks %% =================================================================== 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]), Dispatch = generate_dispatch(), io:format("Using Cowboy Dispatch Table:~n ~p~n",[Dispatch]), Opts = #{env => #{dispatch => Dispatch}, 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 %% that. %% 2) 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 %% 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; undefined -> case application:get_env(simple_bridge, cowboy_dispatch_fun) of {ok, {M,F}} -> M:F(); undefined -> build_dispatch() end end. %% @doc Gets the environment variables document_root and static_paths, and %% generates dispatches from them build_dispatch() -> {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) -> {StaticDispatches,HandlerModule,HandlerOpts} = get_dispatch_info(DocRoot,StaticPaths), %% 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 %% files get caught in general by cowboy and are never passed to the nitrogen %% handler at all. In general, your best bet is to include the directory in %% the static_paths section of cowboy.config %% %% 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 BaseDispatch=[ %% Nitrogen will handle everything that's not handled in the StaticDispatches {'_', StaticDispatches ++ [{'_', HandlerModule , HandlerOpts}]} ], 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), %% HandlerModule will end up calling HandlerModule:handle(Req,HandlerOpts) HandlerModule = simple_bridge_util:get_anchor_module(cowboy), HandlerOpts = [], {StaticDispatches,HandlerModule,HandlerOpts}. localized_dir_file(DocRoot,Path) -> NewPath = case hd(Path) of $/ -> DocRoot ++ Path; _ -> DocRoot ++ "/" ++ Path end, _NewPath2 = case lists:last(Path) of $/ -> {dir, NewPath}; _ -> {file, NewPath} end. %% Ensure the paths start with /, and if a path ends with /, then add "[...]" to it reformat_path(Path) -> Path2 = case hd(Path) of $/ -> Path; $\ -> Path; _ -> [$/|Path] end, Path3 = case lists:last(Path) of $/ -> Path2 ++ "[...]"; $\ -> Path2 ++ "[...]"; _ -> Path2 end, Path3.