-module(testcontainer@network). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/testcontainer/network.gleam"). -export([create/1, remove/1, with_network/2, name/1, id/1]). -export_type([network/0, guard_event/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. -opaque network() :: {network, binary(), binary()}. -type guard_event() :: guard_stop | parent_down. -file("src/testcontainer/network.gleam", 14). ?DOC(" Creates a new bridge network with the given name.\n"). -spec create(binary()) -> {ok, network()} | {error, testcontainer@error:error()}. create(Name) -> gleam@result:'try'( testcontainer@internal@docker:create_network(Name), fun(Id) -> {ok, {network, Id, Name}} end ). -file("src/testcontainer/network.gleam", 20). ?DOC(" Removes a network created via `create/1`.\n"). -spec remove(network()) -> {ok, nil} | {error, testcontainer@error:error()}. remove(Network) -> testcontainer@internal@docker:remove_network(erlang:element(2, Network)). -file("src/testcontainer/network.gleam", 91). -spec guard_loop(binary(), gleam@erlang@process:subject(guard_event())) -> nil. guard_loop(Id, Subject) -> Selector = begin _pipe = gleam_erlang_ffi:new_selector(), _pipe@1 = gleam@erlang@process:select(_pipe, Subject), gleam@erlang@process:select_trapped_exits( _pipe@1, fun(_) -> parent_down end ) end, case gleam_erlang_ffi:select(Selector) of guard_stop -> nil; parent_down -> proc_lib:spawn_link( fun() -> _ = testcontainer@internal@docker:remove_network(Id), nil end ), nil end. -file("src/testcontainer/network.gleam", 68). -spec create_guarded(binary()) -> {ok, {network(), gleam@erlang@process:subject(guard_event())}} | {error, testcontainer@error:error()}. create_guarded(Name) -> Startup_subject = gleam@erlang@process:new_subject(), proc_lib:spawn_link( fun() -> gleam_erlang_ffi:trap_exits(true), Guard = gleam@erlang@process:new_subject(), case create(Name) of {ok, Net} -> gleam@erlang@process:send( Startup_subject, {ok, {Net, Guard}} ), guard_loop(erlang:element(2, Net), Guard); {error, E} -> gleam@erlang@process:send(Startup_subject, {error, E}) end end ), Selector = begin _pipe = gleam_erlang_ffi:new_selector(), gleam@erlang@process:select(_pipe, Startup_subject) end, gleam_erlang_ffi:select(Selector). -file("src/testcontainer/network.gleam", 30). ?DOC( " Creates a network, runs `body/1`, then removes it. Cleanup runs even if\n" " `body/1` returns an error or the caller process crashes (a linked guard\n" " process performs the removal asynchronously on caller down).\n" "\n" " use net <- network.with_network(\"test-net\")\n" ). -spec with_network( binary(), fun((network()) -> {ok, GZG} | {error, testcontainer@error:error()}) ) -> {ok, GZG} | {error, testcontainer@error:error()}. with_network(Name, Body) -> gleam@result:'try'( create_guarded(Name), fun(_use0) -> {Net, Guard} = _use0, Body_result = Body(Net), gleam@erlang@process:send(Guard, guard_stop), Remove_result = remove(Net), case {Body_result, Remove_result} of {{ok, _}, {error, Rm_e}} -> {error, Rm_e}; {_, _} -> Body_result end end ). -file("src/testcontainer/network.gleam", 45). ?DOC(" The network's name (as passed to `create/1`).\n"). -spec name(network()) -> binary(). name(Network) -> erlang:element(3, Network). -file("src/testcontainer/network.gleam", 50). ?DOC(" The Docker-assigned network id.\n"). -spec id(network()) -> binary(). id(Network) -> erlang:element(2, Network).