-module(tale@server). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/tale/server.gleam"). -export([serve/1, main/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -file("src/tale/server.gleam", 62). ?DOC(" Detects the public root\n"). -spec detect_public_root() -> binary(). detect_public_root() -> case tale@site:resolved_public_root() of {ok, Path} -> Path; {error, Error} -> erlang:error(#{gleam_error => panic, message => Error, file => <>, module => <<"tale/server"/utf8>>, function => <<"detect_public_root"/utf8>>, line => 65}) end. -file("src/tale/server.gleam", 114). ?DOC(" Page not found response\n"). -spec not_found() -> gleam@http@response:response(ewe:response_body()). not_found() -> _pipe = gleam@http@response:new(404), _pipe@1 = gleam@http@response:set_header( _pipe, <<"content-type"/utf8>>, <<"text/plain; charset=utf-8"/utf8>> ), gleam@http@response:set_body(_pipe@1, {text_data, <<"Not found"/utf8>>}). -file("src/tale/server.gleam", 121). ?DOC(" Content type development server supports\n"). -spec content_type(binary()) -> binary(). content_type(Path) -> case begin _pipe = gleam@string:split(Path, <<"."/utf8>>), _pipe@1 = lists:reverse(_pipe), gleam@list:first(_pipe@1) end of {ok, <<"html"/utf8>>} -> <<"text/html; charset=utf-8"/utf8>>; {ok, <<"css"/utf8>>} -> <<"text/css; charset=utf-8"/utf8>>; {ok, <<"js"/utf8>>} -> <<"application/javascript; charset=utf-8"/utf8>>; {ok, <<"json"/utf8>>} -> <<"application/json; charset=utf-8"/utf8>>; {ok, <<"svg"/utf8>>} -> <<"image/svg+xml"/utf8>>; {ok, <<"png"/utf8>>} -> <<"image/png"/utf8>>; {ok, <<"jpg"/utf8>>} -> <<"image/jpeg"/utf8>>; {ok, <<"jpeg"/utf8>>} -> <<"image/jpeg"/utf8>>; {ok, <<"ico"/utf8>>} -> <<"image/vnd.microsoft.icon"/utf8>>; _ -> <<"application/octet-stream"/utf8>> end. -file("src/tale/server.gleam", 107). ?DOC(" Succesfull Response\n"). -spec success_response(binary(), ewe:response_body()) -> gleam@http@response:response(ewe:response_body()). success_response(Path, Body) -> _pipe = gleam@http@response:new(200), _pipe@1 = gleam@http@response:set_header( _pipe, <<"content-type"/utf8>>, content_type(Path) ), gleam@http@response:set_body(_pipe@1, Body). -file("src/tale/server.gleam", 93). -spec serve_candidates(binary(), list(binary())) -> gleam@http@response:response(ewe:response_body()). serve_candidates(Root, Paths) -> case Paths of [] -> not_found(); [Path | Rest] -> Absolute = <<<>/binary, Path/binary>>, case ewe:file(Absolute, none, none) of {ok, Body} -> success_response(Path, Body); {error, _} -> serve_candidates(Root, Rest) end end. -file("src/tale/server.gleam", 139). -spec has_extension(binary()) -> boolean(). has_extension(Path) -> gleam_stdlib:contains_string(Path, <<"."/utf8>>). -file("src/tale/server.gleam", 74). -spec candidate_paths(list(binary())) -> list(binary()). candidate_paths(Segments) -> Clean = begin _pipe = Segments, _pipe@1 = gleam@list:filter( _pipe, fun(Segment) -> (Segment /= <<"."/utf8>>) andalso (Segment /= <<""/utf8>>) end ), gleam@list:filter( _pipe@1, fun(Segment@1) -> Segment@1 /= <<".."/utf8>> end ) end, case Clean of [] -> [<<"index.html"/utf8>>]; [<<""/utf8>> | Rest] -> candidate_paths(Rest); Segments@1 -> Joined = gleam@string:join(Segments@1, <<"/"/utf8>>), case has_extension(Joined) of true -> [Joined]; false -> [<>, <>] end end. -file("src/tale/server.gleam", 69). -spec static_handler( gleam@http@request:request(ewe@internal@http1:connection()), binary() ) -> gleam@http@response:response(ewe:response_body()). static_handler(Req, Root) -> Candidates = candidate_paths(gleam@http@request:path_segments(Req)), serve_candidates(Root, Candidates). -file("src/tale/server.gleam", 143). -spec rebuild_site() -> nil. rebuild_site() -> case tale@site:build_site() of {ok, Messages} -> gleam@list:each( Messages, fun(Message) -> logging:log(info, Message) end ); {error, Problem} -> logging:log(error, <<"Build failed: "/utf8, Problem/binary>>) end. -file("src/tale/server.gleam", 183). -spec dedup(list(binary())) -> list(binary()). dedup(Paths) -> gleam@list:fold( Paths, [], fun(Acc, Path) -> case gleam@list:contains(Acc, Path) of true -> Acc; false -> [Path | Acc] end end ). -file("src/tale/server.gleam", 192). -spec absolute_path(binary(), binary()) -> binary(). absolute_path(Base, Path) -> Joined = case filepath:is_absolute(Path) of true -> Path; false -> filepath:join(Base, Path) end, case filepath:expand(Joined) of {ok, Expanded} -> Expanded; {error, _} -> Joined end. -file("src/tale/server.gleam", 152). ?DOC(" Paths in the directory that watcher monitor for changes\n"). -spec paths_to_watch() -> list(binary()). paths_to_watch() -> Cwd = begin _pipe = simplifile:current_directory(), gleam@result:unwrap(_pipe, <<"."/utf8>>) end, case tale@config:load() of {ok, Site_config} -> Site_paths = tale@config:site_paths(Site_config), _pipe@1 = dedup( [<<"config.toml"/utf8>>, erlang:element(8, Site_config), erlang:element(3, Site_paths), erlang:element(4, Site_paths), erlang:element(5, Site_paths), erlang:element(6, Site_paths)] ), gleam@list:map(_pipe@1, fun(Path) -> absolute_path(Cwd, Path) end); {error, Problem} -> logging:log( warning, <<"Watcher fallback paths: "/utf8, Problem/binary>> ), [absolute_path(Cwd, <<"config.toml"/utf8>>), absolute_path(Cwd, <<"content"/utf8>>), absolute_path(Cwd, <<"layouts"/utf8>>), absolute_path(Cwd, <<"assets"/utf8>>), absolute_path(Cwd, <<"static"/utf8>>)] end. -file("src/tale/server.gleam", 26). -spec serve(integer()) -> nil. serve(Port) -> logging_ffi:configure(), logging:set_level(info), rebuild_site(), Root = detect_public_root(), logging:log( info, <<<<<<"Serving "/utf8, Root/binary>>/binary, " on http://localhost:"/utf8>>/binary, (erlang:integer_to_binary(Port))/binary>> ), _ = tale@watch:start({watch_config, paths_to_watch(), fun rebuild_site/0}), Handler = fun(Req) -> static_handler(Req, Root) end, case begin _pipe = ewe:new(Handler), _pipe@1 = ewe:bind_all(_pipe), _pipe@2 = ewe:listening(_pipe@1, Port), ewe:start(_pipe@2) end of {ok, _} -> gleam_erlang_ffi:sleep_forever(); {error, Error} -> logging:log( error, <<"Failed to start server: "/utf8, (gleam@string:inspect(Error))/binary>> ) end. -file("src/tale/server.gleam", 22). -spec main() -> nil. main() -> serve(8000).