3
3
-behaviour (asteroid_handler ).
4
4
-behaviour (gen_server ).
5
5
6
- % % API
7
- -export ([start_link /0 ]).
6
+ % %public API
7
+ -export ([start_link /0 ,
8
+ login /1 ,
9
+ send_message /1 ]).
10
+
11
+ % % asteroid_handler callbacks
8
12
-export ([handle /2 , is_periodical /1 ]).
9
- -export ([login /1 , send_message /1 ]).
10
13
11
14
% % gen_server callbacks
12
15
-export ([init /1 ,
16
19
terminate /2 ,
17
20
code_change /3 ]).
18
21
19
- -record (state , {clients }).
20
-
21
22
22
- % %%===================================================================
23
- % %% public API
24
- % %%===================================================================
23
+ -record (state , {clients }).
24
+ -record (userinfo , {name , session , pid }).
25
25
26
26
start_link () ->
27
27
gen_server :start_link ({local , ? MODULE }, ? MODULE , [], []).
@@ -61,45 +61,38 @@ init([]) ->
61
61
62
62
handle_call ({login , Username }, {Pid , _Ref }, State ) ->
63
63
SessionRef = erlang :list_to_binary (erlang :ref_to_list (make_ref ())),
64
- Clients = State # state .clients ++ [{Username , SessionRef , Pid }],
65
- Mesage = erlang :iolist_to_binary ([<<" User " >>, Username , <<" login" >>]),
66
- self () ! {message , Mesage },
64
+ Clients = State # state .clients ++ [# userinfo {name = Username ,
65
+ session = SessionRef ,
66
+ pid = Pid }],
67
+ send_to_all (<<" CHAT SERVER" >>,
68
+ erlang :iolist_to_binary ([<<" User " >>,
69
+ Username ,
70
+ <<" login" >>]),
71
+ Clients ),
67
72
{reply , {session_ref , SessionRef }, State # state {clients = Clients }};
68
-
69
73
handle_call ({logout , SessionRef }, _From , State ) ->
70
- Clients = lists :filter (fun ({Username , UserSessionRef , _UserPid }) ->
71
- case SessionRef =/= UserSessionRef of
72
- true -> true ;
73
- false -> Message = erlang :iolist_to_binary ([<<" User " >>, Username , <<" logout" >>]),
74
- self () ! {message , Message },
75
- false
76
- end
77
- end ,
78
- State # state .clients ),
74
+ {ok , User } = userinfo_by_session (SessionRef , State # state .clients ),
75
+ Clients = State # state .clients -- [User ],
76
+ send_to_all (<<" CHAT SERVER" >>,
77
+ erlang :iolist_to_binary ([<<" User " >>,
78
+ User # userinfo .name ,
79
+ <<" logout" >>]),
80
+ Clients ),
79
81
{reply , ok , State # state {clients = Clients }};
80
- handle_call ({message , ClientSessionRef , ClientMessage }, _From , State ) ->
81
- case lists :filter (
82
- fun ({_Username , UserSessionRef , _UserPid }) -> UserSessionRef =:= ClientSessionRef end ,
83
- State # state .clients ) of
84
- [{ClientUsername , _SessionRef , _Pid }] ->
85
- lists :foreach (fun ({_Username , _UserSesionRef , UserPid }) ->
86
- UserPid ! {message , jsx :encode ([{<<" username" >>, ClientUsername },
87
- {<<" message" >>, ClientMessage }])}
88
- end ,
89
- State # state .clients ),
90
- {reply , ok , State };
91
- _ -> {reply , error , State }
92
- end .
82
+ handle_call ({message , SessionRef , Message }, _From , State ) ->
83
+ case userinfo_by_session (SessionRef , State # state .clients ) of
84
+ {ok , User } -> send_to_all (User # userinfo .name ,
85
+ Message ,
86
+ State # state .clients ),
87
+ {reply , ok , State };
88
+ {error , _ErrorInfo } ->
89
+ {reply , error , State }
90
+ end .
93
91
94
92
handle_cast (_Msg , State ) ->
95
93
{noreply , State }.
96
94
97
- handle_info ({message , MessageText }, State ) ->
98
- lists :foreach (fun ({_Username , _SessionRef , UserPid }) ->
99
- UserPid ! {message , jsx :encode ([{<<" username" >>, <<" CHAT SERVER" >>},
100
- {<<" message" >>, MessageText }])}
101
- end ,
102
- State # state .clients ),
95
+ handle_info (_Info , State ) ->
103
96
{noreply , State }.
104
97
105
98
terminate (_Reason , _State ) ->
@@ -111,3 +104,20 @@ code_change(_OldVsn, State, _Extra) ->
111
104
% %%===================================================================
112
105
% %% Internal functions
113
106
% %%===================================================================
107
+ send_to_all (UserName , MessageText , Clients ) ->
108
+ lists :foreach (fun (User ) ->
109
+ User # userinfo .pid ! {message ,
110
+ jsx :encode ([{<<" username" >>, UserName },
111
+ {<<" message" >>, MessageText }])}
112
+ end ,
113
+ Clients ).
114
+
115
+ userinfo_by_session (SessionRef , Clients ) ->
116
+ case lists :filter (
117
+ fun (User ) ->
118
+ User # userinfo .session =:= SessionRef
119
+ end ,
120
+ Clients ) of
121
+ [User ] -> {ok , User };
122
+ [] -> {error , not_found }
123
+ end .
0 commit comments