Current section

Files

Jump to
grammy src grammy.erl
Raw

src/grammy.erl

-module(grammy).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([get_supervisor/1, new/2, port/2, ip_address_to_string/1, udp_send/4, send_to/4, start/1]).
-export_type([udp_server/0, internal_message/1, state/2, builder/2, message/1, connection/0, active_type/0, socket_option/0, socket/0]).
-opaque udp_server() :: {udp_server,
gleam@erlang@process:subject(gleam@otp@supervisor:message())}.
-type internal_message(PMR) :: {internal_user, PMR} |
{udp_packet,
{integer(), integer(), integer(), integer()},
integer(),
bitstring()} |
unknown.
-opaque state(PMS, PMT) :: {state,
socket(),
PMS,
gleam@dict:dict({{integer(), integer(), integer(), integer()},
integer()}, gleam@erlang@process:subject(message(PMT)))}.
-type builder(PMU, PMV) :: {builder,
fun(() -> {PMU, gleam@option:option(gleam@erlang@process:selector(PMV))}),
integer(),
fun((message(PMV), connection(), PMU) -> gleam@otp@actor:next(PMV, PMU))}.
-type message(PMW) :: {user, PMW} |
{packet,
{integer(), integer(), integer(), integer()},
integer(),
bitstring()}.
-opaque connection() :: {connection, socket()}.
-type active_type() :: once.
-type socket_option() :: binary |
{active, active_type()} |
{sndbuf, integer()} |
{recbuf, integer()}.
-type socket() :: any().
-file("/home/alex/gleams/grammy/src/grammy.gleam", 19).
-spec get_supervisor(udp_server()) -> gleam@erlang@process:subject(gleam@otp@supervisor:message()).
get_supervisor(Server) ->
erlang:element(2, Server).
-file("/home/alex/gleams/grammy/src/grammy.gleam", 144).
-spec udp_message_selector() -> gleam@erlang@process:selector(internal_message(any())).
udp_message_selector() ->
_pipe = gleam_erlang_ffi:new_selector(),
gleam@erlang@process:selecting_record5(
_pipe,
erlang:binary_to_atom(<<"udp"/utf8>>),
fun(_, Ip_address, Port, Message) ->
Ip = (gleam@dynamic:tuple4(
fun gleam@dynamic:int/1,
fun gleam@dynamic:int/1,
fun gleam@dynamic:int/1,
fun gleam@dynamic:int/1
))(Ip_address),
Port@1 = gleam@dynamic:int(Port),
Data = gleam@dynamic:bit_array(Message),
case {Ip, Port@1, Data} of
{{ok, Ip@1}, {ok, Port@2}, {ok, Data@1}} ->
{udp_packet, Ip@1, Port@2, Data@1};
{_, _, _} ->
unknown
end
end
).
-file("/home/alex/gleams/grammy/src/grammy.gleam", 183).
-spec new(
fun(() -> {PNM, gleam@option:option(gleam@erlang@process:selector(PNN))}),
fun((message(PNN), connection(), PNM) -> gleam@otp@actor:next(PNN, PNM))
) -> builder(PNM, PNN).
new(Init, Handler) ->
{builder, Init, 4000, Handler}.
-file("/home/alex/gleams/grammy/src/grammy.gleam", 190).
-spec port(builder(PNU, PNV), integer()) -> builder(PNU, PNV).
port(Builder, Port) ->
erlang:setelement(3, Builder, Port).
-file("/home/alex/gleams/grammy/src/grammy.gleam", 226).
-spec ip_address_to_string({integer(), integer(), integer(), integer()}) -> binary().
ip_address_to_string(Ip) ->
<<<<<<<<<<<<(erlang:integer_to_binary(erlang:element(1, Ip)))/binary,
"."/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(2, Ip)))/binary>>/binary,
"."/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(3, Ip)))/binary>>/binary,
"."/utf8>>/binary,
(erlang:integer_to_binary(erlang:element(4, Ip)))/binary>>.
-file("/home/alex/gleams/grammy/src/grammy.gleam", 249).
-spec udp_send(
socket(),
{integer(), integer(), integer(), integer()},
integer(),
gleam@bytes_tree:bytes_tree()
) -> {ok, nil} | {error, nil}.
udp_send(Socket, Host, Port, Packet) ->
grammy_ffi:send(Socket, Host, Port, Packet).
-file("/home/alex/gleams/grammy/src/grammy.gleam", 236).
-spec send_to(
connection(),
{integer(), integer(), integer(), integer()},
integer(),
gleam@bytes_tree:bytes_tree()
) -> {ok, nil} | {error, nil}.
send_to(Connection, Address, Port, Data) ->
grammy_ffi:send(erlang:element(2, Connection), Address, Port, Data).
-file("/home/alex/gleams/grammy/src/grammy.gleam", 23).
-spec start(builder(any(), any())) -> {ok, udp_server()} |
{error, gleam@otp@actor:start_error()}.
start(Builder) ->
Ten_megabytes = (10 * 1024) * 1024,
Worker = gleam@otp@supervisor:worker(
fun(_) ->
_pipe@10 = gleam@otp@actor:start_spec(
{spec,
fun() ->
case gen_udp:open(
erlang:element(3, Builder),
[binary,
{active, once},
{sndbuf, Ten_megabytes},
{recbuf, Ten_megabytes}]
) of
{error, Reason} ->
{failed,
<<"Failed to open UDP socket: "/utf8,
(gleam@string:inspect(Reason))/binary>>};
{ok, Socket} ->
{User_state, User_selector} = (erlang:element(
2,
Builder
))(),
Message_selector = udp_message_selector(),
Selector = case User_selector of
{some, User} ->
_pipe = User,
_pipe@1 = gleam_erlang_ffi:map_selector(
_pipe,
fun(Field@0) -> {internal_user, Field@0} end
),
gleam_erlang_ffi:merge_selector(
_pipe@1,
Message_selector
);
none ->
Message_selector
end,
{ready,
{state, Socket, User_state, maps:new()},
Selector}
end
end,
500,
fun(Message, State) ->
Conn = {connection, erlang:element(2, State)},
case Message of
unknown ->
logging:log(
warning,
<<"Discarding unknown message type"/utf8>>
),
gleam@otp@actor:continue(State);
{udp_packet, Address, Port, Data} ->
Resp = (erlang:element(4, Builder))(
{packet, Address, Port, Data},
Conn,
erlang:element(3, State)
),
case Resp of
{continue, New_state, User_selector@1} ->
_pipe@2 = erlang:element(2, State),
_pipe@3 = grammy_ffi:set_active(_pipe@2),
_pipe@6 = gleam@result:map(
_pipe@3,
fun(_) ->
Selector@2 = gleam@option:map(
User_selector@1,
fun(Selector@1) ->
_pipe@4 = Selector@1,
_pipe@5 = gleam_erlang_ffi:map_selector(
_pipe@4,
fun(Field@0) -> {internal_user, Field@0} end
),
gleam_erlang_ffi:merge_selector(
_pipe@5,
udp_message_selector(
)
)
end
),
{continue,
erlang:setelement(
3,
State,
New_state
),
Selector@2}
end
),
_pipe@7 = gleam@result:map_error(
_pipe@6,
fun(Err) ->
logging:log(
error,
<<"Failed to set UDP socket active: "/utf8,
(gleam@string:inspect(
Err
))/binary>>
),
{stop,
{abnormal,
<<"Failed to set UDP socket active"/utf8>>}}
end
),
gleam@result:unwrap_both(_pipe@7);
{stop, Reason@1} ->
{stop, Reason@1}
end;
{internal_user, User@1} ->
case (erlang:element(4, Builder))(
{user, User@1},
Conn,
erlang:element(3, State)
) of
{continue, New_state@1, none} ->
gleam@otp@actor:continue(
erlang:setelement(
3,
State,
New_state@1
)
);
{continue,
New_state@2,
{some, New_user_selector}} ->
{continue,
erlang:setelement(
3,
State,
New_state@2
),
{some,
begin
_pipe@8 = New_user_selector,
_pipe@9 = gleam_erlang_ffi:map_selector(
_pipe@8,
fun(Field@0) -> {internal_user, Field@0} end
),
gleam_erlang_ffi:merge_selector(
_pipe@9,
udp_message_selector()
)
end}};
{stop, Reason@2} ->
{stop, Reason@2}
end
end
end}
),
gleam@result:map(
_pipe@10,
fun(Subj) ->
gleam_stdlib:println(
<<"UDP socket listening on port "/utf8,
(erlang:integer_to_binary(
erlang:element(3, Builder)
))/binary>>
),
Subj
end
)
end
),
_pipe@11 = gleam@otp@supervisor:start(
fun(Children) -> gleam@otp@supervisor:add(Children, Worker) end
),
gleam@result:map(_pipe@11, fun(Field@0) -> {udp_server, Field@0} end).