Erlang 聊天室程序(十一) 主题房间之Supervisor引起的改造
于由使用了Supervisor来管理当前所有的房间,每个房间都为单独的进程,所以要计对之前的chat_room.erl代码做相应的修改。
具体包括以下几点:
1.getPid/0 : 以前是由{local,?Module}房间进程来产生新的客户端进程。这次由于采用simple_one_to_one的启动方式,所以要重新指定客户端进程的产生方式(这里交由大厅来创建)
所以修改chat_room进程的创建方法,房间名由外部传入,再根据房间名为每个chat_room进程命名。
#roominfo{name=Name,type=Type}=Para,
gen_server:start_link({local,list_to_atom(Name)}, [Para],[]).
再修改echatServer.erl,启动supervisor后创建大厅子进程
%start supervisor
room_manager:start_link([]),
%add hall to supervisor
Para=#roominfo{name="room-hall",type="public"},
room_manager:startNewRoom(Para),
chat_acceptor:start(3377),
ok.
可以看到,这里为大厅指定的进程名为"room-hall",所以下面修改getPid/0
Id=id_generator:getnewid(client),
Pid=gen_server:call(list_to_existing_atom("room-hall"),{getpid,Id}),
io:format("id generated ~w~n",[Id]),
#clientinfo{id=Id,pid=Pid}
.
2. bindPid/2 : 这次就要指定客户端进程具体要添加到哪个房间中。 同时为了方便后面的操作,我们为chat_room.erl添加两个函数joinRoom/2 和 leaveRoom/2 让客户端通过这两个函数来进入和退出某个房间。
joinRoom(RoomName,ClientInfo) when is_list(RoomName)->
gen_server:call(list_to_existing_atom(RoomName), {add_clientinfo,ClientInfo})
;
joinRoom(Ref,ClientInfo)->
gen_server:call(Ref, {add_clientinfo,ClientInfo})
.
%leave Room,clean userinfo
leaveRoom(RoomName,ClientInfo) when is_list(RoomName)->
gen_server:call(list_to_existing_atom(RoomName), {remove_clientinfo,ClientInfo})
;
leaveRoom(Ref,ClientInfo)->
gen_server:call(Ref, {remove_clientinfo,ClientInfo})
.
在此基础上再修改bindPid/2 (第一次进入房间时默认为进入大厅)
io:format("binding socket...~n"),
case gen_tcp:controlling_process(Socket, Record#clientinfo.pid) of
{error,Reason}->
io:format("binding socket...error~n");
ok ->
NewRec =#clientinfo{id=Record#clientinfo.id,socket=Socket,pid=Record#clientinfo.pid},
%gen_server:call(list_to_existing_atom("room-hall"), {add_clientinfo,NewRec}),
joinRoom("room-hall",NewRec),
%then we send info to clientSession to update it's State (Socket info)
Pid=Record#clientinfo.pid,
Pid!{bind,Socket},
io:format("clientBinded~n")
end
.
3.setUserInfo/1 的改造。整个系统中,用户信息可以通过两个地方获取:1用户进程绑定的PID,它是一个gen_server,用户信息保存于State中。2用户信息存在用户所在房间的clientManager管理的ets表中。要更新用户信息,这两个地方就都要更新。
先修改chat_room.erl部分:
gen_server:call(list_to_existing_atom(RoomName), {set_clientinfo,Message})
;
setUserInfo(Ref,Message)->
gen_server:call(Ref, {set_clientinfo,Message})
.
再修改客户端部分,由于所有接受到的消息都是交由message_router路由的,所以修改message_router.erl中的代码:
Message消息需要在这里被解析为#clientinfo
#clientinfo{pid=From}=State,
case Type of
"msg"->
case Sub of
"chat"->
io:format("message_router:route to chat_room:broadcast:~p~n",[Message]),
chat_room:broadCastMsg(Message);
_Els->
io:format("unkonw msssage subject:~p~n",[Sub])
end;
"set"->
case Sub of
"clientinfo"->
#message{content=Info,from=Key}=Message,
Rec =util_SetInfoParas:paraElements(Info),
From!{setinfo,Rec},
chat_room:setUserInfo(Message);
4.broadCastMsg/1
broadCastMsg(RoomName,Msg) when is_list(RoomName)->
gen_server:call(list_to_existing_atom(RoomName), {sendmsg,Msg})
;
broadCastMsg(Ref,Msg)->
gen_server:call(Ref, {sendmsg,Msg})
.
5.getMembers/1
gen_server:call(list_to_existing_atom(RoomName), {get_member,Message})
;
getMembers(Ref,Message)->
gen_server:call(Ref, {get_member,Message})
.