Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -module(user_listener).
- -export([start/0, start/1, process_users/1]).
- -include("defs.hrl").
- % ==============================================================================
- % Запуск сервиса обслуживания пользователей
- % @return error (в случае недоступности порта)
- % ==============================================================================
- start() ->
- start(util:rpc(whereis(config), users_port)).
- % ==============================================================================
- % Запуск сервиса обслуживания пользователей
- % @param Port Порт сервиса обслуживания пользователей
- % @return error (в случае недоступности порта)
- % ==============================================================================
- start(Port) ->
- case gen_tcp:listen(Port, [binary, {packet, line}, {active, false}]) of
- {ok, LSock} ->
- io:format("*user_listener:server started~n"),
- case whereis(users) of
- undefined ->
- register(users, spawn(?MODULE, process_users, [[]]));
- _ ->
- unregister(users),
- register(users, spawn(?MODULE, process_users, [[]]))
- end,
- loop(LSock);
- _ ->
- io:format("*user_listener:Can't bind to socket~n"),
- error
- end.
- % ==============================================================================
- % Запуск сервиса обслуживания пользователей
- % @param Listen Хэндлер соединения
- % @return error (в случае недоступности порта)
- % ==============================================================================
- loop(Listen) ->
- case gen_tcp:accept(Listen) of
- {ok, Socket} ->
- io:format("*user_listener:Accept connection~n"),
- case gen_tcp:recv(Socket, 0) of
- {ok, Packet} ->
- util:rpc(whereis(user), {add, binary_to_list(Packet), Socket});
- {error, Reason} ->
- io:format("*user_listener:Recv error: ~p. Connection close.~n", [Reason])
- end,
- loop(Listen);
- {error, Reason} ->
- io:format("*user_listener:Error while accept connection: ~p~n", [Reason]),
- loop(Listen)
- end.
- % ==============================================================================
- % Процесс обслуживания пользователей
- % @param Users Список пользователей
- % ==============================================================================
- process_users(Users) ->
- receive
- {Pid, Cmd} ->
- case Cmd of
- {add, Name, Socket} -> % добавить нового пользователя в список
- Users1 = add_user({Name, Socket}, Users),
- Pid ! {self(), ok},
- process_users(Users1);
- {remove, Name} -> % удалить пользователя из списка
- Users1 = remove_user(Name, Users),
- Pid ! {self(), ok},
- process_users(Users1);
- {send, Names, Message} -> % Отправить сообщение выбранным пользователям
- Replies = send_message(Names, Message, Users),
- Users1 = remove_broken_users(Users, lists:zip(Names, Replies)),
- Pid ! {self(), Replies},
- process_users(Users1);
- {list_all} -> % Получение списка пользователей / Пинг активных
- Names = proplists:get_keys(Users),
- Replies = send_message(Names, ?PING_COMMAND, Users),
- Users1 = remove_broken_users(Users, lists:zip(Names, Replies)),
- Pid ! {self(), proplists:get_keys(Users1)},
- process_users(Users1)
- end
- end.
- % ==============================================================================
- % Удаление из списка пользователей тех, у кого зафиксированы ошибки ввода/вывода
- % @param Users Список пользователей
- % ==============================================================================
- remove_broken_users(Users, []) ->
- Users;
- remove_broken_users(Users, [H|T]) ->
- {User, State} = H,
- case State of
- ?E_IO ->
- case proplists:get_value(User, Users) of
- undefined ->
- true;
- Socket ->
- gen_tcp:close(Socket)
- end,
- Users1 = proplists:delete(User, Users),
- remove_broken_users(Users1, T);
- _ ->
- remove_broken_users(Users, T)
- end.
- % ==============================================================================
- % Добавление нового подключенного клиента
- % @param NewUser Новый пользователь
- % @param Users Сипсок имеющихся пользователей
- % @return Новый список пользователей
- % ==============================================================================
- add_user(NewUser, Users) ->
- case proplists:lookup(NewUser, Users) of
- none ->
- [NewUser | Users];
- {OldUser, OldSocket} ->
- gen_tcp:close(OldSocket),
- [NewUser | proplists:delete(OldUser, Users)]
- end.
- % ==============================================================================
- % Удаление подключенного клиента из списка
- % @param NewUser Новый пользователь
- % @param Users Сипсок имеющихся пользователей
- % @return Новый список пользователей
- % ==============================================================================
- remove_user(UserToRemove, Users) ->
- case proplists:lookup(UserToRemove, Users) of
- none ->
- Users;
- {OldUser, OldSocket} ->
- gen_tcp:close(OldSocket),
- proplists:delete(OldUser, Users)
- end.
- % ==============================================================================
- % Рассылка сообщения указанным пользователям
- % @param Names Имена пользователей для отправки
- % @param Message Сообщение для отправки пользователю
- % @param Users Список активных пользователей
- % @return Новый список с ответами на посланное сообщение или кодами ошибок
- % ==============================================================================
- send_message(Names, Message, Users) ->
- [ send_message0(Name, Message, Users) || Name <- Names].
- % ==============================================================================
- % Отправка сообщения конкретному пользователю
- % @param Name Имя пользователей для отправки
- % @param Message Сообщение для отправки пользователю
- % @param Users Список активных пользователей
- % @return Ответ пользователя
- % ==============================================================================
- send_message0(Name, Message, Users) ->
- Socket = proplists:get_value(Name, Users),
- case Socket of
- undefined ->
- ?E_NOTEXIST;
- _ ->
- case gen_tcp:send(Socket, list_to_binary(lists:append([Message, [$\n]]))) of
- ok ->
- case gen_tcp:recv(Socket, 0, ?CLIENT_REPLY_TIMEOUT) of
- {ok, Packet} ->
- binary_to_list(Packet);
- {error, _Reason} ->
- ?E_IO
- end;
- {error, _Reason} ->
- ?E_IO
- end
- end.
Add Comment
Please, Sign In to add comment