Guest User

Untitled

a guest
Aug 8th, 2018
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Erlang 8.23 KB | None | 0 0
  1. -module(user_listener).
  2. -export([start/0, start/1, process_users/1]).
  3. -include("defs.hrl").
  4.  
  5. % ==============================================================================
  6. % Запуск сервиса обслуживания пользователей
  7. % @return error (в случае недоступности порта)
  8. % ==============================================================================
  9. start() ->
  10.     start(util:rpc(whereis(config), users_port)).
  11.  
  12. % ==============================================================================
  13. % Запуск сервиса обслуживания пользователей
  14. % @param Port Порт сервиса обслуживания пользователей
  15. % @return error (в случае недоступности порта)
  16. % ==============================================================================
  17. start(Port) ->
  18.     case gen_tcp:listen(Port, [binary, {packet, line}, {active, false}]) of
  19.         {ok, LSock} ->
  20.             io:format("*user_listener:server started~n"),
  21.             case whereis(users) of
  22.                 undefined ->
  23.                     register(users, spawn(?MODULE, process_users, [[]]));
  24.                 _ ->
  25.                     unregister(users),
  26.                     register(users, spawn(?MODULE, process_users, [[]]))
  27.             end,
  28.             loop(LSock);
  29.         _ ->
  30.             io:format("*user_listener:Can't bind to socket~n"),
  31.             error
  32.     end.
  33.  
  34. % ==============================================================================
  35. % Запуск сервиса обслуживания пользователей
  36. % @param Listen Хэндлер соединения
  37. % @return error (в случае недоступности порта)
  38. % ==============================================================================
  39. loop(Listen) ->
  40.     case gen_tcp:accept(Listen) of
  41.         {ok, Socket} ->
  42.             io:format("*user_listener:Accept connection~n"),
  43.             case gen_tcp:recv(Socket, 0) of
  44.                 {ok, Packet} ->
  45.                     util:rpc(whereis(user), {add, binary_to_list(Packet), Socket});
  46.                 {error, Reason} ->
  47.                     io:format("*user_listener:Recv error: ~p. Connection close.~n", [Reason])
  48.             end,
  49.             loop(Listen);
  50.         {error, Reason} ->
  51.             io:format("*user_listener:Error while accept connection: ~p~n", [Reason]),
  52.             loop(Listen)
  53.     end.
  54.  
  55. % ==============================================================================
  56. % Процесс обслуживания пользователей
  57. % @param Users Список пользователей
  58. % ==============================================================================
  59. process_users(Users) ->
  60.     receive
  61.         {Pid, Cmd} ->
  62.             case Cmd of
  63.                 {add, Name, Socket} ->      % добавить нового пользователя в список
  64.                     Users1 = add_user({Name, Socket}, Users),
  65.                     Pid ! {self(), ok},
  66.                     process_users(Users1);
  67.                 {remove, Name} ->           % удалить пользователя из списка
  68.                     Users1 = remove_user(Name, Users),
  69.                     Pid ! {self(), ok},
  70.                     process_users(Users1);
  71.                 {send, Names, Message} ->   % Отправить сообщение выбранным пользователям
  72.                     Replies = send_message(Names, Message, Users),
  73.                     Users1 = remove_broken_users(Users, lists:zip(Names, Replies)),
  74.                     Pid ! {self(), Replies},
  75.                     process_users(Users1);
  76.                 {list_all} ->               % Получение списка пользователей / Пинг активных
  77.                     Names = proplists:get_keys(Users),
  78.                     Replies = send_message(Names, ?PING_COMMAND, Users),
  79.                     Users1 = remove_broken_users(Users, lists:zip(Names, Replies)),
  80.                     Pid ! {self(), proplists:get_keys(Users1)},
  81.                     process_users(Users1)
  82.             end
  83.     end.
  84.  
  85. % ==============================================================================
  86. % Удаление из списка пользователей тех, у кого зафиксированы ошибки ввода/вывода
  87. % @param Users Список пользователей
  88. % ==============================================================================
  89. remove_broken_users(Users, []) ->
  90.     Users;
  91. remove_broken_users(Users, [H|T]) ->
  92.     {User, State} = H,
  93.     case State of
  94.         ?E_IO ->
  95.             case proplists:get_value(User, Users) of
  96.                 undefined ->
  97.                     true;
  98.                 Socket ->
  99.                     gen_tcp:close(Socket)
  100.             end,
  101.             Users1 = proplists:delete(User, Users),
  102.             remove_broken_users(Users1, T);
  103.         _ ->
  104.             remove_broken_users(Users, T)
  105.     end.
  106.  
  107.  
  108. % ==============================================================================
  109. % Добавление нового подключенного клиента
  110. % @param NewUser Новый пользователь
  111. % @param Users Сипсок имеющихся пользователей
  112. % @return Новый список пользователей
  113. % ==============================================================================
  114. add_user(NewUser, Users) ->
  115.     case proplists:lookup(NewUser, Users) of
  116.         none ->
  117.             [NewUser | Users];
  118.         {OldUser, OldSocket} ->
  119.             gen_tcp:close(OldSocket),
  120.             [NewUser | proplists:delete(OldUser, Users)]
  121.     end.
  122.  
  123. % ==============================================================================
  124. % Удаление подключенного клиента из списка
  125. % @param NewUser Новый пользователь
  126. % @param Users Сипсок имеющихся пользователей
  127. % @return Новый список пользователей
  128. % ==============================================================================
  129. remove_user(UserToRemove, Users) ->
  130.     case proplists:lookup(UserToRemove, Users) of
  131.         none ->
  132.             Users;
  133.         {OldUser, OldSocket} ->
  134.             gen_tcp:close(OldSocket),
  135.             proplists:delete(OldUser, Users)
  136.     end.
  137.  
  138. % ==============================================================================
  139. % Рассылка сообщения указанным пользователям
  140. % @param Names Имена пользователей для отправки
  141. % @param Message Сообщение для отправки пользователю
  142. % @param Users Список активных пользователей
  143. % @return Новый список с ответами на посланное сообщение или кодами ошибок
  144. % ==============================================================================
  145. send_message(Names, Message, Users) ->
  146.     [ send_message0(Name, Message, Users) || Name <- Names].
  147.  
  148. % ==============================================================================
  149. % Отправка сообщения конкретному пользователю
  150. % @param Name Имя пользователей для отправки
  151. % @param Message Сообщение для отправки пользователю
  152. % @param Users Список активных пользователей
  153. % @return Ответ пользователя
  154. % ==============================================================================
  155. send_message0(Name, Message, Users) ->
  156.     Socket = proplists:get_value(Name, Users),
  157.     case Socket of
  158.         undefined ->
  159.             ?E_NOTEXIST;
  160.         _ ->
  161.             case gen_tcp:send(Socket, list_to_binary(lists:append([Message, [$\n]]))) of
  162.                 ok ->
  163.                     case gen_tcp:recv(Socket, 0, ?CLIENT_REPLY_TIMEOUT) of
  164.                         {ok, Packet} ->
  165.                             binary_to_list(Packet);
  166.                         {error, _Reason} ->
  167.                             ?E_IO
  168.                     end;
  169.                 {error, _Reason} ->
  170.                     ?E_IO
  171.             end
  172.     end.
Add Comment
Please, Sign In to add comment