Current section
Files
Jump to
Current section
Files
src/spectator.erl
-module(spectator).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([tag/2, tag_subject/2, tag_result/2, start_on/1, start/0, main/0]).
-export_type([node_connection_error/0]).
-type node_connection_error() :: not_distributed_error |
failed_to_set_cookie_error |
failed_to_connect_error.
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 146).
-spec tag(gleam@erlang@process:pid_(), binary()) -> gleam@erlang@process:pid_().
tag(Pid, Name) ->
spectator_tag_manager:add_tag(Pid, Name),
Pid.
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 153).
-spec tag_subject(gleam@erlang@process:subject(AUEP), binary()) -> gleam@erlang@process:subject(AUEP).
tag_subject(Sub, Name) ->
Pid = gleam@erlang@process:subject_owner(Sub),
tag(Pid, Name),
Sub.
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 164).
-spec tag_result(
{ok, gleam@erlang@process:subject(AUES)} | {error, AUEU},
binary()
) -> {ok, gleam@erlang@process:subject(AUES)} | {error, AUEU}.
tag_result(Result, Name) ->
case Result of
{ok, Sub} ->
{ok, tag_subject(Sub, Name)};
Other ->
Other
end.
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 180).
-spec validate_node_connection(list({binary(), binary()})) -> {ok, binary()} |
{error, node_connection_error()}.
validate_node_connection(Params) ->
Node_res = spectator@internal@common:get_param(Params, <<"node"/utf8>>),
case Node_res of
{error, _} ->
{ok, <<""/utf8>>};
{ok, Node} ->
Self = begin
_pipe = erlang:node(),
gleam_erlang_ffi:identity(_pipe)
end,
gleam@bool:guard(
Self =:= erlang:binary_to_atom(<<"nonode@nohost"/utf8>>),
{error, not_distributed_error},
fun() ->
Node_atom = erlang:binary_to_atom(Node),
Cookie_validation_passed = case spectator@internal@common:get_param(
Params,
<<"cookie"/utf8>>
) of
{error, _} ->
true;
{ok, Cookie} ->
Cookie_atom = erlang:binary_to_atom(Cookie),
gleam@result:unwrap(
spectator_ffi:set_cookie(Node_atom, Cookie_atom),
false
)
end,
gleam@bool:guard(
not Cookie_validation_passed,
{error, failed_to_set_cookie_error},
fun() ->
gleam@bool:guard(
not gleam@result:unwrap(
spectator_ffi:hidden_connect_node(Node_atom),
false
),
{error, failed_to_connect_error},
fun() ->
{ok,
<<"🟢 "/utf8,
(erlang:atom_to_binary(Node_atom))/binary>>}
end
)
end
)
end
)
end.
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 220).
-spec render_server_component(binary(), binary(), list({binary(), binary()})) -> gleam@http@response:response(mist:response_data()).
render_server_component(Title, Path, Params) ->
Res = gleam@http@response:new(200),
Styles = spectator@internal@common:static_file(<<"styles.css"/utf8>>),
Html = case validate_node_connection(Params) of
{ok, Connection_name} ->
lustre@element@html:html(
[],
[lustre@element@html:head(
[],
[lustre@element@html:title([], Title),
lustre@server_component:script(),
lustre@element@html:meta(
[lustre@attribute:attribute(
<<"charset"/utf8>>,
<<"utf-8"/utf8>>
)]
),
lustre@element@html:link(
[lustre@attribute:rel(<<"icon"/utf8>>),
lustre@attribute:href(
<<"/favicon.svg"/utf8>>
),
lustre@attribute:type_(
<<"image/svg+xml"/utf8>>
)]
),
lustre@element@html:style([], Styles)]
),
lustre@element@html:body(
[],
[spectator@internal@views@navbar:render(
Title,
Connection_name,
begin
_pipe = spectator@internal@common:sanitize_params(
Params
),
spectator@internal@common:encode_params(
_pipe
)
end
),
lustre@element:element(
<<"lustre-server-component"/utf8>>,
[lustre@server_component:route(
<<<<"/"/utf8, Path/binary>>/binary,
(spectator@internal@common:encode_params(
Params
))/binary>>
)],
[]
)]
)]
);
{error, Connection_error} ->
lustre@element@html:html(
[],
[lustre@element@html:head(
[],
[lustre@element@html:title([], Title),
lustre@element@html:meta(
[lustre@attribute:attribute(
<<"charset"/utf8>>,
<<"utf-8"/utf8>>
)]
),
lustre@element@html:link(
[lustre@attribute:rel(<<"icon"/utf8>>),
lustre@attribute:href(
<<"/favicon.svg"/utf8>>
),
lustre@attribute:type_(
<<"image/svg+xml"/utf8>>
)]
),
lustre@element@html:style([], Styles)]
),
lustre@element@html:body(
[],
[spectator@internal@views@navbar:render(
Title,
<<"Connection Failed"/utf8>>,
begin
_pipe@1 = spectator@internal@common:sanitize_params(
Params
),
spectator@internal@common:encode_params(
_pipe@1
)
end
),
lustre@element@html:'div'(
[lustre@attribute:class(
<<"component-error"/utf8>>
)],
[lustre@element@html:'div'(
[],
[lustre@element@html:text(
<<"Node connection failed:"/utf8>>
)]
),
lustre@element@html:'div'(
[],
[lustre@element@html:text(
case Connection_error of
not_distributed_error ->
<<"Node is not distributed, cannot connect to other nodes. Please start the spectator instance in distributed mode by setting a node name."/utf8>>;
failed_to_set_cookie_error ->
<<"Failed to set cookie, could not apply the cookie to the node"/utf8>>;
failed_to_connect_error ->
<<"Failed to connect to node, please check the node name and cookie"/utf8>>
end
)]
),
lustre@element@html:'div'(
[],
[lustre@element@html:a(
[lustre@attribute:href(
<<"/"/utf8>>
),
lustre@attribute:class(
<<"button"/utf8>>
)],
[lustre@element@html:text(
<<"Return to local node"/utf8>>
)]
)]
)]
)]
)]
)
end,
gleam@http@response:set_body(
Res,
begin
_pipe@2 = Html,
_pipe@3 = lustre@element:to_document_string(_pipe@2),
_pipe@4 = gleam_stdlib:wrap_list(_pipe@3),
{bytes, _pipe@4}
end
).
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 312).
-spec connect_server_component(
gleam@http@request:request(mist@internal@http:connection()),
fun(() -> lustre:app(list({binary(), binary()}), any(), any())),
list({binary(), binary()})
) -> gleam@http@response:response(mist:response_data()).
connect_server_component(Req, Lustre_application, Params) ->
Socket_init = fun(_) ->
Self = gleam@erlang@process:new_subject(),
App = Lustre_application(),
_assert_subject = lustre:start_actor(App, Params),
{ok, Live_component} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"spectator"/utf8>>,
function => <<"connect_server_component"/utf8>>,
line => 320})
end,
tag_subject(
Live_component,
<<"__spectator_internal Server Component"/utf8>>
),
gleam@erlang@process:send(
Live_component,
lustre@server_component:subscribe(
<<"ws"/utf8>>,
fun(_capture) -> gleam@erlang@process:send(Self, _capture) end
)
),
{Live_component,
{some,
gleam@erlang@process:selecting(
gleam_erlang_ffi:new_selector(),
Self,
fun(A) -> A end
)}}
end,
Socket_update = fun(Live_component@1, Conn, Msg) -> case Msg of
{text, Json} ->
Action = gleam@json:decode(
Json,
fun lustre@server_component:decode_action/1
),
case Action of
{ok, Action@1} ->
gleam@erlang@process:send(Live_component@1, Action@1);
{error, _} ->
nil
end,
gleam@otp@actor:continue(Live_component@1);
{binary, _} ->
gleam@otp@actor:continue(Live_component@1);
{custom, Patch} ->
_assert_subject@1 = begin
_pipe = Patch,
_pipe@1 = lustre@server_component:encode_patch(_pipe),
_pipe@2 = gleam@json:to_string(_pipe@1),
mist:send_text_frame(Conn, _pipe@2)
end,
{ok, _} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail@1,
module => <<"spectator"/utf8>>,
function => <<"connect_server_component"/utf8>>,
line => 357})
end,
gleam@otp@actor:continue(Live_component@1);
closed ->
{stop, normal};
shutdown ->
{stop, normal}
end end,
Socket_close = fun(Live_component@2) ->
gleam@erlang@process:send(Live_component@2, lustre:shutdown())
end,
mist:websocket(Req, Socket_update, Socket_init, Socket_close).
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 41).
-spec start_server(integer()) -> {ok, gleam@erlang@process:pid_()} |
{error, nil}.
start_server(Port) ->
Empty_body = {bytes, gleam@bytes_tree:new()},
Not_found = gleam@http@response:set_body(
gleam@http@response:new(404),
Empty_body
),
Server_result = begin
_pipe@9 = fun(Req) ->
Query_params = begin
_pipe = gleam@http@request:get_query(Req),
gleam@result:unwrap(_pipe, [])
end,
case gleam@http@request:path_segments(Req) of
[<<"dashboard"/utf8>>] ->
render_server_component(
<<"Dashboard"/utf8>>,
<<"dashboard-feed"/utf8>>,
Query_params
);
[<<"processes"/utf8>>] ->
render_server_component(
<<"Processes"/utf8>>,
<<"process-feed"/utf8>>,
Query_params
);
[<<"ets"/utf8>>] ->
render_server_component(
<<"ETS"/utf8>>,
<<"ets-feed"/utf8>>,
Query_params
);
[<<"ets"/utf8>>, Table] ->
render_server_component(
<<"ETS"/utf8>>,
<<"ets-feed/"/utf8, Table/binary>>,
Query_params
);
[<<"ports"/utf8>>] ->
render_server_component(
<<"Ports"/utf8>>,
<<"port-feed"/utf8>>,
Query_params
);
[<<"dashboard-feed"/utf8>>] ->
connect_server_component(
Req,
fun spectator@internal@components@dashboard_live:app/0,
Query_params
);
[<<"process-feed"/utf8>>] ->
connect_server_component(
Req,
fun spectator@internal@components@processes_live:app/0,
Query_params
);
[<<"ets-feed"/utf8>>] ->
connect_server_component(
Req,
fun spectator@internal@components@ets_overview_live:app/0,
Query_params
);
[<<"ets-feed"/utf8>>, Table@1] ->
connect_server_component(
Req,
fun spectator@internal@components@ets_table_live:app/0,
[{<<"table_name"/utf8>>,
begin
_pipe@1 = gleam_stdlib:percent_decode(
Table@1
),
gleam@result:unwrap(_pipe@1, <<""/utf8>>)
end} |
Query_params]
);
[<<"port-feed"/utf8>>] ->
connect_server_component(
Req,
fun spectator@internal@components@ports_live:app/0,
Query_params
);
[<<"favicon.svg"/utf8>>] ->
_assert_subject = gleam_erlang_ffi:priv_directory(
<<"spectator"/utf8>>
),
{ok, Priv} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"spectator"/utf8>>,
function => <<"start_server"/utf8>>,
line => 74})
end,
Path = <<Priv/binary, "/lucy_spectator.svg"/utf8>>,
_pipe@2 = mist:send_file(Path, 0, none),
_pipe@5 = gleam@result:map(
_pipe@2,
fun(Favicon) -> _pipe@3 = gleam@http@response:new(200),
_pipe@4 = gleam@http@response:prepend_header(
_pipe@3,
<<"content-type"/utf8>>,
<<"image/svg+xml"/utf8>>
),
gleam@http@response:set_body(_pipe@4, Favicon) end
),
gleam@result:lazy_unwrap(
_pipe@5,
fun() -> _pipe@6 = gleam@http@response:new(404),
gleam@http@response:set_body(
_pipe@6,
{bytes, gleam@bytes_tree:new()}
) end
);
[] ->
_pipe@7 = gleam@http@response:new(302),
_pipe@8 = gleam@http@response:prepend_header(
_pipe@7,
<<"location"/utf8>>,
<<"/dashboard"/utf8>>
),
gleam@http@response:set_body(_pipe@8, Empty_body);
_ ->
Not_found
end
end,
_pipe@10 = mist:new(_pipe@9),
_pipe@12 = mist:after_start(
_pipe@10,
fun(Port@1, Scheme, Interface) ->
Address = case Interface of
{ip_v6, _, _, _, _, _, _, _, _} ->
<<<<"["/utf8,
(mist:ip_address_to_string(Interface))/binary>>/binary,
"]"/utf8>>;
_ ->
mist:ip_address_to_string(Interface)
end,
Message = <<<<<<<<<<<<<<"🔍 Spectator is listening on "/utf8,
(gleam@http:scheme_to_string(Scheme))/binary>>/binary,
"://"/utf8>>/binary,
Address/binary>>/binary,
":"/utf8>>/binary,
(erlang:integer_to_binary(Port@1))/binary>>/binary,
" - Node: "/utf8>>/binary,
(erlang:atom_to_binary(
begin
_pipe@11 = erlang:node(),
gleam_erlang_ffi:identity(_pipe@11)
end
))/binary>>,
gleam_stdlib:println(Message)
end
),
_pipe@13 = mist:port(_pipe@12, Port),
mist:start_http(_pipe@13)
end,
case Server_result of
{ok, Server} ->
Server_pid = gleam@erlang@process:subject_owner(Server),
tag(Server_pid, <<"__spectator_internal Server"/utf8>>),
{ok, Server_pid};
{error, _} ->
{error, nil}
end.
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 135).
-spec start_on(integer()) -> {ok, gleam@erlang@process:pid_()} |
{error, gleam@dynamic:dynamic_()}.
start_on(Port) ->
_pipe = gleam@otp@static_supervisor:new(one_for_one),
_pipe@1 = gleam@otp@static_supervisor:add(
_pipe,
gleam@otp@static_supervisor:worker_child(
<<"Spectator Tag Manager"/utf8>>,
fun spectator_tag_manager:start_link/0
)
),
_pipe@2 = gleam@otp@static_supervisor:add(
_pipe@1,
gleam@otp@static_supervisor:worker_child(
<<"Spectator Mist Server"/utf8>>,
fun() -> start_server(Port) end
)
),
gleam@otp@static_supervisor:start_link(_pipe@2).
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 131).
-spec start() -> {ok, gleam@erlang@process:pid_()} |
{error, gleam@dynamic:dynamic_()}.
start() ->
start_on(3000).
-file("/Users/jonas/Projects/spectator/src/spectator.gleam", 36).
-spec main() -> nil.
main() ->
_assert_subject = start(),
{ok, _} = case _assert_subject of
{ok, _} -> _assert_subject;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
value => _assert_fail,
module => <<"spectator"/utf8>>,
function => <<"main"/utf8>>,
line => 37})
end,
gleam_erlang_ffi:sleep_forever().