Current section

Files

Jump to
lustre src lustre@runtime@server@runtime.erl
Raw

src/lustre@runtime@server@runtime.erl

-module(lustre@runtime@server@runtime).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([start/4]).
-export_type([state/2, config/1, message/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-type state(SNN, SNO) :: {state,
gleam@erlang@process:subject(message(SNO)),
gleam@erlang@process:selector(message(SNO)),
gleam@erlang@process:selector(message(SNO)),
SNN,
fun((SNN, SNO) -> {SNN, lustre@effect:effect(SNO)}),
fun((SNN) -> lustre@vdom@vnode:element(SNO)),
config(SNO),
lustre@vdom@vnode:element(SNO),
lustre@vdom@events:events(SNO),
gleam@dict:dict(gleam@erlang@process:subject(lustre@runtime@transport:client_message(SNO)), gleam@erlang@process:process_monitor()),
gleam@set:set(fun((lustre@runtime@transport:client_message(SNO)) -> nil))}.
-type config(SNP) :: {config,
boolean(),
boolean(),
gleam@dict:dict(binary(), fun((binary()) -> {ok, SNP} | {error, nil})),
gleam@dict:dict(binary(), gleam@dynamic@decode:decoder(SNP))}.
-type message(SNQ) :: {client_dispatched_message,
lustre@runtime@transport:server_message()} |
{client_registered_subject,
gleam@erlang@process:subject(lustre@runtime@transport:client_message(SNQ))} |
{client_deregistered_subject,
gleam@erlang@process:subject(lustre@runtime@transport:client_message(SNQ))} |
{client_registered_callback,
fun((lustre@runtime@transport:client_message(SNQ)) -> nil)} |
{client_deregistered_callback,
fun((lustre@runtime@transport:client_message(SNQ)) -> nil)} |
{effect_added_selector, gleam@erlang@process:selector(message(SNQ))} |
{effect_dispatched_message, SNQ} |
{effect_emit_event, binary(), gleam@json:json()} |
{self_dispatched_messages, list(SNQ), lustre@effect:effect(SNQ)} |
system_requested_shutdown.
-file("src/lustre/runtime/server/runtime.gleam", 315).
?DOC(false).
-spec handle_attribute_change(
gleam@dict:dict(binary(), fun((binary()) -> {ok, SOU} | {error, nil})),
binary(),
binary()
) -> {ok, SOU} | {error, nil}.
handle_attribute_change(Attributes, Name, Value) ->
case gleam_stdlib:map_get(Attributes, Name) of
{error, _} ->
{error, nil};
{ok, Handler} ->
Handler(Value)
end.
-file("src/lustre/runtime/server/runtime.gleam", 326).
?DOC(false).
-spec handle_property_change(
gleam@dict:dict(binary(), gleam@dynamic@decode:decoder(SPB)),
binary(),
gleam@dynamic:dynamic_()
) -> {ok, SPB} | {error, nil}.
handle_property_change(Properties, Name, Value) ->
case gleam_stdlib:map_get(Properties, Name) of
{error, _} ->
{error, nil};
{ok, Decoder} ->
_pipe = gleam@dynamic@decode:run(Value, Decoder),
gleam@result:replace_error(_pipe, nil)
end.
-file("src/lustre/runtime/server/runtime.gleam", 338).
?DOC(false).
-spec handle_effect(
gleam@erlang@process:subject(message(SPH)),
lustre@effect:effect(SPH)
) -> nil.
handle_effect(Self, Effect) ->
Send = fun(_capture) -> gleam@erlang@process:send(Self, _capture) end,
Dispatch = fun(Message) -> Send({effect_dispatched_message, Message}) end,
Emit = fun(Name, Data) -> Send({effect_emit_event, Name, Data}) end,
Select = fun(Selector) -> _pipe = Selector,
_pipe@1 = gleam_erlang_ffi:map_selector(
_pipe,
fun(Field@0) -> {effect_dispatched_message, Field@0} end
),
_pipe@2 = {effect_added_selector, _pipe@1},
Send(_pipe@2) end,
Internals = fun() -> gleam_stdlib:identity(nil) end,
lustre@effect:perform(Effect, Dispatch, Emit, Select, Internals).
-file("src/lustre/runtime/server/runtime.gleam", 266).
?DOC(false).
-spec handle_client_message(
state(SOO, SOP),
lustre@runtime@transport:server_message()
) -> state(SOO, SOP).
handle_client_message(State, Message) ->
case Message of
{batch, _, Messages} ->
gleam@list:fold(Messages, State, fun handle_client_message/2);
{attribute_changed, _, Name, Value} ->
case handle_attribute_change(
erlang:element(4, erlang:element(8, State)),
Name,
Value
) of
{error, _} ->
State;
{ok, Msg} ->
{Model, Effect} = (erlang:element(6, State))(
erlang:element(5, State),
Msg
),
Vdom = (erlang:element(7, State))(Model),
handle_effect(erlang:element(2, State), Effect),
_record = State,
{state,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
Model,
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
Vdom,
erlang:element(10, _record),
erlang:element(11, _record),
erlang:element(12, _record)}
end;
{property_changed, _, Name@1, Value@1} ->
case handle_property_change(
erlang:element(5, erlang:element(8, State)),
Name@1,
Value@1
) of
{error, _} ->
State;
{ok, Msg@1} ->
{Model@1, Effect@1} = (erlang:element(6, State))(
erlang:element(5, State),
Msg@1
),
Vdom@1 = (erlang:element(7, State))(Model@1),
handle_effect(erlang:element(2, State), Effect@1),
_record@1 = State,
{state,
erlang:element(2, _record@1),
erlang:element(3, _record@1),
erlang:element(4, _record@1),
Model@1,
erlang:element(6, _record@1),
erlang:element(7, _record@1),
erlang:element(8, _record@1),
Vdom@1,
erlang:element(10, _record@1),
erlang:element(11, _record@1),
erlang:element(12, _record@1)}
end;
{event_fired, _, Path, Name@2, Event} ->
case lustre@vdom@events:handle(
erlang:element(10, State),
Path,
Name@2,
Event
) of
{Events, {error, _}} ->
_record@2 = State,
{state,
erlang:element(2, _record@2),
erlang:element(3, _record@2),
erlang:element(4, _record@2),
erlang:element(5, _record@2),
erlang:element(6, _record@2),
erlang:element(7, _record@2),
erlang:element(8, _record@2),
erlang:element(9, _record@2),
Events,
erlang:element(11, _record@2),
erlang:element(12, _record@2)};
{Events@1, {ok, Message@1}} ->
{Model@2, Effect@2} = (erlang:element(6, State))(
erlang:element(5, State),
Message@1
),
Vdom@2 = (erlang:element(7, State))(Model@2),
handle_effect(erlang:element(2, State), Effect@2),
_record@3 = State,
{state,
erlang:element(2, _record@3),
erlang:element(3, _record@3),
erlang:element(4, _record@3),
Model@2,
erlang:element(6, _record@3),
erlang:element(7, _record@3),
erlang:element(8, _record@3),
Vdom@2,
Events@1,
erlang:element(11, _record@3),
erlang:element(12, _record@3)}
end
end.
-file("src/lustre/runtime/server/runtime.gleam", 356).
?DOC(false).
-spec broadcast(
gleam@dict:dict(gleam@erlang@process:subject(lustre@runtime@transport:client_message(SPL)), gleam@erlang@process:process_monitor()),
gleam@set:set(fun((lustre@runtime@transport:client_message(SPL)) -> nil)),
lustre@runtime@transport:client_message(SPL)
) -> nil.
broadcast(Clients, Callbacks, Message) ->
gleam@dict:each(
Clients,
fun(Client, _) -> gleam@erlang@process:send(Client, Message) end
),
gleam@set:each(Callbacks, fun(Callback) -> Callback(Message) end).
-file("src/lustre/runtime/server/runtime.gleam", 114).
?DOC(false).
-spec loop(message(SOE), state(SOG, SOE)) -> gleam@otp@actor:next(message(SOE), state(SOG, SOE)).
loop(Message, State) ->
case Message of
{client_dispatched_message, Message@1} ->
Next = handle_client_message(State, Message@1),
{diff, Patch, Events} = lustre@vdom@diff:diff(
erlang:element(10, State),
erlang:element(9, State),
erlang:element(9, Next)
),
broadcast(
erlang:element(11, State),
erlang:element(12, State),
lustre@runtime@transport:reconcile(Patch)
),
gleam@otp@actor:continue(
begin
_record = Next,
{state,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
erlang:element(6, _record),
erlang:element(7, _record),
erlang:element(8, _record),
erlang:element(9, _record),
Events,
erlang:element(11, _record),
erlang:element(12, _record)}
end
);
{client_registered_subject, Client} ->
case gleam@dict:has_key(erlang:element(11, State), Client) of
true ->
gleam@otp@actor:continue(State);
false ->
Monitor = gleam@erlang@process:monitor_process(
gleam@erlang@process:subject_owner(Client)
),
Subscribers = gleam@dict:insert(
erlang:element(11, State),
Client,
Monitor
),
Selector@1 = begin
gleam@dict:fold(
Subscribers,
erlang:element(4, State),
fun(Selector, Client@1, Monitor@1) ->
gleam@erlang@process:selecting_process_down(
Selector,
Monitor@1,
fun(_) ->
{client_deregistered_subject, Client@1}
end
)
end
)
end,
gleam@erlang@process:send(
Client,
lustre@runtime@transport:mount(
erlang:element(2, erlang:element(8, State)),
erlang:element(3, erlang:element(8, State)),
maps:keys(
erlang:element(4, erlang:element(8, State))
),
maps:keys(
erlang:element(5, erlang:element(8, State))
),
erlang:element(9, State)
)
),
{continue,
begin
_record@1 = State,
{state,
erlang:element(2, _record@1),
Selector@1,
erlang:element(4, _record@1),
erlang:element(5, _record@1),
erlang:element(6, _record@1),
erlang:element(7, _record@1),
erlang:element(8, _record@1),
erlang:element(9, _record@1),
erlang:element(10, _record@1),
Subscribers,
erlang:element(12, _record@1)}
end,
{some, Selector@1}}
end;
{client_deregistered_subject, Client@2} ->
case gleam_stdlib:map_get(erlang:element(11, State), Client@2) of
{error, _} ->
gleam@otp@actor:continue(State);
{ok, Monitor@2} ->
_ = gleam@erlang@process:demonitor_process(Monitor@2),
Subscribers@1 = gleam@dict:delete(
erlang:element(11, State),
Client@2
),
Selector@3 = begin
gleam@dict:fold(
Subscribers@1,
erlang:element(4, State),
fun(Selector@2, Client@3, Monitor@3) ->
Unsubscribe = fun(_) ->
{client_deregistered_subject, Client@3}
end,
gleam@erlang@process:selecting_process_down(
Selector@2,
Monitor@3,
Unsubscribe
)
end
)
end,
{continue,
begin
_record@2 = State,
{state,
erlang:element(2, _record@2),
Selector@3,
erlang:element(4, _record@2),
erlang:element(5, _record@2),
erlang:element(6, _record@2),
erlang:element(7, _record@2),
erlang:element(8, _record@2),
erlang:element(9, _record@2),
erlang:element(10, _record@2),
Subscribers@1,
erlang:element(12, _record@2)}
end,
{some, Selector@3}}
end;
{client_registered_callback, Callback} ->
case gleam@set:contains(erlang:element(12, State), Callback) of
true ->
gleam@otp@actor:continue(State);
false ->
Callbacks = gleam@set:insert(
erlang:element(12, State),
Callback
),
Callback(
lustre@runtime@transport:mount(
erlang:element(2, erlang:element(8, State)),
erlang:element(3, erlang:element(8, State)),
maps:keys(
erlang:element(4, erlang:element(8, State))
),
maps:keys(
erlang:element(5, erlang:element(8, State))
),
erlang:element(9, State)
)
),
gleam@otp@actor:continue(
begin
_record@3 = State,
{state,
erlang:element(2, _record@3),
erlang:element(3, _record@3),
erlang:element(4, _record@3),
erlang:element(5, _record@3),
erlang:element(6, _record@3),
erlang:element(7, _record@3),
erlang:element(8, _record@3),
erlang:element(9, _record@3),
erlang:element(10, _record@3),
erlang:element(11, _record@3),
Callbacks}
end
)
end;
{client_deregistered_callback, Callback@1} ->
case gleam@set:contains(erlang:element(12, State), Callback@1) of
false ->
gleam@otp@actor:continue(State);
true ->
Callbacks@1 = gleam@set:delete(
erlang:element(12, State),
Callback@1
),
gleam@otp@actor:continue(
begin
_record@4 = State,
{state,
erlang:element(2, _record@4),
erlang:element(3, _record@4),
erlang:element(4, _record@4),
erlang:element(5, _record@4),
erlang:element(6, _record@4),
erlang:element(7, _record@4),
erlang:element(8, _record@4),
erlang:element(9, _record@4),
erlang:element(10, _record@4),
erlang:element(11, _record@4),
Callbacks@1}
end
)
end;
{effect_added_selector, Selector@4} ->
Base_selector = gleam_erlang_ffi:merge_selector(
erlang:element(4, State),
Selector@4
),
Selector@5 = gleam_erlang_ffi:merge_selector(
erlang:element(3, State),
Selector@4
),
{continue,
begin
_record@5 = State,
{state,
erlang:element(2, _record@5),
Selector@5,
Base_selector,
erlang:element(5, _record@5),
erlang:element(6, _record@5),
erlang:element(7, _record@5),
erlang:element(8, _record@5),
erlang:element(9, _record@5),
erlang:element(10, _record@5),
erlang:element(11, _record@5),
erlang:element(12, _record@5)}
end,
{some, Selector@5}};
{effect_dispatched_message, Message@2} ->
{Model, Effect} = (erlang:element(6, State))(
erlang:element(5, State),
Message@2
),
Vdom = (erlang:element(7, State))(erlang:element(5, State)),
{diff, Patch@1, Events@1} = lustre@vdom@diff:diff(
erlang:element(10, State),
erlang:element(9, State),
Vdom
),
handle_effect(erlang:element(2, State), Effect),
broadcast(
erlang:element(11, State),
erlang:element(12, State),
lustre@runtime@transport:reconcile(Patch@1)
),
gleam@otp@actor:continue(
begin
_record@6 = State,
{state,
erlang:element(2, _record@6),
erlang:element(3, _record@6),
erlang:element(4, _record@6),
Model,
erlang:element(6, _record@6),
erlang:element(7, _record@6),
erlang:element(8, _record@6),
Vdom,
Events@1,
erlang:element(11, _record@6),
erlang:element(12, _record@6)}
end
);
{effect_emit_event, Name, Data} ->
broadcast(
erlang:element(11, State),
erlang:element(12, State),
lustre@runtime@transport:emit(Name, Data)
),
gleam@otp@actor:continue(State);
{self_dispatched_messages, [], Effect@1} ->
Vdom@1 = (erlang:element(7, State))(erlang:element(5, State)),
{diff, Patch@2, Events@2} = lustre@vdom@diff:diff(
erlang:element(10, State),
erlang:element(9, State),
Vdom@1
),
handle_effect(erlang:element(2, State), Effect@1),
broadcast(
erlang:element(11, State),
erlang:element(12, State),
lustre@runtime@transport:reconcile(Patch@2)
),
gleam@otp@actor:continue(
begin
_record@7 = State,
{state,
erlang:element(2, _record@7),
erlang:element(3, _record@7),
erlang:element(4, _record@7),
erlang:element(5, _record@7),
erlang:element(6, _record@7),
erlang:element(7, _record@7),
erlang:element(8, _record@7),
Vdom@1,
Events@2,
erlang:element(11, _record@7),
erlang:element(12, _record@7)}
end
);
{self_dispatched_messages, [Message@3 | Messages], Effect@2} ->
{Model@1, More_effects} = (erlang:element(6, State))(
erlang:element(5, State),
Message@3
),
Effect@3 = lustre@effect:batch([Effect@2, More_effects]),
State@1 = begin
_record@8 = State,
{state,
erlang:element(2, _record@8),
erlang:element(3, _record@8),
erlang:element(4, _record@8),
Model@1,
erlang:element(6, _record@8),
erlang:element(7, _record@8),
erlang:element(8, _record@8),
erlang:element(9, _record@8),
erlang:element(10, _record@8),
erlang:element(11, _record@8),
erlang:element(12, _record@8)}
end,
loop({self_dispatched_messages, Messages, Effect@3}, State@1);
system_requested_shutdown ->
gleam@dict:each(
erlang:element(11, State),
fun(_, Monitor@4) ->
gleam@erlang@process:demonitor_process(Monitor@4)
end
),
{stop, normal}
end.
-file("src/lustre/runtime/server/runtime.gleam", 55).
?DOC(false).
-spec start(
{SNU, lustre@effect:effect(SNV)},
fun((SNU, SNV) -> {SNU, lustre@effect:effect(SNV)}),
fun((SNU) -> lustre@vdom@vnode:element(SNV)),
config(SNV)
) -> {ok, gleam@erlang@process:subject(message(SNV))} |
{error, gleam@otp@actor:start_error()}.
start(Init, Update, View, Config) ->
gleam@otp@actor:start_spec(
begin
{spec,
fun() ->
Self = gleam@erlang@process:new_subject(),
Base_selector = begin
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:selecting(
_pipe,
Self,
fun gleam@function:identity/1
)
end,
Vdom = View(erlang:element(1, Init)),
Events = lustre@vdom@events:from_node(Vdom),
State = {state,
Self,
Base_selector,
Base_selector,
erlang:element(1, Init),
Update,
View,
Config,
Vdom,
Events,
maps:new(),
gleam@set:new()},
handle_effect(Self, erlang:element(2, Init)),
{ready, State, Base_selector}
end,
1000,
fun loop/2}
end
).