<commit_before>-module(unbound_server).
-behaviour(gen_server).
-export_type([async_ref/0]).
-opaque async_ref() :: {integer(), reference()}.

-include("internal.hrl").

%% API.
-export([start_link/0, start_link/1]).
-export([resolve/2, resolve/3, resolve/4, cancel/2, cancel_noflush/2]).
-export([defaults/0]).

%% gen_server.
-export([init/1]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).

-record(client, {ref, pid}).
-record(request, {
    q :: #ub_question{},
    async_id,
    clients :: [#client{}]
}).
-record(state, {port, requests = []}).

%% API.

-spec start_link() -> {ok, pid()}.
start_link() ->
    start_link(defaults()).

start_link(Opts) when is_list(Opts) ->
    case lists:keyfind(register, 1, Opts) of
        {register, ServerName} ->
            gen_server:start_link(ServerName, ?MODULE, Opts, []);
        false -> gen_server:start_link(?MODULE, Opts, [])
    end.

resolve(ServerRef, Name, Type) ->
    resolve(ServerRef, Name, Type, ?UB_CL_IN).

resolve(ServerRef, Name, Type, Class) ->
    resolve(ServerRef, #ub_question{name = Name, type = Type, class = Class}).

resolve(ServerRef, #ub_question{name = N} = Q) when is_list(N) ->
    resolve(ServerRef, Q#ub_question{name = iolist_to_binary(N)});
resolve(ServerRef, #ub_question{name = N, type = T, class = C} = Q)
    when is_binary(N) andalso
         is_integer(T), T > 0, T < 65535 andalso
         is_integer(C), C > 0, C < 65535 ->
    gen_server:call(ServerRef, {resolve, Q}).

cancel(ServerRef, AsyncRef) ->
    Result = cancel_noflush(ServerRef, AsyncRef),
    receive #ub_callback{ref = AsyncRef} -> Result
    after 0 -> Result end.

cancel_noflush(ServerRef, AsyncRef) ->
    gen_server:call(ServerRef, {cancel, AsyncRef}).

defaults() ->
    Args = application:get_env(unbound, server_defaults, []),
    true = is_list(Args),
    false = lists:keymember(register, 1, Args),
    Args.

%% gen_server.

init(Opts) ->
    {ok, Port} = unbound_drv:open(),
    IsMain = whereis(unbound) =:= self(),
    init(Port, IsMain, Opts).

init(Port, _IsMain, []) ->
    {ok, #state{port = Port}};
init(Port, IsMain, [Opt|Opts]) ->
    [ ok = apply(unbound_drv, Function, [Port|Args])
      || {Function, Args} <- init_drv_sig(IsMain, Opt) ],
    init(Port, IsMain, Opts).

init_drv_sig(_IsMain, {register, _ServerRef}) -> [];
init_drv_sig(IsMain, {trust_anchor, auto}) ->
    init_drv_sig(IsMain, {trust_anchor, {auto, {priv, "root.key"}}});
init_drv_sig(IsMain, {trust_anchor, read}) ->
    init_drv_sig(IsMain, {trust_anchor, {read, {priv, "root.key"}}});
init_drv_sig(true, {trust_anchor, {auto, Path}}) ->
    init_drv_sig(true, {trust_anchor, {maintain, Path}});
init_drv_sig(false, {trust_anchor, {auto, Path}}) ->
    init_drv_sig(false, {trust_anchor, {read, Path}});
init_drv_sig(_IsMain, {trust_anchor, {maintain, Path}}) ->
    [{add_ta_autr, [init_drv_sig_path(Path)]}];
init_drv_sig(_IsMain, {trust_anchor, {read, Path}}) -><commit_msg>make unbound_server:defaults/0 checks options are valid<commit_after>-module(unbound_server).
-behaviour(gen_server).
-export_type([async_ref/0]).
-opaque async_ref() :: {integer(), reference()}.

-include("internal.hrl").

%% API.
-export([start_link/0, start_link/1]).
-export([resolve/2, resolve/3, resolve/4, cancel/2, cancel_noflush/2]).
-export([defaults/0]).

%% gen_server.
-export([init/1]).
-export([handle_call/3]).
-export([handle_cast/2]).
-export([handle_info/2]).
-export([terminate/2]).
-export([code_change/3]).

-record(client, {ref, pid}).
-record(request, {
    q :: #ub_question{},
    async_id,
    clients :: [#client{}]
}).
-record(state, {port, requests = []}).

%% API.

-spec start_link() -> {ok, pid()}.
start_link() ->
    start_link(defaults()).

start_link(Opts) when is_list(Opts) ->
    case lists:keyfind(register, 1, Opts) of
        {register, ServerName} ->
            gen_server:start_link(ServerName, ?MODULE, Opts, []);
        false -> gen_server:start_link(?MODULE, Opts, [])
    end.

resolve(ServerRef, Name, Type) ->
    resolve(ServerRef, Name, Type, ?UB_CL_IN).

resolve(ServerRef, Name, Type, Class) ->
    resolve(ServerRef, #ub_question{name = Name, type = Type, class = Class}).

resolve(ServerRef, #ub_question{name = N} = Q) when is_list(N) ->
    resolve(ServerRef, Q#ub_question{name = iolist_to_binary(N)});
resolve(ServerRef, #ub_question{name = N, type = T, class = C} = Q)
    when is_binary(N) andalso
         is_integer(T), T > 0, T < 65535 andalso
         is_integer(C), C > 0, C < 65535 ->
    gen_server:call(ServerRef, {resolve, Q}).

cancel(ServerRef, AsyncRef) ->
    Result = cancel_noflush(ServerRef, AsyncRef),
    receive #ub_callback{ref = AsyncRef} -> Result
    after 0 -> Result end.

cancel_noflush(ServerRef, AsyncRef) ->
    gen_server:call(ServerRef, {cancel, AsyncRef}).

defaults() ->
    Args = application:get_env(unbound, server_defaults, []),
    Ok = lists:all(fun(Arg) ->
        case init_drv_sig(false, Arg) of
            [{add_ta_autr, _}] -> false;
            _ -> element(1, Arg) =/= register
        end
    end, Args),
    case Ok of
        true -> Args;
        false -> erlang:error(badarg)
    end.

%% gen_server.

init(Opts) ->
    {ok, Port} = unbound_drv:open(),
    IsMain = whereis(unbound) =:= self(),
    init(Port, IsMain, Opts).

init(Port, _IsMain, []) ->
    {ok, #state{port = Port}};
init(Port, IsMain, [Opt|Opts]) ->
    [ ok = apply(unbound_drv, Function, [Port|Args])
      || {Function, Args} <- init_drv_sig(IsMain, Opt) ],
    init(Port, IsMain, Opts).

init_drv_sig(_IsMain, {register, _ServerRef}) -> [];
init_drv_sig(IsMain, {trust_anchor, auto}) ->
    init_drv_sig(IsMain, {trust_anchor, {auto, {priv, "root.key"}}});
init_drv_sig(IsMain, {trust_anchor, read}) ->
    init_drv_sig(IsMain, {trust_anchor, {read, {priv, "root.key"}}});
init_drv_sig(true, {trust_anchor, {auto, Path}}) ->
    init_drv_sig(true, {trust_anchor, {maintain, Path}});
init_drv_sig(false, {trust_anchor, {auto, Path}}) ->
    init_drv_sig(false, {trust_anchor, {read, Path}});
init_drv_sig(_IsMain, {trust_anchor, {maintain, Path}}) ->
    [{add_ta_autr, [init_drv_sig_path(Path)]}];
init_drv_sig(_IsMain, {trust_anchor, {read, Path}}) ->
{'fraction_non_alphanumeric': 0.18902926595234287, 'fraction_numerical': 0.00975531744762514, 'mean_word_length': 4.1053061224489795, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 60, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1167841', 'n_tokens_mistral': 2370, 'n_tokens_neox': 2317, 'n_words': 452}