ekfa/apps/docker/src/docker_helper.erl
2026-05-11 23:21:19 +08:00

103 lines
4.3 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @author anlicheng
%%% @copyright (C) 2025, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 17. 9月 2025 14:50
%%%-------------------------------------------------------------------
-module(docker_helper).
-author("anlicheng").
%% API
-export([root_dir/0]).
-export([ensure_container_dir/2, ensure_container_dir/3, get_container_dir/2, get_config_file/1]).
-export([update_container_config/2]).
-spec root_dir() -> {ok, string()} | undefined.
root_dir() ->
case application:get_env(docker, root_dir) of
{ok, RootDir} ->
{ok, RootDir};
undefined ->
application:get_env(efka, root_dir)
end.
-spec ensure_container_dir(RootDir :: string(), ContainerName :: binary()) -> {ok, ServerRootDir :: string()}.
ensure_container_dir(RootDir, ContainerName) when is_list(RootDir), is_binary(ContainerName) ->
ensure_container_dir(RootDir, ContainerName, <<>>).
-spec ensure_container_dir(RootDir :: string(), ContainerName :: binary(), ContainerDir :: binary()) ->
{ok, ServerRootDir :: string()}.
ensure_container_dir(RootDir, ContainerName, ContainerDir) when is_list(RootDir), is_binary(ContainerName), is_binary(ContainerDir) ->
PointerDir = default_container_dir(RootDir, ContainerName),
PointerFile = container_dir_pointer_file(PointerDir),
ActualContainerDir = resolve_container_dir(RootDir, ContainerName, ContainerDir),
ok = filelib:ensure_dir(PointerDir),
ok = filelib:ensure_dir(ActualContainerDir),
ok = file:write_file(PointerFile, unicode:characters_to_binary(ActualContainerDir), [write]),
{ok, ActualContainerDir}.
-spec get_config_file(ContainerDir :: string()) -> ConfigFile :: string().
get_config_file(ContainerDir) when is_list(ContainerDir) ->
%% 根目录
ContainerDir ++ "service.conf".
-spec get_container_dir(RootDir :: string(), ContainerName :: binary()) -> {ok, ServerRootDir :: string()} | error.
get_container_dir(RootDir, ContainerName) when is_list(RootDir), is_binary(ContainerName) ->
ContainerRootDir = default_container_dir(RootDir, ContainerName),
PointerFile = container_dir_pointer_file(ContainerRootDir),
ResolvedContainerDir = case file:read_file(PointerFile) of
{ok, ActualContainerDirBin} ->
normalize_container_dir(binary_to_list(ActualContainerDirBin));
{error, _} ->
ContainerRootDir
end,
case filelib:is_dir(ResolvedContainerDir) of
true ->
{ok, ResolvedContainerDir};
false ->
error
end.
-spec update_container_config(binary(), binary()) -> ok | {error, binary()}.
update_container_config(ContainerName, Config) when is_binary(ContainerName), is_binary(Config) ->
{ok, RootDir} = root_dir(),
case get_container_dir(RootDir, ContainerName) of
{ok, ContainerDir} ->
ConfigFile = get_config_file(ContainerDir),
case file:write_file(ConfigFile, Config, [write, binary]) of
ok ->
logger:warning("[efka_iot_client] write config file: ~p success", [ConfigFile]),
ok;
{error, Reason} ->
logger:warning("[efka_iot_client] write config file: ~p, get error: ~p", [ConfigFile, Reason]),
{error, <<"write config failed">>}
end;
error ->
{error, <<"error">>}
end.
-spec default_container_dir(RootDir :: string(), ContainerName :: binary()) -> string().
default_container_dir(RootDir, ContainerName) ->
normalize_container_dir(RootDir ++ "/" ++ binary_to_list(ContainerName)).
-spec container_dir_pointer_file(ContainerDir :: string()) -> string().
container_dir_pointer_file(ContainerDir) ->
ContainerDir ++ ".container_dir".
-spec resolve_container_dir(RootDir :: string(), ContainerName :: binary(), ContainerDir :: binary()) -> string().
resolve_container_dir(RootDir, ContainerName, <<>>) ->
default_container_dir(RootDir, ContainerName);
resolve_container_dir(_RootDir, _ContainerName, ContainerDir) ->
normalize_container_dir(binary_to_list(ContainerDir)).
-spec normalize_container_dir(ContainerDir :: string()) -> string().
normalize_container_dir(ContainerDir) ->
case lists:last(ContainerDir) of
$/ ->
ContainerDir;
_ ->
ContainerDir ++ "/"
end.