Skip to main content

src/starfruit@internal.erl

-module(starfruit@internal).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src\\starfruit\\internal.gleam").
-export([senddata/2, parse_url/4, router/1, response/1, bind/2]).
-export_type([response/0, response_code/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(false).

-type response() :: {response, binary(), binary(), bitstring()}.

-type response_code() :: status51 | status59 | status53.

-file("src\\starfruit\\internal.gleam", 18).
?DOC(false).
-spec senddata(list(gleam@bytes_tree:bytes_tree()), glisten:connection(any())) -> {ok,
        nil} |
    {error, glisten@socket:socket_reason()}.
senddata(Data, Conn) ->
    Firstsegment@1 = case gleam@list:first(Data) of
        {ok, Firstsegment} -> Firstsegment;
        _assert_fail ->
            erlang:error(#{gleam_error => let_assert,
                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                        file => <<?FILEPATH/utf8>>,
                        module => <<"starfruit/internal"/utf8>>,
                        function => <<"senddata"/utf8>>,
                        line => 22,
                        value => _assert_fail,
                        start => 451,
                        'end' => 497,
                        pattern_start => 462,
                        pattern_end => 478})
    end,
    case erlang:length(Data) of
        1 ->
            glisten:send(Conn, Firstsegment@1);

        _ ->
            case glisten:send(Conn, Firstsegment@1) of
                {ok, _} -> nil;
                _assert_fail@1 ->
                    erlang:error(#{gleam_error => let_assert,
                                message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                file => <<?FILEPATH/utf8>>,
                                module => <<"starfruit/internal"/utf8>>,
                                function => <<"senddata"/utf8>>,
                                line => 28,
                                value => _assert_fail@1,
                                start => 604,
                                'end' => 655,
                                pattern_start => 615,
                                pattern_end => 620})
            end,
            senddata(gleam@list:drop(Data, 1), Conn)
    end.

-file("src\\starfruit\\internal.gleam", 124).
?DOC(false).
-spec checkiflocalip(binary()) -> boolean().
checkiflocalip(Host) ->
    case Host of
        <<"::1"/utf8>> ->
            true;

        <<"localhost"/utf8>> ->
            true;

        <<"127.0.0.1"/utf8>> ->
            true;

        A ->
            Splitip = gleam@string:split(A, <<"."/utf8>>),
            case erlang:length(Splitip) of
                4 ->
                    Toint = gleam@list:map(
                        Splitip,
                        fun(A@1) ->
                            Z@1 = case gleam_stdlib:parse_int(A@1) of
                                {ok, Z} -> Z;
                                _assert_fail ->
                                    erlang:error(#{gleam_error => let_assert,
                                                message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                                file => <<?FILEPATH/utf8>>,
                                                module => <<"starfruit/internal"/utf8>>,
                                                function => <<"checkiflocalip"/utf8>>,
                                                line => 135,
                                                value => _assert_fail,
                                                start => 3763,
                                                'end' => 3794,
                                                pattern_start => 3774,
                                                pattern_end => 3779})
                            end,
                            Z@1
                        end
                    ),
                    case Toint of
                        [10, _, _, _] ->
                            true;

                        [172, A@2, _, _] ->
                            case gleam@bool:'and'(A@2 >= 16, A@2 < 32) of
                                true ->
                                    true;

                                false ->
                                    false
                            end;

                        [192, 168, _, _] ->
                            true;

                        _ ->
                            false
                    end;

                _ ->
                    false
            end
    end.

-file("src\\starfruit\\internal.gleam", 37).
?DOC(false).
-spec parse_url(bitstring(), integer(), binary(), glisten:ip_address()) -> {ok,
        binary()} |
    {error, response_code()}.
parse_url(Url, Boundport, Hostname, Clientip) ->
    gleam_stdlib:print(
        gleam@result:unwrap(
            gleam@bit_array:to_string(Url),
            <<"unwrappable request"/utf8>>
        )
    ),
    Checklength = fun(X) -> case X of
            {error, _} ->
                {error, status59};

            {ok, A} ->
                _assert_subject = <<"\r\n"/utf8>>,
                case gleam_stdlib:contains_string(A, _assert_subject) of
                    true -> nil;
                    false -> erlang:error(#{gleam_error => assert,
                            message => <<"Assertion failed."/utf8>>,
                            file => <<?FILEPATH/utf8>>,
                            module => <<"starfruit/internal"/utf8>>,
                            function => <<"parse_url"/utf8>>,
                            line => 48,
                            kind => function_call,
                            arguments => [#{kind => expression,
                                    value => A,
                                    start => 1271,
                                    'end' => 1272
                                    }, #{kind => literal,
                                    value => _assert_subject,
                                    start => 1274,
                                    'end' => 1280
                                    }],
                            start => 1248,
                            'end' => 1281,
                            expression_start => 1255})
                end,
                Trimmed = gleam@string:trim(A),
                case erlang:byte_size(Trimmed) > 1024 of
                    true ->
                        {error, status59};

                    false ->
                        {ok, Trimmed}
                end
        end end,
    Touri = fun(X@1) -> case X@1 of
            {error, A@1} ->
                {error, A@1};

            {ok, A@2} ->
                _pipe = gleam_stdlib:uri_parse(A@2),
                gleam@result:replace_error(_pipe, status59)
        end end,
    Checkscheme = fun(X@2) ->
        Validhost = fun(Hostname@1, Req, Client_ip) ->
            Reqdhostname = gleam@option:unwrap(Req, <<""/utf8>>),
            Client = glisten:ip_address_to_string(Client_ip),
            case checkiflocalip(Client) of
                true ->
                    checkiflocalip(Reqdhostname);

                false ->
                    Hostname@1 =:= Reqdhostname
            end
        end,
        case X@2 of
            {error, A@3} ->
                {error, A@3};

            {ok, A@4} ->
                case A@4 of
                    {uri, {some, <<"gemini"/utf8>>}, none, D, C, B, _, _} ->
                        case Validhost(Hostname, D, Clientip) of
                            false ->
                                {error, status53};

                            true ->
                                case C of
                                    none ->
                                        {ok, B};

                                    {some, C@1} ->
                                        case C@1 =:= Boundport of
                                            true ->
                                                {ok, B};

                                            false ->
                                                {error, status53}
                                        end
                                end
                        end;

                    {uri, none, _, _, _, _, _, _} ->
                        {error, status59};

                    _ ->
                        {error, status53}
                end
        end
    end,
    _ = begin
        _pipe@1 = gleam@bit_array:to_string(Url),
        _pipe@2 = Checklength(_pipe@1),
        _pipe@3 = Touri(_pipe@2),
        Checkscheme(_pipe@3)
    end.

