Current section
Files
Jump to
Current section
Files
src/shimmer@ws@event_loop.erl
-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
).