Current section
Files
Jump to
Current section
Files
src/butterbee@config.erl
-module(butterbee@config).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/butterbee/config.gleam").
-export([with_driver_config/2, with_capabilities/2, with_browser_config/3, default_individual_browser_config/1, configuration_options_decoder/1, browser_config_decoder/0, driver_config_decoder/0, parse_config_string/1, parse_config/1, default_capabilities_config/0, default_browser_config/0, browser_type_to_string/1, browser_type_decoder/0, with_start_url/2, with_cmd/2, with_extra_flags/2, with_host/2]).
-export_type([butterbee_config/0, error/0, driver_config/0, browser_type/0, browser_config/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(
" Butterbee can be configured using the `gleam.toml` file.\n"
" When you call the `new` function in the webdriver module, butterbee tries \n"
" to parse the `gleam.toml` file in the root of the project. If it can't find it,\n"
" it will use the default configuration.\n"
"\n"
" Example of the default configuration in toml format:\n"
"\n"
" ```toml\n"
" # gleam.toml\n"
"\n"
" [tools.butterbee.driver]\n"
" max_wait_time = 20000\n"
" request_timeout = 5000\n"
" data_dir = \"/tmp/butterbee\"\n"
"\n"
" [tools.butterbee.capabilities.always_match]\n"
" webSocketUrl = true\n"
"\n"
" [tools.butterbee.browser.firefox]\n"
" cmd = \"firefox\"\n"
" flags = []\n"
" host = \"127.0.0.1\"\n"
"\n"
" [tools.butterbee.browser.chromium]\n"
" cmd = \"chromedriver\"\n"
" flags = []\n"
" host = \"127.0.0.1\"\n"
" ```\n"
"\n"
" ## Driver Config\n"
"\n"
" The driver config module contains functions for parsing and creating driver\n"
" configurations. The driver configuration specifies general options the webdriver\n"
" needs to run, such as the maximum wait time, and the request timeout.\n"
"\n"
" ```toml\n"
" # gleam.toml\n"
"\n"
" [tools.butterbee.driver]\n"
" max_wait_time = 20000\n"
" request_timeout = 5000\n"
" data_dir = \"/tmp/butterbee\"\n"
" ```\n"
"\n"
" ## Capabilities Config\n"
"\n"
" This module provides functionality for parsing and creating capabilities requests \n"
" from TOML configuration files for WebDriver(state) BiDi sessions.\n"
"\n"
" In browser automation contexts, **capabilities** define the desired properties \n"
" and features that a WebDriver(state) session should support. They specify requirements \n"
" like browser version, platform, extensions, timeouts, and other session-specific \n"
" configurations. Capabilities are used during session negotiation to match the \n"
" requested features with what the browser/driver can provide.\n"
"\n"
" The capabilities matching process typically involves:\n"
" - `always_match`: Capabilities that must be satisfied for the session to be created\n"
" - `first_match`: A list of capability sets where at least one must be satisfied\n"
"\n"
" ```toml\n"
" # gleam.toml\n"
" # TODO: add realistic example here, the current example works but is not realistic\n"
"\n"
" [tools.butterbee.capabilities.always_match]\n"
" webSocketUrl = true\n"
" \"goog:chromeOptions\" = { args = [\"--headless=new\"] }\n"
"\n"
" [[tools.butterbee.capabilities.first_match]]\n"
" browserVersion = \"latest\"\n"
" \"chrome:options\" = { debuggerAddress = \"localhost:9222\" }\n"
"\n"
" [[tools.butterbee.capabilities.first_match]]\n"
" \"moz:firefoxOptions\" = { binary = \"/usr/bin/firefox\", args = [\n"
" \"-headless\",\n"
" \"-safe-mode\",\n"
" ], prefs = { \"dom.webnotifications.enabled\" = false }, log = { level = \"trace\" } }\n"
" browserVersion = \"stable\"\n"
" }\n"
" ```\n"
"\n"
" ## Browser Config\n"
"\n"
" This module provides functionality for parsing and creating browser configurations\n"
" from TOML configuration files for WebDriver BiDi sessions.\n"
"\n"
" ### Chromium support\n"
"\n"
" Because chromium does not natively support WebDriver BiDi, \n"
" butterbee uses the [chromedriver](https://chromedriver.chromium.org/downloads)\n"
" to control chromium. Which has a BiDi to CDP mapper built in.\n"
"\n"
" Chromedriver does not come with chromium built in, so make sure you have chromium installed.\n"
" Chromedriver will search for the chromium binary on your system. so no additional \n"
" configuration is needed.\n"
"\n"
" ```toml\n"
" # gleam.toml\n"
"\n"
" [tools.butterbee.browser.firefox]\n"
" cmd = \"firefox\"\n"
" flags = [\"-headless\"]\n"
" host = \"127.0.0.1\"\n"
"\n"
" [tools.butterbee.browser.chromium]\n"
" cmd = \"chromedriver\"\n"
" flags = []\n"
" host = \"127.0.0.1\"\n"
" ```\n"
"\n"
" #### Headless\n"
" to run the browsers headless, add the following to your `gleam.toml` file:\n"
"\n"
" ```toml\n"
" [tools.butterbee.browser.firefox]\n"
" flags = [\"-headless\"]\n"
"\n"
" [tools.butterbee.capabilities.always_match]\n"
" webSocketUrl = true\n"
" \"goog:chromeOptions\" = { args = [\"--headless=new\"] }\n"
" ```\n"
).
-type butterbee_config() :: {butterbee_config,
driver_config(),
gleam@option:option(butterbidi@session@types@capabilities_request:capabilities_request()),
gleam@option:option(gleam@dict:dict(browser_type(), browser_config()))}.
-type error() :: {read_error, simplifile:file_error()} |
{parse_error, tom:parse_error()} |
{decode_error, list(gleam@dynamic@decode:decode_error())}.
-type driver_config() :: {driver_config, integer(), integer(), binary()}.
-type browser_type() :: firefox | chromium.
-type browser_config() :: {browser_config,
binary(),
binary(),
list(binary()),
binary()}.
-file("src/butterbee/config.gleam", 156).
-spec with_driver_config(butterbee_config(), driver_config()) -> butterbee_config().
with_driver_config(Config, Driver) ->
{butterbee_config,
Driver,
erlang:element(3, Config),
erlang:element(4, Config)}.
-file("src/butterbee/config.gleam", 163).
-spec with_capabilities(
butterbee_config(),
butterbidi@session@types@capabilities_request:capabilities_request()
) -> butterbee_config().
with_capabilities(Config, Capabilities) ->
{butterbee_config,
erlang:element(2, Config),
{some, Capabilities},
erlang:element(4, Config)}.
-file("src/butterbee/config.gleam", 170).
-spec with_browser_config(butterbee_config(), browser_type(), browser_config()) -> butterbee_config().
with_browser_config(Config, Browser_type, Browser_config) ->
Apply_config = fun(Dict, Browser_type@1, Browser_config@1) ->
case Browser_type@1 of
firefox ->
gleam@dict:insert(Dict, Browser_type@1, Browser_config@1);
chromium ->
gleam@dict:insert(Dict, Browser_type@1, Browser_config@1)
end
end,
Browser_config@2 = case erlang:element(4, Config) of
none ->
Apply_config(maps:new(), Browser_type, Browser_config);
{some, Existing_config} ->
Apply_config(Existing_config, Browser_type, Browser_config)
end,
{butterbee_config,
erlang:element(2, Config),
erlang:element(3, Config),
{some, Browser_config@2}}.
-file("src/butterbee/config.gleam", 378).
?DOC(false).
-spec default_individual_browser_config(browser_type()) -> browser_config().
default_individual_browser_config(Browser_type) ->
Cmd = case Browser_type of
firefox ->
<<"firefox"/utf8>>;
chromium ->
<<"chromedriver"/utf8>>
end,
Default_start_url = case Browser_type of
firefox ->
<<"about:blank"/utf8>>;
chromium ->
<<"about:blank"/utf8>>
end,
{browser_config, Default_start_url, Cmd, [], <<"127.0.0.1"/utf8>>}.
-file("src/butterbee/config.gleam", 440).
?DOC(false).
-spec configuration_options_decoder(browser_type()) -> gleam@dynamic@decode:decoder(browser_config()).
configuration_options_decoder(Browser_type) ->
{browser_config, Start_url, Cmd, Extra_flags, Host} = default_individual_browser_config(
Browser_type
),
gleam@dynamic@decode:optional_field(
<<"start_url"/utf8>>,
Start_url,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Start_url@1) ->
gleam@dynamic@decode:optional_field(
<<"cmd"/utf8>>,
Cmd,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Cmd@1) ->
gleam@dynamic@decode:optional_field(
<<"flags"/utf8>>,
Extra_flags,
gleam@dynamic@decode:list(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
fun(Extra_flags@1) ->
gleam@dynamic@decode:optional_field(
<<"host"/utf8>>,
Host,
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Host@1) ->
gleam@dynamic@decode:success(
{browser_config,
Start_url@1,
Cmd@1,
Extra_flags@1,
Host@1}
)
end
)
end
)
end
)
end
).
-file("src/butterbee/config.gleam", 419).
?DOC(false).
-spec browser_config_decoder() -> gleam@dynamic@decode:decoder(gleam@dict:dict(browser_type(), browser_config())).
browser_config_decoder() ->
gleam@dynamic@decode:optional_field(
<<"firefox"/utf8>>,
default_individual_browser_config(firefox),
configuration_options_decoder(firefox),
fun(Firefox_config) ->
gleam@dynamic@decode:optional_field(
<<"chromium"/utf8>>,
default_individual_browser_config(chromium),
configuration_options_decoder(chromium),
fun(Chromium_config) ->
gleam@dynamic@decode:success(
begin
_pipe = maps:new(),
_pipe@1 = gleam@dict:insert(
_pipe,
firefox,
Firefox_config
),
gleam@dict:insert(
_pipe@1,
chromium,
Chromium_config
)
end
)
end
)
end
).
-file("src/butterbee/config.gleam", 278).
?DOC(false).
-spec driver_config_decoder() -> gleam@dynamic@decode:decoder(driver_config()).
driver_config_decoder() ->
gleam@dynamic@decode:optional_field(
<<"max_wait_time"/utf8>>,
20000,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Max_wait_time) ->
gleam@dynamic@decode:optional_field(
<<"request_timeout"/utf8>>,
5000,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Request_timeout) ->
gleam@dynamic@decode:optional_field(
<<"data_dir"/utf8>>,
<<"/tmp/butterbee"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Data_dir) ->
gleam@dynamic@decode:success(
{driver_config,
Max_wait_time,
Request_timeout,
Data_dir}
)
end
)
end
)
end
).
-file("src/butterbee/config.gleam", 195).
-spec butterbee_config_decoder() -> gleam@dynamic@decode:decoder(butterbee_config()).
butterbee_config_decoder() ->
gleam@dynamic@decode:optional_field(
<<"driver"/utf8>>,
{driver_config, 20000, 5000, <<"/tmp/butterbee"/utf8>>},
driver_config_decoder(),
fun(Driver) ->
gleam@dynamic@decode:optional_field(
<<"capabilities"/utf8>>,
none,
gleam@dynamic@decode:optional(
butterbidi@session@types@capabilities_request:capabilities_request_decoder(
)
),
fun(Capabilities) ->
gleam@dynamic@decode:optional_field(
<<"browser"/utf8>>,
none,
gleam@dynamic@decode:optional(browser_config_decoder()),
fun(Browser_config) ->
gleam@dynamic@decode:success(
{butterbee_config,
Driver,
Capabilities,
Browser_config}
)
end
)
end
)
end
).
-file("src/butterbee/config.gleam", 231).
?DOC(false).
-spec parse_config_string(binary()) -> {ok, butterbee_config()} |
{error, error()}.
parse_config_string(Toml) ->
gleam@result:'try'(
begin
_pipe = tom:parse(Toml),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {parse_error, Field@0} end
)
end,
fun(Config) ->
Config@1 = butterbee@internal@lib:toml_to_dynamic({table, Config}),
Decoder = gleam@dynamic@decode:at(
[<<"tools"/utf8>>, <<"butterbee"/utf8>>],
butterbee_config_decoder()
),
gleam@result:'try'(
begin
_pipe@1 = gleam@dynamic@decode:run(Config@1, Decoder),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {decode_error, Field@0} end
)
end,
fun(Config@2) ->
_pipe@2 = palabres:debug(<<"Butterbee config"/utf8>>),
_pipe@3 = palabres:string(
_pipe@2,
<<"config"/utf8>>,
gleam@string:inspect(Config@2)
),
palabres:log(_pipe@3),
{ok, Config@2}
end
)
end
).
-file("src/butterbee/config.gleam", 222).
?DOC(false).
-spec parse_config(binary()) -> {ok, butterbee_config()} | {error, error()}.
parse_config(Path) ->
gleam@result:'try'(
begin
_pipe = simplifile:read(Path),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {read_error, Field@0} end
)
end,
fun(Path@1) -> parse_config_string(Path@1) end
).
-file("src/butterbee/config.gleam", 303).
?DOC(" Creates a default `CapabilitiesRequest` with only the `webSocketUrl` capability for `always_match`.\n").
-spec default_capabilities_config() -> butterbidi@session@types@capabilities_request:capabilities_request().
default_capabilities_config() ->
{capabilities_request,
{some,
begin
_record = butterbidi@session@types@capability_request:default(),
{capability_request,
erlang:element(2, _record),
erlang:element(3, _record),
erlang:element(4, _record),
erlang:element(5, _record),
begin
_pipe = maps:new(),
gleam@dict:insert(
_pipe,
<<"webSocketUrl"/utf8>>,
gleam_stdlib:identity(true)
)
end}
end},
none}.
-file("src/butterbee/config.gleam", 327).
?DOC(" Returns the default browser configuration\n").
-spec default_browser_config() -> gleam@dict:dict(browser_type(), browser_config()).
default_browser_config() ->
_pipe = maps:new(),
_pipe@1 = gleam@dict:insert(
_pipe,
firefox,
default_individual_browser_config(firefox)
),
gleam@dict:insert(
_pipe@1,
chromium,
default_individual_browser_config(chromium)
).
-file("src/butterbee/config.gleam", 339).
?DOC(false).
-spec browser_type_to_string(browser_type()) -> binary().
browser_type_to_string(Browser_type) ->
case Browser_type of
firefox ->
<<"firefox"/utf8>>;
chromium ->
<<"chromium"/utf8>>
end.
-file("src/butterbee/config.gleam", 350).
?DOC(false).
-spec browser_type_decoder() -> gleam@dynamic@decode:decoder(browser_type()).
browser_type_decoder() ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Browser_type) -> case Browser_type of
<<"firefox"/utf8>> ->
gleam@dynamic@decode:success(firefox);
<<"chromium"/utf8>> ->
gleam@dynamic@decode:success(chromium);
_ ->
_pipe = palabres:error(
<<"Browser type not supported"/utf8>>
),
_pipe@1 = palabres:string(
_pipe,
<<"browser_type"/utf8>>,
Browser_type
),
palabres:log(_pipe@1),
gleam@dynamic@decode:failure(
firefox,
<<"Browser type not supported"/utf8>>
)
end end
).
-file("src/butterbee/config.gleam", 399).
-spec with_start_url(browser_config(), binary()) -> browser_config().
with_start_url(Config, Start_url) ->
{browser_config,
Start_url,
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config)}.
-file("src/butterbee/config.gleam", 403).
-spec with_cmd(browser_config(), binary()) -> browser_config().
with_cmd(Config, Cmd) ->
{browser_config,
erlang:element(2, Config),
Cmd,
erlang:element(4, Config),
erlang:element(5, Config)}.
-file("src/butterbee/config.gleam", 407).
-spec with_extra_flags(browser_config(), list(binary())) -> browser_config().
with_extra_flags(Config, Extra_flags) ->
{browser_config,
erlang:element(2, Config),
erlang:element(3, Config),
Extra_flags,
erlang:element(5, Config)}.
-file("src/butterbee/config.gleam", 414).
-spec with_host(browser_config(), binary()) -> browser_config().
with_host(Config, Host) ->
{browser_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
Host}.