-module(shimmer@ws@event_loop). -compile(no_auto_import). -export([actor_setup/1, actor_loop/2]). -export_type([message/0, websocket_meta/0, actor_state/0]). -type message() :: {websocket_frame, shimmer@internal@network@websocket:frame()} | beat | halt. -type websocket_meta() :: {websocket_meta, binary(), integer(), shimmer@handlers:handlers()}. -type actor_state() :: {actor_state, integer(), integer(), shimmer@internal@network@websocket:connection(), websocket_meta(), gleam@erlang@process:selector(message()), gleam@erlang@process:subject(message())}. -spec actor_setup(shimmer@client:client()) -> fun(() -> gleam@otp@actor:init_result(actor_state(), message())). actor_setup(Client) -> fun() -> Setup = fun(Inner_client) -> case begin _pipe = shimmer@http@endpoints:bot_gateway( erlang:element(2, Inner_client) ), gleam@result:replace_error( _pipe, {failed, <<"Couldn't get bot gateway information"/utf8>>} ) end of {error, _try} -> {error, _try}; {ok, Gateway_settings} -> Url = uri_ffi:parse(erlang:element(2, Gateway_settings)), case begin _pipe@1 = shimmer@internal@network@websocket:connect( erlang:element(2, Url), <<"/?v=10&encoding=etf"/utf8>>, 443, [] ), gleam@result:replace_error( _pipe@1, {failed, <<"Failed to open websocket"/utf8>>} ) end of {error, _try@1} -> {error, _try@1}; {ok, Conn} -> To_self_subject = gleam@erlang@process:new_subject(), Selector = begin _pipe@2 = gleam_erlang_ffi:new_selector(), _pipe@3 = gleam@erlang@process:selecting( _pipe@2, To_self_subject, fun(A) -> A end ), gleam@erlang@process:selecting_record4( _pipe@3, erlang:binary_to_atom(<<"gun_ws"/utf8>>), fun(_, _, Dyn_frame) -> Map = fun(Frame) -> {websocket_frame, Frame} end, Map( gleam@dynamic:unsafe_coerce( Dyn_frame ) ) end ) end, {ok, {ready, {actor_state, -1, -1, Conn, {websocket_meta, erlang:element(2, Inner_client), erlang:element(4, Inner_client), erlang:element(3, Inner_client)}, Selector, To_self_subject}, Selector}} end end end, case Setup(Client) of {ok, Ready} -> Ready; {error, Failed} -> Failed end end. -spec actor_loop(message(), actor_state()) -> gleam@otp@actor:next(actor_state()). actor_loop(Msg, State) -> case Msg of {websocket_frame, {binary, Etf_bitstring}} -> Dynamic_payload = shimmer_ws:parse_etf(Etf_bitstring), case shimmer@ws@packet:from_dynamic(Dynamic_payload) of {ok, {0, Seq, {some, <<"READY"/utf8>>}, {some, Data}}} -> case shimmer@ws@packets@ready:from_map(Data) of {ok, Packet} -> (erlang:element( 2, erlang:element(4, erlang:element(5, State)) ))(Packet), {continue, update_state(Seq, State)}; _@1 -> {continue, update_state(Seq, State)} end; {ok, {10, Seq@1, _@2, {some, Data@1}}} -> case shimmer@ws@packets@hello:from_map(Data@1) of {ok, Packet@1} -> New_state = erlang:setelement( 2, update_state(Seq@1, State), erlang:element(2, Packet@1) ), shimmer@internal@network@websocket:send( erlang:element(4, New_state), begin _pipe = gleam@map:new(), _pipe@1 = gleam@map:insert( _pipe, <<"op"/utf8>>, gleam@dynamic:from(1) ), _pipe@2 = gleam@map:insert( _pipe@1, <<"d"/utf8>>, gleam@dynamic:from(nil) ), erlang:term_to_binary(_pipe@2) end ), shimmer@internal@network@websocket:send( erlang:element(4, New_state), begin _pipe@3 = {identify_packet_data, erlang:element( 2, erlang:element(5, State) ), erlang:element( 3, erlang:element(5, State) )}, shimmer@ws@packets@identify:to_etf(_pipe@3) end ), gleam@erlang@process:send_after( erlang:element(7, New_state), erlang:element(2, New_state), beat ), {continue, New_state}; _@3 -> {continue, update_state(Seq@1, State)} end; {ok, {11, Seq@2, _@4, _@5}} -> (erlang:element( 4, erlang:element(4, erlang:element(5, State)) ))(), {continue, update_state(Seq@2, State)}; _@6 -> {continue, State} end; {websocket_frame, {close, Code, Message}} -> gleam@io:println( begin _pipe@4 = [<<"Websocket Closed with code: "/utf8>>, gleam@int:to_string(Code), <<" and message \""/utf8>>, Message, <<"\""/utf8>>], gleam@string:join(_pipe@4, <<""/utf8>>) end ), {stop, {abnormal, Message}}; beat -> Payload = begin _pipe@9 = case erlang:element(3, State) of -1 -> _pipe@5 = gleam@map:new(), _pipe@6 = gleam@map:insert( _pipe@5, <<"op"/utf8>>, gleam@dynamic:from(1) ), gleam@map:insert( _pipe@6, <<"d"/utf8>>, gleam@dynamic:from(nil) ); Seq@3 -> _pipe@7 = gleam@map:new(), _pipe@8 = gleam@map:insert( _pipe@7, <<"op"/utf8>>, gleam@dynamic:from(1) ), gleam@map:insert( _pipe@8, <<"d"/utf8>>, gleam@dynamic:from(gleam@int:to_string(Seq@3)) ) end, erlang:term_to_binary(_pipe@9) end, shimmer@internal@network@websocket:send( erlang:element(4, State), Payload ), gleam@erlang@process:send_after( erlang:element(7, State), erlang:element(2, State), beat ), {continue, State}; _@7 -> {stop, {abnormal, <<"Heartbeat actor recieved unknown message"/utf8>>}} end. -spec update_state(gleam@option:option(integer()), actor_state()) -> actor_state(). update_state(Seq, Old_state) -> erlang:setelement( 3, Old_state, begin _pipe = Seq, gleam@option:unwrap(_pipe, erlang:element(3, Old_state)) end ).