The previously implemented function is equivalent to a hall. Here we are for this chat roomProgramAdd the topic room function ". After logging on to the client, the client is in the lobby, obtains all the current theme rooms, and sends a message to enter a room. Members in the same room are visible, and messages sent are only visible to the room.
To manage these rooms, the monitoring tree in Erlang OPT is the most suitable.
Create a module room_manager.erl whose behavior complies with gen_supervisor. The sub-process is chat_room.
Init (para)-> <br/> {OK, <br/>{< br/> {one_for_one, 3,5}, <br/> [<br/> {the_room, <br/> {chat_room, start_link, []}, <br/> permanent, <br/> 10000, <br/> worker <br/>}< br/>] <br/>}< br/>. <br/>
Add another method to start this supervisor.
Start_link (para)-> <br/> Supervisor: start_link ({local ,? Module },? Module, [para]) <br/>.
If you start this module directly now, there is no problem, but since it is a theme room, there must be more than one. Next we will add the topic room function for this Supervisor:Startnewroom (para)-> <br/> Supervisor: start_child (the_room, [para]) <br/>.Is that simple? Certainly not. Consider the following:
1. How to identify the information of each room, such as name, type, number, start time, and current number of users.
2. How to maintain the online user information of each room.
3. How to maintain the currently available topic room information.
4. How to enter the room from the lobby.
5. How to exit from the room to the lobby.
6. How to route information to your room.
The solution is as follows:
Room ID:
AboveCodeThe para parameter is input when the topic room is started. You can use this parameter to initialize any room information you need. PS: This is one of the benefits of Erlang.
Modify chat_room.erl
Start_link (para)-> <br/> gen_server: start_link (? Module, [para], []).
Define a record named roominfo
-Record (roominfo, {ID, name, type, unum, creationdate }).
Initialize room information with input parameters
Init ([para])-> <br/> id_generator: start_link (), <br/> % ETS: New (clientinfo, [public, <br/> % ordered_set, <br/> % named_table, <br/> % {keypos, # clientinfo. id} <br/> %]), <br/> client_manager: Init (), <br/> roomid = id_generator: getnewid ("room "), <br/> case is_record (para, roominfo) of <br/> true-> <br/> {OK, # roominfo {unum = 0} = para }; <br/> Els-> <br/> % Maybe we shocould throw exception here <br/> {OK, # roominfo {id = roomid, unum = 0, name = "room" ++ integer_to_list (roomid), type = "def" }}< br/> end <br/>.
Maintenance of online member information for each room:
Do you still remember the client_manager module? This module is used to manage the online members of a room. You need to modify it here.
In the previous code, the client_manager module is called in the same process as chat_room, that is, sequential call.
The table to be manipulated is written to death during each call. Here, it needs to be changed to dynamic. the table to be manipulated is input during each operation.
Therefore, you should save your own table name in chat_room.
Modify the roominfo definition and add tablename, which is generated when chat_room is initialized.
-Record (roominfo, {ID, name, type, unum, tablename, creationdate }).Init ([para])-> <br/> id_generator: start_link (), <br/> % ETS: New (clientinfo, [public, <br/> % ordered_set, <br/> % named_table, <br/> % {keypos, # clientinfo. id} <br/> %]), <br/> roomid = id_generator: getnewid ("room"), <br/> clienttablename = list_to_atom (? Prifix ++ integer_to_list (roomid), <br/> client_manager: Init (clienttablename), <br/> case is_record (para, roominfo) of <br/> true-> <br/> {OK, # roominfo {unum = 0} = para}; <br/> Els-> <br/> {OK, # roominfo {id = roomid, unum = 0, name = "room" ++ integer_to_list (roomid), type = "def" }}< br/> end <br/>.
Modify client_manger.erl to add the table parameter for each method.
% Author: Administrator <br/> % created: 2012-2-28 <br/> % Description: Todo: Response for managing clientinfo <br/>-module (client_manager ). </P> <p> % <br/> % include files <br/> % <br/>-include ("clientinfo. HRL "). <br/>-include ("message. HRL "). <br/> % exported functions <br/> % <br/>-Export ([init/1, addclient/2, updateclient/2, getnextclient/2, removeclient/2, getclient/2, getnick/2]). </P> <p> % <B R/> % API functions <br/> % </P> <p> % create clientinfo talbe here <br/> Init (Tab) -> <br/> ETS: New (tab, [public, <br/> ordered_set, <br/> named_table, <br/> {keypos, # clientinfo. id} <br/>]) <br/>. </P> <p> % <br/> % local functions <br/> % </P> <p> % add new clientinfo <br/> addclient (tab, clientinfo)-> <br/> ETS: insert (tab, clientinfo) <br/>. </P> <p> % update clientinfo <br/> updateclient (tab, message)-> <br/> # Messa GE {content = info, from = key} = message, <br/> IO: Format ("content of message is :~ P ~ N ", [info]), <br/> % todo: We shocould formart content from JSON to record # clientinfo <br/> rec = util_setinfoparas: paraelements (Info ), <br/> IO: Format ("parased record is :~ P ~ N ", [Rec]), <br/> If is_record (REC, clientinfo)-> <br/> # clientinfo {Nick = Nick, sex = sex, age = age, province = province, <br/> city = city, posx = px, Posy = py} = rec, <br/> IO: Format ("Here key is :~ P ~ N ", [Key]), <br/> case ETS: update_element (tab, key, [{# clientinfo. nick, Nick}, <br/>{# clientinfo. sex, sex },< br/>{# clientinfo. age, age },< br/>{# clientinfo. province, Province}, <br/>{# clientinfo. city, city },< br/>{# clientinfo. posx, PX },< br/>{# clientinfo. posy, Py}]) of <br/> true-> <br/> {OK, REC}; <br/> false-> <br/> {FALs, REC} <br/> end; <br/> true-> <br/> IO: Format ("wrong format of clientinfo"), <br/> {Fals E, REC} <br/> end <br/>. </P> <p> % remove clientinfo <br/> removeclient (tab, key)-> <br/> [thekey] = key, <br/> case ETS: lookup (tab, thekey) of <br/> [Record]-> <br/> IO: Format ("record tobe Delete from clientinfo is :~ P ~ N ", [Record]); <br/> []-> <br/> IO: Format (" no record found tobe Delete from clientinfo ~ N ") <br/> end, <br/> IO: Format (" delete clientinfo from Table key is :~ P ~ N ", [thekey]), <br/> ETS: delete (tab, thekey) <br/>. </P> <p> getnick (tab, key)-> <br/> case ETS: Lookup (tab, key) of <br/> [Record]-> <br/> # clientinfo {Nick = Nick} = record, <br/> case Nick of <br/> undefined-> <br/> "client" ++ integer_to_list (key ); <br/> nick-> <br/> Nick <br/> end; <br/> []-> <br/> "client" ++ integer_to_list (key) <br/> end <br/>. </P> <p> getclient (tab, key)-> <br/> ETS: Lookup (tab, key) <br/>. </P> <p> get Nextclient (tab, [Key])-> <br/> case ETS: Next (tab, key) of <br/> '$ end_of_table'-> <br/> IO: format ("getnext1, no key found ~ N "), <br/> []; <br/> next-> <br/> IO: Format (" getnext1, key found ~ P ~ N ", [Key]), <br/> ETS: Lookup (tab, next) <br/> end <br/>; <br/> getnextclient (tab, [])-> <br/> case ETS: First (Tab) of <br/> '$ end_of_table'-> <br/> IO: Format ("getnext, no key found ~ N "), <br/> []; <br/> key-> <br/> IO: Format (" getnext, key found ~ P ~ N ", [Key]), <br/> ETS: Lookup (tab, key) <br/> end <br/>. </P> <p>
Modify the call section in chat_room.erl to add the table parameter for each call.
Handle_call ({remove_clientinfo, ref}, from, state)-> <br/> key = ref # clientinfo. ID, <br/> # roominfo {tablename = TABLE} = state, <br/> client_manager: removeclient (table, Key), <br/> {reply, OK, state} <br/>; <br/> handle_call ({sendmsg, MSG}, from, state)-> <br/> % key = ETS: First (clientinfo ), <br/> % IO: Format ("feching talbe key is ~ P ~ N ", [Key]), <br/> % sendmsg (Key, MSG), <br/> # roominfo {tablename = TABLE} = state, <br/> sendmsg (table, MSG, []), <br/> {reply, OK, State} <br/>; <br/> handle_call ({get_member, MSG}, from, state)-> <br/> # message {content = content} = MSG, <br/> # roominfo {tablename = TABLE} = state, <br/> case binary_to_list (content) of <br/> "all"-> <br/> List = getclient (table, [], []), <br/> # message {from = ID} = MSG, <br/> thefrom = client_manage R: getnick (table, ID), <br/> message = MSG # message {type = "result", from = thefrom, subject = "clientinfo", content = List }, <br/> {pid, _ }= from, <br/> PID! {Get_member, message };< br/> _ Els-> <br/> OK <br/> end, <br/> {reply, OK, state} <br/>; <br/> handle_call ({add_clientinfo, clientinfo}, from, state) -> <br/> % store clientinfo to ETS <br/> % ETS: insert (clientinfo, newrec) <br/> # roominfo {tablename = TABLE} = state, <br/> client_manager: addclient (table, clientinfo), <br/> {reply, OK, State} <br/>; <br/> handle_call ({set_clientinfo, message}, from, state)-> <br/> % We c An send result message to client <br/> % or send a broadcast message to all client <br/> # message {from = ID} = message, <br/> # roominfo {tablename = TABLE} = state, <br/> [client] = client_manager: getclient (table, ID ), <br/> # clientinfo {pid = PID} = client, <br/> thenick = client_manager: getnick (table, ID), <br/> case client_manager: updateclient (table, message) of <br/> {OK, REC}-> <br/> # clientinfo {Nick = Nick} = rec, <B R/> PID! {Setinfo, REC },< br/> {content }={ thenick ++ "has change nickname:" ++ Nick }, <br/> newmessage = # message {id = "0", <br/> from = ID, <br/> to = "", <br/> content = content, <br/> type = "MSG", <br/> subject = "chat", <br/> time = message # message. time },< br/> IO: Format ("notice message is :~ P ~ N ", [newmessage]), <br/> sendmsg (table, newmessage, []); <br/> {false, REC}-> <br/> OK <br/> end, <br/> {reply, OK, State} <br/>. </P> <p> sendmsg (table, MSG, key)-> <br/> IO: Format ("broading casting MSG ~ P ~ N ", [Key]), <br/> case client_manager: getnextclient (table, key) of <br/> [Record]-> <br/> next = record # clientinfo. ID, <br/> pid = record # clientinfo. PID, <br/> PID! {Dwmsg, MSG}, <br/> sendmsg (table, MSG, [next]); <br/> []-> <br/> OK <br/> end <br/>. </P> <p> getclient (table, key, ulist)-> <br/> case client_manager: getnextclient (key) of <br/> [Record]-> <br/> next = record # clientinfo. ID, <br/> IO: Format ("record is :~ P ~ N ", [Record]), <br/> JSON = util_setinfoparas: deparaelement (record), <br/> IO: Format (" clientsession found :~ P ~ N ", [Record]), <br/> newulist = [JSON | ulist], <br/> getclient (table, [next], newulist ); <br/> []-> <br/> ulist <br/> end <br/>. <br/>
In this case. Note: client_manager has a getnick/1 function, which returns the nickname of the user corresponding to the ID. How can I find the nickname of a user from the correct table? This issue will be handled in the user message routing section.
Now.