Current section
Files
Jump to
Current section
Files
src/illustrious@server.erl
-module(illustrious@server).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([build_app/1, handle_request/5]).
-export_type([server_app_builder/4, server_result/1, server_app/4, api_request/0]).
-type server_app_builder(OTN, OTO, OTP, OTQ) :: {server_app_builder,
fun((list(binary()), OTO) -> gleam@option:option(lustre@internals@vdom:element(illustrious@state:illustrious_action(OTP)))),
OTO,
fun((OTO, OTP) -> {OTO,
lustre@effect:effect(illustrious@state:illustrious_action(OTP))}),
fun((gleam@dynamic:dynamic_()) -> {ok,
illustrious@state:illustrious_action(OTP)} |
{error, list(gleam@dynamic:decode_error())}),
fun((list(binary()), OTN) -> {ok, gleam@json:json()} | {error, OTQ}),
fun((list(binary()), OTN) -> {ok, gleam@json:json()} | {error, OTQ}),
fun((OTQ) -> binary())}.
-type server_result(OTR) :: {view,
lustre@internals@vdom:element(illustrious@state:illustrious_action(OTR))} |
{data, gleam@json:json()} |
{server_error, binary()} |
no_result.
-opaque server_app(OTS, OTT, OTU, OTV) :: {server_app,
fun((list(binary()), OTT) -> gleam@option:option(lustre@internals@vdom:element(illustrious@state:illustrious_action(OTU)))),
OTT,
fun((illustrious@state:illustrious_model(OTT), illustrious@state:illustrious_action(OTU)) -> {illustrious@state:illustrious_model(OTT),
lustre@effect:effect(illustrious@state:illustrious_action(OTU))}),
fun((gleam@dynamic:dynamic_()) -> {ok,
illustrious@state:illustrious_action(OTU)} |
{error, list(gleam@dynamic:decode_error())}),
fun((list(binary()), OTS) -> {ok, gleam@json:json()} | {error, OTV}),
fun((list(binary()), OTS) -> {ok, gleam@json:json()} | {error, OTV}),
fun((OTV) -> binary())}.
-type api_request() :: {api_request, binary()}.
-spec build_app(server_app_builder(OUE, OUF, OUG, OUH)) -> server_app(OUE, OUF, OUG, OUH).
build_app(Builder) ->
Updater = illustrious@internal@state_priv:wrap_updater(
erlang:element(4, Builder),
erlang:element(5, Builder)
),
{server_app,
erlang:element(2, Builder),
erlang:element(3, Builder),
Updater,
erlang:element(5, Builder),
erlang:element(6, Builder),
erlang:element(7, Builder),
erlang:element(8, Builder)}.
-spec api_request_decoder(binary()) -> {ok, api_request()} |
{error, gleam@json:decode_error()}.
api_request_decoder(Json) ->
gleam@json:decode(
Json,
gleam@dynamic:decode1(
fun(Field@0) -> {api_request, Field@0} end,
gleam@dynamic:field(<<"path"/utf8>>, fun gleam@dynamic:string/1)
)
).
-spec serialize_json_decode_error(gleam@json:decode_error()) -> binary().
serialize_json_decode_error(_) ->
<<"Failed to deserialize request"/utf8>>.
-spec wrap_element(
lustre@internals@vdom:element(illustrious@state:illustrious_action(OVC)),
binary()
) -> lustre@internals@vdom:element(illustrious@state:illustrious_action(OVC)).
wrap_element(Children, Baked_data) ->
lustre@element@html:html(
[],
[lustre@element@html:head(
[],
[lustre@element@html:title([], <<"Illustrious"/utf8>>),
lustre@element@html:link(
[lustre@attribute:rel(<<"stylesheet"/utf8>>),
lustre@attribute:type_(<<"text/css"/utf8>>),
lustre@attribute:href(<<"/static/client.css"/utf8>>)]
)]
),
lustre@element@html:body(
[],
[lustre@element@html:'div'(
[lustre@attribute:id(<<"app"/utf8>>)],
[Children]
),
lustre@element@html:script(
[lustre@attribute:id(<<"illustrious_baked_data"/utf8>>),
lustre@attribute:type_(<<"application/json"/utf8>>)],
Baked_data
),
lustre@element@html:script(
[lustre@attribute:src(<<"/static/client.mjs"/utf8>>),
lustre@attribute:type_(<<"module"/utf8>>)],
<<""/utf8>>
)]
)]
).
-spec handle_request(
server_app(OUN, any(), OUP, any()),
gleam@http:method(),
list(binary()),
binary(),
OUN
) -> server_result(OUP).
handle_request(App, Method, Path, Body, Context) ->
case {Method, Path} of
{post, [<<"illustrious_api"/utf8>>]} ->
case api_request_decoder(Body) of
{error, Decode_error} ->
{server_error, serialize_json_decode_error(Decode_error)};
{ok, Req} ->
Path@1 = illustrious@internal@router:parse_path(
erlang:element(2, Req)
),
case (erlang:element(7, App))(Path@1, Context) of
{error, Err} ->
{server_error, (erlang:element(8, App))(Err)};
{ok, Json} ->
{data, Json}
end
end;
{get, Path@2} ->
Init_result = (erlang:element(6, App))(Path@2, Context),
case Init_result of
{error, Error} ->
{server_error, (erlang:element(8, App))(Error)};
{ok, Json@1} ->
gleam@io:print(<<"initializer"/utf8>>),
Json_str = gleam@io:debug(gleam@json:to_string(Json@1)),
Model@1 = case gleam@json:decode(
Json_str,
gleam@dynamic:list(erlang:element(5, App))
) of
{ok, Actions} ->
gleam@list:fold(
Actions,
{illustrious_model,
Path@2,
erlang:element(3, App)},
fun(Model, Action) ->
erlang:element(
1,
(erlang:element(4, App))(Model, Action)
)
end
);
_ ->
_assert_subject = gleam@json:decode(
Json_str,
erlang:element(5, App)
),
{ok, Action@1} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail,
module => <<"illustrious/server"/utf8>>,
function => <<"handle_request"/utf8>>,
line => 151})
end,
erlang:element(
1,
(erlang:element(4, App))(
{illustrious_model,
Path@2,
erlang:element(3, App)},
Action@1
)
)
end,
case (erlang:element(2, App))(
erlang:element(2, Model@1),
erlang:element(3, Model@1)
) of
{some, Element} ->
{view, wrap_element(Element, Json_str)};
none ->
no_result
end
end;
{_, _} ->
no_result
end.