-module(shimmer@ws@event_loop). -compile(no_auto_import). -export([actor_setup/4, actor_loop/2]). -export_type([message/0, websocket_meta/0, gateway_session/0, sharding_meta/0, actor_state/0]). -type message() :: {websocket_frame, shimmer@internal@network@websocket:frame()} | {update_presence, shimmer@types@presence:presence()} | beat | halt. -type websocket_meta() :: {websocket_meta, binary(), integer(), shimmer@handlers:handlers(message())}. -type gateway_session() :: {gateway_session, binary(), binary()}. -type sharding_meta() :: {sharding_meta, gleam@erlang@process:subject(message()), integer(), integer()}. -type actor_state() :: {actor_state, integer(), integer(), shimmer@internal@network@websocket:connection(), websocket_meta(), sharding_meta(), gleam@erlang@process:selector(message()), gleam@erlang@process:subject(message()), gleam@option:option(gateway_session())}. -spec actor_setup( shimmer@client:client(message()), binary(), shimmer@handlers:handlers(message()), gleam@option:option(sharding_meta()) ) -> fun(() -> gleam@otp@actor:init_result(actor_state(), message())). actor_setup(Client, Gateway_url, Handlers, Sharding) -> fun() -> Setup = fun(Inner_client) -> Url = uri_ffi:parse(Gateway_url), case begin _pipe = shimmer@internal@network@websocket:connect( erlang:element(2, Url), <<"/?v=10&encoding=etf"/utf8>>, 443, [] ), gleam@result:replace_error( _pipe, {failed, <<"Failed to open websocket"/utf8>>} ) end of {error, _try} -> {error, _try}; {ok, Conn} -> To_self_subject = gleam@erlang@process:new_subject(), Selector = begin _pipe@1 = gleam_erlang_ffi:new_selector(), _pipe@2 = gleam@erlang@process:selecting( _pipe@1, erlang:element(4, Inner_client), fun(A) -> A end ), _pipe@3 = gleam@erlang@process:selecting( _pipe@2, To_self_subject, fun(A@1) -> A@1 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(3, Inner_client), Handlers}, begin _pipe@4 = Sharding, gleam@option:unwrap( _pipe@4, {sharding_meta, To_self_subject, 1, 1} ) end, Selector, To_self_subject, none}, Selector}} end end, case Setup(Client) of {ok, Ready} -> Ready; {error, Failed} -> Failed end end. -spec internal_error_handler(actor_state(), {ok, any()} | {error, any()}) -> gleam@otp@actor:next(actor_state()). internal_error_handler(State, _) -> {continue, State}. -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, {client, erlang:element(2, erlang:element(5, State)), erlang:element(3, erlang:element(5, State)), erlang:element(8, State)} ), {continue, erlang:setelement( 9, update_state(Seq, State), {some, {gateway_session, erlang:element(3, Packet), erlang:element(4, Packet)}} )}; {error, E} -> internal_error_handler( update_state(Seq, State), {error, E} ) end; {ok, {0, Seq@1, {some, <<"MESSAGE_CREATE"/utf8>>}, {some, Data@1}}} -> case shimmer@ws@packets@message_create:from_map(Data@1) of {ok, Packet@1} -> (erlang:element( 3, erlang:element(4, erlang:element(5, State)) ))( Packet@1, {client, erlang:element(2, erlang:element(5, State)), erlang:element(3, erlang:element(5, State)), erlang:element(8, State)} ), {continue, update_state(Seq@1, State)}; {error, E@1} -> internal_error_handler( update_state(Seq@1, State), {error, E@1} ) end; {ok, {10, Seq@2, _@1, {some, Data@2}}} -> case shimmer@ws@packets@hello:from_map(Data@2) of {ok, Packet@2} -> New_state = erlang:setelement( 2, update_state(Seq@2, State), erlang:element(2, Packet@2) ), 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) ), erlang:element( 3, erlang:element(6, State) ), erlang:element( 4, erlang:element(6, State) )}, shimmer@ws@packets@identify:to_etf(_pipe@3) end ), gleam@erlang@process:send_after( erlang:element(8, New_state), erlang:element(2, New_state), beat ), {continue, New_state}; {error, E@2} -> internal_error_handler( update_state(Seq@2, State), {error, E@2} ) end; {ok, {11, Seq@3, _@2, _@3}} -> (erlang:element( 4, erlang:element(4, erlang:element(5, State)) ))( {client, erlang:element(2, erlang:element(5, State)), erlang:element(3, erlang:element(5, State)), erlang:element(8, State)} ), {continue, update_state(Seq@3, State)}; {ok, {_@4, Seq@4, _@5, _@6}} -> {continue, update_state(Seq@4, State)}; {error, E@3} -> internal_error_handler(State, {error, E@3}); _@7 -> {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 ), (erlang:element(5, erlang:element(4, erlang:element(5, State))))( Code, {client, erlang:element(2, erlang:element(5, State)), erlang:element(3, erlang:element(5, State)), erlang:element(8, State)} ), {stop, {abnormal, Message}}; {update_presence, New_presence} -> Payload = begin _pipe@5 = gleam@map:new(), _pipe@6 = gleam@map:insert( _pipe@5, <<"op"/utf8>>, gleam@dynamic:from(3) ), _pipe@9 = gleam@map:insert( _pipe@6, <<"d"/utf8>>, begin _pipe@7 = New_presence, _pipe@8 = shimmer@types@presence:to_map(_pipe@7), gleam@dynamic:from(_pipe@8) end ), erlang:term_to_binary(_pipe@9) end, shimmer@internal@network@websocket:send( erlang:element(4, State), Payload ), {continue, State}; beat -> Payload@1 = begin _pipe@14 = case erlang:element(3, State) of -1 -> _pipe@10 = gleam@map:new(), _pipe@11 = gleam@map:insert( _pipe@10, <<"op"/utf8>>, gleam@dynamic:from(1) ), gleam@map:insert( _pipe@11, <<"d"/utf8>>, gleam@dynamic:from(nil) ); Seq@5 -> _pipe@12 = gleam@map:new(), _pipe@13 = gleam@map:insert( _pipe@12, <<"op"/utf8>>, gleam@dynamic:from(1) ), gleam@map:insert( _pipe@13, <<"d"/utf8>>, gleam@dynamic:from(gleam@int:to_string(Seq@5)) ) end, erlang:term_to_binary(_pipe@14) end, shimmer@internal@network@websocket:send( erlang:element(4, State), Payload@1 ), gleam@erlang@process:send_after( erlang:element(8, State), erlang:element(2, State), beat ), {continue, State}; _@8 -> {stop, {abnormal, <<"event loop's 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 ).