Current section
Files
Jump to
Current section
Files
src/lily@server.erl
-module(lily@server).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/lily/server.gleam").
-export([connect/3, disconnect/2, incoming/3, start/2]).
-export_type([server_event/1, server_state/2]).
-opaque server_event(GPF) :: {client_connected,
binary(),
gleam@erlang@process:subject(binary())} |
{client_disconnected, binary()} |
{incoming, binary(), binary()} |
{gleam_phantom, GPF}.
-type server_state(GPG, GPH) :: {server_state,
lily@store:store(GPG, GPH),
gleam@dict:dict(binary(), gleam@erlang@process:subject(binary())),
integer(),
lily@protocol:serialiser(GPG, GPH)}.
-file("src/lily/server.gleam", 28).
-spec connect(
gleam@erlang@process:subject(server_event(any())),
binary(),
gleam@erlang@process:subject(binary())
) -> nil.
connect(Server, Client_id, Subject) ->
gleam@otp@actor:send(Server, {client_connected, Client_id, Subject}).
-file("src/lily/server.gleam", 37).
-spec disconnect(gleam@erlang@process:subject(server_event(any())), binary()) -> nil.
disconnect(Server, Client_id) ->
gleam@otp@actor:send(Server, {client_disconnected, Client_id}).
-file("src/lily/server.gleam", 45).
-spec incoming(
gleam@erlang@process:subject(server_event(any())),
binary(),
binary()
) -> nil.
incoming(Server, Client_id, Text) ->
gleam@otp@actor:send(Server, {incoming, Client_id, Text}).
-file("src/lily/server.gleam", 82).
-spec broadcast_except(
gleam@dict:dict(binary(), gleam@erlang@process:subject(binary())),
binary(),
binary()
) -> nil.
broadcast_except(Clients, Message, Excluded_id) ->
gleam@dict:each(Clients, fun(Id, Subject) -> case Id =:= Excluded_id of
true ->
nil;
false ->
gleam@erlang@process:send(Subject, Message)
end end).
-file("src/lily/server.gleam", 96).
-spec handle_client_connected(
server_state(GQF, GQG),
binary(),
gleam@erlang@process:subject(binary())
) -> gleam@otp@actor:next(server_state(GQF, GQG), server_event(GQG)).
handle_client_connected(State, Client_id, Subject) ->
Clients = gleam@dict:insert(erlang:element(3, State), Client_id, Subject),
gleam@otp@actor:continue(
{server_state,
erlang:element(2, State),
Clients,
erlang:element(4, State),
erlang:element(5, State)}
).
-file("src/lily/server.gleam", 106).
-spec handle_client_disconnected(server_state(GQP, GQQ), binary()) -> gleam@otp@actor:next(server_state(GQP, GQQ), server_event(GQQ)).
handle_client_disconnected(State, Client_id) ->
Clients = gleam@dict:delete(erlang:element(3, State), Client_id),
gleam@otp@actor:continue(
{server_state,
erlang:element(2, State),
Clients,
erlang:element(4, State),
erlang:element(5, State)}
).
-file("src/lily/server.gleam", 115).
-spec handle_client_message(server_state(GQY, GQZ), binary(), GQZ) -> gleam@otp@actor:next(server_state(GQY, GQZ), server_event(GQZ)).
handle_client_message(State, Client_id, Payload) ->
Updated_store = lily@store:apply(erlang:element(2, State), Payload),
New_sequence = erlang:element(4, State) + 1,
Server_message = {server_message, New_sequence, Payload},
Encoded = lily@protocol:encode(Server_message, erlang:element(5, State)),
broadcast_except(erlang:element(3, State), Encoded, Client_id),
Acknowledge = {acknowledge, New_sequence},
Acknowledge_encoded = lily@protocol:encode(
Acknowledge,
erlang:element(5, State)
),
case gleam_stdlib:map_get(erlang:element(3, State), Client_id) of
{ok, Subject} ->
gleam@erlang@process:send(Subject, Acknowledge_encoded);
{error, nil} ->
nil
end,
gleam@otp@actor:continue(
{server_state,
Updated_store,
erlang:element(3, State),
New_sequence,
erlang:element(5, State)}
).
-file("src/lily/server.gleam", 174).
-spec handle_resync(server_state(GSA, GSB), binary(), integer()) -> gleam@otp@actor:next(server_state(GSA, GSB), server_event(GSB)).
handle_resync(State, Client_id, _) ->
case gleam_stdlib:map_get(erlang:element(3, State), Client_id) of
{error, nil} ->
gleam@otp@actor:continue(State);
{ok, Subject} ->
Snapshot = {snapshot,
erlang:element(4, State),
lily@store:get_model(erlang:element(2, State))},
Encoded = lily@protocol:encode(Snapshot, erlang:element(5, State)),
gleam@erlang@process:send(Subject, Encoded),
gleam@otp@actor:continue(State)
end.
-file("src/lily/server.gleam", 142).
-spec handle_incoming(server_state(GRH, GRI), binary(), binary()) -> gleam@otp@actor:next(server_state(GRH, GRI), server_event(GRI)).
handle_incoming(State, Client_id, Text) ->
case lily@protocol:decode(Text, erlang:element(5, State)) of
{ok, {client_message, Payload}} ->
handle_client_message(State, Client_id, Payload);
{ok, {resync, After_sequence}} ->
handle_resync(State, Client_id, After_sequence);
_ ->
gleam@otp@actor:continue(State)
end.
-file("src/lily/server.gleam", 159).
-spec handle_message(server_state(GRQ, GRR), server_event(GRR)) -> gleam@otp@actor:next(server_state(GRQ, GRR), server_event(GRR)).
handle_message(State, Message) ->
case Message of
{client_connected, Client_id, Subject} ->
handle_client_connected(State, Client_id, Subject);
{client_disconnected, Client_id@1} ->
handle_client_disconnected(State, Client_id@1);
{incoming, Client_id@2, Text} ->
handle_incoming(State, Client_id@2, Text)
end.
-file("src/lily/server.gleam", 54).
-spec start(lily@store:store(GPS, GPT), lily@protocol:serialiser(GPS, GPT)) -> {ok,
gleam@erlang@process:subject(server_event(GPT))} |
{error, gleam@otp@actor:start_error()}.
start(Store, Serialiser) ->
Initial_state = {server_state, Store, maps:new(), 0, Serialiser},
_pipe = gleam@otp@actor:new(Initial_state),
_pipe@1 = gleam@otp@actor:on_message(_pipe, fun handle_message/2),
_pipe@2 = gleam@otp@actor:start(_pipe@1),
gleam@result:map(_pipe@2, fun(Started) -> erlang:element(3, Started) end).