-module(sprocket@socket). -compile([no_auto_import, nowarn_unused_vars]). -export([new/1, reset_for_render/1, fetch_or_init_hook/2, update_hook/3, push_event_handler/2, get_event_handler/2]). -export_type([event_handler/0, updater/1, component_wip/0, socket/0]). -type event_handler() :: {event_handler, sprocket@internal@utils@unique:unique(), sprocket@internal@identifiable_callback:callback_fn()}. -type updater(JYK) :: {updater, fun((JYK) -> {ok, nil} | {error, nil})}. -type component_wip() :: {component_wip, sprocket@internal@utils@ordered_map:ordered_map(integer(), sprocket@hooks:hook()), integer(), boolean()}. -type socket() :: {socket, component_wip(), list(event_handler()), gleam@option:option(gleam@erlang@process:subject(glisten@handler:handler_message())), fun(() -> nil)}. -spec new( gleam@option:option(gleam@erlang@process:subject(glisten@handler:handler_message())) ) -> socket(). new(Ws) -> {socket, {component_wip, sprocket@internal@utils@ordered_map:new(), 0, true}, [], Ws, fun() -> nil end}. -spec reset_for_render(socket()) -> socket(). reset_for_render(Socket) -> erlang:setelement(3, Socket, []). -spec fetch_or_init_hook(socket(), fun(() -> sprocket@hooks:hook())) -> {socket(), sprocket@hooks:hook(), integer()}. fetch_or_init_hook(Socket, Init) -> Index = erlang:element(3, erlang:element(2, Socket)), Hooks = erlang:element(2, erlang:element(2, Socket)), case sprocket@internal@utils@ordered_map:get(Hooks, Index) of {ok, Hook} -> {erlang:setelement( 2, Socket, erlang:setelement(3, erlang:element(2, Socket), Index + 1) ), Hook, Index}; {error, nil} -> case erlang:element(4, erlang:element(2, Socket)) of true -> nil; false -> sprocket@internal@logger:error( <<<<" Hook not found for index: "/utf8, (gleam@int:to_string(Index))/binary>>/binary, ". This indicates a hook was dynamically created since first render which is not allowed. "/utf8>> ), erlang:error(#{gleam_error => panic, message => <<"panic expression evaluated"/utf8>>, module => <<"sprocket/socket"/utf8>>, function => <<"fetch_or_init_hook"/utf8>>, line => 82}) end, Hook@1 = Init(), {erlang:setelement( 2, Socket, {component_wip, sprocket@internal@utils@ordered_map:insert( erlang:element(2, erlang:element(2, Socket)), Index, Hook@1 ), Index + 1, erlang:element(4, erlang:element(2, Socket))} ), Hook@1, Index} end. -spec update_hook(socket(), sprocket@hooks:hook(), integer()) -> socket(). update_hook(Socket, Hook, Index) -> erlang:setelement( 2, Socket, erlang:setelement( 2, erlang:element(2, Socket), sprocket@internal@utils@ordered_map:update( erlang:element(2, erlang:element(2, Socket)), Index, Hook ) ) ). -spec push_event_handler( socket(), sprocket@internal@identifiable_callback:identifiable_callback() ) -> {socket(), sprocket@internal@utils@unique:unique()}. push_event_handler(Socket, Identifiable_cb) -> {identifiable_callback, Id, Cb} = Identifiable_cb, {erlang:setelement( 3, Socket, [{event_handler, Id, Cb} | erlang:element(3, Socket)] ), Id}. -spec get_event_handler(socket(), sprocket@internal@utils@unique:unique()) -> {socket(), {ok, event_handler()} | {error, nil}}. get_event_handler(Socket, Id) -> Handler = gleam@list:find( erlang:element(3, Socket), fun(H) -> {event_handler, I, _} = H, I =:= Id end ), {Socket, Handler}.