Реализовать модуль регистрации ботов #19

This commit is contained in:
2026-05-05 16:55:35 +03:00
parent b85885ce83
commit 11971ebb06
4 changed files with 146 additions and 1 deletions

View File

@@ -307,6 +307,21 @@ docker-swarm-reg-admin:
docker-swarm-check-admin:
@docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub eval 'eventhub_auth:authenticate_admin_request(<<"">>,<<"admin@eventhub.local">>,<<"123456">>).'
docker-swarm-reg-bots:
@docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub eval "os:putenv(\"BOT_COUNT\", \"3000\"), bot_controller:register()."
docker-swarm-reg-bots-stop:
@docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub eval 'bot_controller:stop().'
docker-swarm-delete-bots:
@docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub eval 'bot_controller:delete().'
docker-swarm-count-bots:
@for id in $$(docker ps -qf "name=eventhub_eventhub"); do \
echo "=== $$id ==="; \
docker exec $$id /app/bin/eventhub eval 'bot_controller:count_bots().'; \
done
docker-swarm-shell:
@docker exec $$(docker ps -qf "name=eventhub_eventhub" | head -n 1) /app/bin/eventhub remote_console

View File

@@ -7,6 +7,7 @@
-export([list_users/0]).
-export([block/2, unblock/2]).
-export([count_users/0, count_users_by_date/2]).
-export([create_bot/2, delete_bot/1]).
%% Создание пользователя
create(Email, Password) ->
@@ -171,3 +172,43 @@ set_field(password_hash, Value, U) -> U#user{password_hash = Value};
set_field(role, Value, U) when Value =:= user; Value =:= admin -> U#user{role = Value};
set_field(status, Value, U) when Value =:= active; Value =:= frozen; Value =:= deleted -> U#user{status = Value};
set_field(_, _, U) -> U.
%% ------------------------------------------------------------------
%% API для ботов
%% ------------------------------------------------------------------
-spec create_bot(Email :: binary(), Password :: binary()) ->
{ok, User :: #user{}} | {error, duplicate_email | invalid_email}.
create_bot(Email, Password) ->
case email_exists(Email) of
true ->
{error, email_exists};
false ->
case mnesia:dirty_index_read(user, Email, email) of
[] ->
{ok, PasswordHash} = logic_auth:hash_password(Password),
Id = generate_id(),
User = #user{
id = Id,
email = Email,
password_hash = PasswordHash,
role = bot,
status = active,
created_at = calendar:universal_time(),
updated_at = calendar:universal_time()
},
ok = mnesia:dirty_write(User),
{ok, User};
_ ->
{error, duplicate_email}
end
end.
-spec delete_bot(Id :: binary()) -> ok | {error, not_found}.
delete_bot(Id) ->
case mnesia:dirty_read({user, Id}) of
[#user{role = bot}] ->
mnesia:dirty_delete({user, Id}),
ok;
[] -> {error, not_found}
end.

View File

@@ -0,0 +1,88 @@
-module(bot_controller).
-include("records.hrl").
-export([register/0, stop/0, delete/0, count_bots/0]).
-define(REG_NAME, {bot_registration, node()}).
%% ------------------------------------------------------------------
%% @doc Асинхронно регистрирует ботов (одновременно только один процесс).
%% Возвращает pid процесса или ошибку.
%% ------------------------------------------------------------------
register() ->
Count = list_to_integer(os:getenv("BOT_COUNT", "0")),
Domain = list_to_binary(os:getenv("BOT_DOMAIN", "eventhub.com")),
Password = list_to_binary(os:getenv("BOT_DEFAULT_PASSWORD", "botpass123")),
if Count =< 0 ->
{error, <<"BOT_COUNT must be greater than 0">>};
true ->
io:format("Starting async registration of ~p bots with domain ~s...~n", [Count, Domain]),
Pid = spawn(fun() ->
register_bots(Count, Domain, Password)
end),
case global:register_name(?REG_NAME, Pid) of
yes ->
{ok, Pid};
no ->
% Уже есть активный процесс регистрации
exit(Pid, kill),
{error, registration_already_running}
end
end.
%% ------------------------------------------------------------------
%% @doc Останавливает текущий процесс регистрации.
%% ------------------------------------------------------------------
stop() ->
case global:whereis_name(?REG_NAME) of
undefined ->
io:format("No active bot registration found.~n");
Pid ->
exit(Pid, kill),
io:format("Bot registration process ~p stopped.~n", [Pid])
end.
%% ------------------------------------------------------------------
%% @doc Удаляет всех пользователей с ролью bot.
%% ------------------------------------------------------------------
delete() ->
Bots = mnesia:dirty_match_object(#user{role = bot, _ = '_'}),
lists:foreach(fun(#user{id = Id}) ->
mnesia:dirty_delete({user, Id})
end, Bots),
io:format("Deleted ~p bots.~n", [length(Bots)]),
ok.
%% ------------------------------------------------------------------
%% @doc Возвращает количество ботов в базе.
%% ------------------------------------------------------------------
count_bots() ->
length(mnesia:dirty_match_object(#user{role = bot, _ = '_'})).
%% ------------------------------------------------------------------
%% Внутренние функции
%% ------------------------------------------------------------------
register_bots(Count, Domain, Password) ->
register_bots(Count, Domain, Password, []).
register_bots(0, _, _, Acc) ->
io:format("Async registration completed. Created ~p bots.~n", [length(Acc)]),
global:unregister_name(?REG_NAME);
register_bots(N, Domain, Password, Acc) ->
Email = generate_email(Domain),
case core_user:create_bot(Email, Password) of
{ok, _User} ->
register_bots(N-1, Domain, Password, [Email | Acc]);
{error, duplicate_email} ->
register_bots(N, Domain, Password, Acc);
{error, _} ->
register_bots(N-1, Domain, Password, Acc)
end.
generate_email(Domain) ->
Name = random_string(8),
<<"bot_", Name/binary, "@", Domain/binary>>.
random_string(Length) ->
Chars = <<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789">>,
list_to_binary([lists:nth(rand:uniform(byte_size(Chars)), binary_to_list(Chars)) || _ <- lists:seq(1, Length)]).

View File

@@ -242,6 +242,7 @@ create_indices() ->
mnesia:add_table_index(calendar_specialist, calendar_id),
mnesia:add_table_index(calendar_specialist, user_id),
mnesia:add_table_index(user, nickname),
mnesia:add_table_index(user, email),
mnesia:add_table_index(notification, user_id),
mnesia:add_table_index(notification, is_read),
ok.