2.4 The source code analysis
Refer to the source code of the chatserver server project and the demo/chatroom/javascript/chatroom.js client in the analysis. The relative project description xml is in the demo/chatroom/xmls/ directory.
In the below description, the chat specifically means the group chat to distinguish the private chat.
-
2.4.1 View
The below View has no well-defined Control to support the script system. Through the Message implementation, directly send the custom string command to the specific View to implement the control function.
-
TemporaryView
chatroom.view.xml:
<view name="ChatRoom" lifecycle="temporary"> <variable name="info" type="ViewChatRoomInfo" /> <subscribe name="names" ref="UserInfo.name" /> <variable name="lastmessage" type="ChatMessage" /> </view>
-
<variable name="lastmessage" type="ChatMessage" />
The TemporaryView ChatRoom describes the core function of a chat room. A temporary View corresponds a detailed chat room. The participants as the members of the TemporaryView join the chat. Any modification to the variable is automatically synchronized to all the members' client. So, the essence of the chat is to use the message sent by the members of the chat room to update the lastmessage. Here the lastmessage of the ChatMessage is defined as:
<bean name="ChatMessage"> <variable name="msg" type="string" /> <variable name="user" type="long" /> </bean>
The msg is the chat information, and the user is the id of the sender.
The user sends the chat type Message to the current ChatRoom. The getMessageTo() here returns -1.
chatroom.js:
function sendMessage() { var sendmsg = document.getElementById('sendmsg'); var msg = sendmsg.value.trim(); if (msg.length > 0) context.send(currentChatView, "message=" + getMessageTo() + "," + msg); sendmsg.value = ""; }
The server ChatRoom receives the Message and process it.
ChatRoom.java:
protected void onMessage(String message, long sessionid) { int index = message.indexOf('='); if (-1 == index) return; final String cmd = message.substring(0, index).trim(); final String params = message.substring(index + 1); switch (cmd) { case "message": { ............................. if (-1L == toid) { ChatRoom.this.setLastmessage(new ChatMessage(msg, sessionid)); RoomInfo.increment_publicMessages_mapkey(roomid); } else { ............................. } return; } ............................. }
Here the setLastmessage is called to set the chat information msg and the sessionid of the current sender to the current ChatRoom. Then the framework automatically synchronizes the change to all the members’ clients.
ctx.register(currentChatView, "lastmessage", function(e) { if (e.type == 1 || e.type == 2) showMessageToAll(e.value.user, e.value.msg); });
The listener of the lastmessage is registered here. Once the change of the server's lastmessage is synchronized to the client, the chat message is displayed through showMessageToAll.
It should be noted that the type is defined as the "var type = [ 'NEW', 'REPLACE', 'TOUCH', 'DELETE' ];". (NEW means that this field is new created from nonexistence to existence; REPLACE means that the value of this field is different from the last synchronized one and has been changed; TOUCH means the value of this field is the same as the last one and has no change; DELETE means that the relative field of the server does not exist and be deleted.) In the above code, the e.type matches the REPLACE and TOUCH, but not NEW. The reason is that when participant joins the TemporaryView, all the information of the current TemporaryView will be synchronized to this participant. That means if the NEW is matched, the last chat message of the previous members will be synchronized to the new participant. So a boundary condition need to be resolved here.
ChatRoom.java:
private ChatRoom(TemporaryView.CreateParameter param) { super(param); ChatRoom.this.setLastmessage(new ChatMessage("", -1)); }
After creating the ChatRoom, the lastmessage sets an useless information for the first user to discard.
-
<subscribe name="names" ref="UserInfo.name" />
The subscription is a very important function of the TemporaryView, which could subscribe the member users' field information of the SessionView. Once the subscribed field of some member is changed, the change will be automatically synchronized to all the members.
Here the subscribed names as an example to implement. Subscribing the user's name means that when some user change its name, all the members of the chat room will see this change.
The user sends the Message to its own SessionView UserInfo to modify the nickname.
chatroom.js:
function doRename() { var v100 = context[100]; var name = prompt("input name", v100.chatviews.UserInfo.name); if (name != null && name != v100.chatviews.UserInfo.name) context.send(v100.chatviews.UserInfo, "nickname=" + name); }
The server receives the message and processes it.
UserInfo.java:
protected void onMessage(String message, long sessionid) { final int index = message.indexOf('='); if (-1 == index) return; checkUpdateHallInfos(); final String cmd = message.substring(0, index).trim(); final String param = message.substring(index + 1).trim(); switch (cmd) { case "nickname": Procedure.execute(ProcedureHelper.nameProcedure( "onMessage nickname", () -> { xbean.UserInfo info = table.Userinfo.update(sessionid); ........................................ info.setNickname(param); SysInfo.increment_nickNameChange(); return true; })); return; ........................................ } }
The setNickname here modifies the xbean relative to the sessionid of the userinfo table. The xbean is bound in the name field of the current UserInfo, and the UserInfo.name of this field is subscribed by this temporary View of the ChatRoom. So all the members of the ChatRoom could see the change of the nickname. The detailed information of the bind will be introduced in the SessionView.
chatroom.js:
ctx.register(currentChatView, "names", function(e) { updateName(e.sessionid, e.value.nickname); });
All the members (including the user itself who changes the name) of the ChatRoom receive the id and new names of the user who changes the name. The updateName is called to modify the UI expression.
-
<variable name="info" type="ViewChatRoomInfo" />
The above is the information description of the chatroom itself. The main function is that the chatroom information is synchronized to the client when the user enters the chatroom. It is simpler than the lastmessage.
-
-