-file("src\\starfruit\\internal.gleam", 199).
?DOC(false).
-spec router({ok, binary()} | {error, response_code()}) -> response().
router(Reqpath) ->
    Index = <<"/index.gmi"/utf8>>,
    Rootpath = gleam@result:map(
        Reqpath,
        fun(A) ->
            gleam_stdlib:string_remove_suffix(
                erlang:list_to_binary([<<"./capsule"/utf8>>, A]),
                <<"/"/utf8>>
            )
        end
    ),
    Path = case Rootpath of
        {ok, A@1} ->
            _pipe = case simplifile_erl:is_directory(A@1) of
                {ok, true} ->
                    {ok, erlang:list_to_binary([A@1, Index])};

                {ok, false} ->
                    {ok, A@1};

                {error, A@2} ->
                    {error, A@2}
            end,
            gleam@result:replace_error(_pipe, status51);

        {error, A@3} ->
            {error, A@3}
    end,
    Validfile = case Path of
        {ok, A@4} ->
            _pipe@1 = simplifile_erl:is_file(A@4),
            gleam@result:replace_error(_pipe@1, status51);

        {error, A@5} ->
            {error, A@5}
    end,
    case Validfile of
        {error, status59} ->
            {response, <<"59"/utf8>>, <<"59 - Bad request!"/utf8>>, <<>>};

        {error, status51} ->
            {response, <<"51"/utf8>>, <<"51 - Page not found!"/utf8>>, <<>>};

        {error, status53} ->
            {response,
                <<"53"/utf8>>,
                <<"53 - Proxy request denied!"/utf8>>,
                <<>>};

        {ok, false} ->
            {response, <<"51 "/utf8>>, <<"51 - Page not found!"/utf8>>, <<>>};

        {ok, true} ->
            Filepath = gleam@result:unwrap(Path, <<""/utf8>>),
            Filedata = begin
                _pipe@2 = simplifile_erl:read_bits(Filepath),
                gleam@result:unwrap(_pipe@2, <<>>)
            end,
            Mime = case gleam_stdlib:string_ends_with(Filepath, <<".gmi"/utf8>>) of
                true ->
                    <<"text/gemini"/utf8>>;

                false ->
                    mimetype:to_string(
                        mimetype:detect_with_filename(Filedata, Filepath)
                    )
            end,
            {response, <<"20"/utf8>>, Mime, Filedata}
    end.

-file("src\\starfruit\\internal.gleam", 260).
?DOC(false).
-spec slicebody(bitstring(), list(gleam@bytes_tree:bytes_tree())) -> list(gleam@bytes_tree:bytes_tree()).
slicebody(Data, Segments) ->
    Length = erlang:byte_size(Data),
    Getslice = fun(A, Len, Slicelen) ->
        _pipe = gleam_stdlib:bit_array_slice(A, Len, Slicelen),
        gleam@result:unwrap(_pipe, <<>>)
    end,
    case Length of
        0 ->
            Segments;

        _ ->
            case (Length =< 65536) of
                true ->
                    [gleam@bytes_tree:from_bit_array(Data) | Segments];

                false ->
                    slicebody(
                        Getslice(Data, 0, Length - 65536),
                        [gleam@bytes_tree:from_bit_array(
                                Getslice(Data, Length, - 65536)
                            ) |
                            Segments]
                    )
            end
    end.

-file("src\\starfruit\\internal.gleam", 249).
?DOC(false).
-spec response(response()) -> list(gleam@bytes_tree:bytes_tree()).
response(Data) ->
    gleam_stdlib:print(
        <<<<<<<<"Response: "/utf8, (erlang:element(2, Data))/binary>>/binary,
                    " "/utf8>>/binary,
                (erlang:element(3, Data))/binary>>/binary,
            "\r\n"/utf8>>
    ),
    Respstring = begin
        _pipe = erlang:list_to_binary(
            [erlang:element(2, Data),
                <<" "/utf8>>,
                erlang:element(3, Data),
                <<"\r\n"/utf8>>]
        ),
        gleam_stdlib:wrap_list(_pipe)
    end,
    [Respstring | slicebody(erlang:element(4, Data), [])].

-file("src\\starfruit\\internal.gleam", 285).
?DOC(false).
-spec bind(glisten:builder(nil, KUY), boolean()) -> glisten:builder(nil, KUY).
bind(Actor, Loopy) ->
    case Loopy of
        false ->
            glisten:bind(Actor, <<"0.0.0.0"/utf8>>);

        true ->
            Actor
    end.