Many friends who develop IM systems want to implement the indispensable function of storing and querying chat records. Here I will regard myself as oraytalk) share the experience of the development chat module for your reference.
I. Overall Design
1. storage location
From the very beginning, we planned to store chat records locally on both the server and client. When viewing chat records on the client, we can choose whether to load the records locally or from the server. There are two advantages:
(1) Loading chat records locally is very fast.
(2) When the login machine is replaced, full chat records can be loaded from the server at any time, and the records will never be lost.
2. Storage Solution
(1) storing chat records on the server, of course, uses our mainstream database sqlserver or MySQL.
(2) on the client side, we chose to use the serialization technology. However, given that the serialization scheme is not flexible enough when the chat record data volume is large, and the performance cannot keep up. Therefore, we finally decided to use the lightweight database SQLite.
3. Orm framework
The latest version of datarabbit adds support for SQLite, and the operation APIs for different databases are completely consistent, therefore, we use datarabbit to write a small component to complete database access operations such as chat record storage and query. This component is used to store chat records on both the client and server.
II. Specific implementation
1. chatmessagerecord class
A chat record basically contains the following content: sender, recipient, content, and time. In addition, we want to abstract two-person chats and group chats into the same model. Therefore, the entity class chatmessagerecord of chat records is designed as follows:
Public class chatmessagerecord {# region autoid private long autoid = 0; // <summary> // auto-increment ID, id. /// </Summary> Public long autoid {get {return autoid;} set {autoid = value ;}# endregion # region speakerid private string speakerid = ""; /// <summary> /// speaker ID. /// </Summary> Public String speakerid {get {return speakerid;} set {speakerid = value; }}# endregion # region audienceid private string audienceid = ""; /// <summary> /// audience ID, which can be groupid. /// </Summary> Public String audienceid {get {return audienceid;} set {audienceid = value ;}# endregion # region occuretime private datetime occuretime = datetime. now; /// <summary> /// the time when the chat record occurred. /// </Summary> Public datetime occuretime {get {return occuretime;} set {occuretime = value; }}# endregion # region contentrtf private string contentrtf = ""; /// <summary> /// chat content. /// </Summary> Public String contentrtf {get {return contentrtf;} set {contentrtf = value; }}# endregion # region isgroupchat private bool isgroupchat = false; /// <summary> /// whether the group chat record is used. /// </Summary> Public bool isgroupchat {get {return isgroupchat;} set {isgroupchat = value ;}# endregion}
In the definition of chatmessagerecord, the chat content field is designed to be of the string type, because in oraytalk, the chat content is in Rich Text RTF format. If needed, you can change it to the byte [] type, so that custom serialization operations can carry more complex chat formats.
The last field isgroupchat indicates whether the current record is a group chat record. If it is a group chat record, audienceid is not a friend ID, but the ID of the target group.
Note: The chatmessagerecord entity is fully mapped to the chatmessagerecord table in the database, which makes it possible to access the ORM Data of datarabbit.
2. chatrecordpage class
When we request chat records, because the number of records may be very large, pagination is inevitable. We use chatrecordpage to encapsulate a page of chat records returned for query:
Based on the totalcount field in the chatrecordpage, The queryer can know the number of qualified records, so that he can know the total number of pages.
3. ichatrecordpersister Interface
We use the same interface ichatrecordpersister to abstract both the client and server to store and query chat records:
Public interface ichatrecordpersister {// <summary> // insert a chat record (including group chat records ). /// </Summary> void insertchatmessagerecord (chatmessagerecord record); /// <summary> /// obtain a page of chat records with friends. /// </Summary> /// <Param name = "timescript"> date range </param> /// <Param name = "myid"> userid </ param> /// <Param name = "friendid"> friend ID </param> /// <Param name = "pagesize"> page size </param> /// <Param name = "pageindex"> page index </param> // <returns> chat record page </returns> chatrecordpage getchatrecordpage (datetimes#times, string myid, string friendid, int pagesize, int pageindex); // <summary> // obtain a group chat record. /// </Summary> /// <Param name = "timescript"> date range </param> /// <Param name = "groupid"> group ID </Param> /// <Param name = "pagesize"> page size </param> /// <Param name = "pageindex"> page index </param> /// <returns> chat record page </returns> chatrecordpage getgroupchatrecordpage (datetimes?times=, string groupid, int pagesize, int pageindex );}
(1) When you insert a game record, you can use the same insertchatmessagerecord method as your friend chat record and group chat record. The field assignment is different when you construct a chatmessagerecord object.
(2) When datarabbit is used to implement this interface (such as the chatrecordpersister class), the attribute databasetype is used to control whether the accessed SQLite database is used. Then, when the server uses chatrecordpersister to access chat records, it sets databasetype to sqlserver and the client to SQLite.
Iii. Possible remoting Interfaces
When loading chat records from the server, you can consider using remoting technology. If so, you only need to expose the ichatrecordpersister interface on the server as the remoting service, then the client uses this remoting service to query chat records. In this way, the client only needs to switch the ichatrecordpersister to the reference of the local chatrecordpersister object or remoting remote reference when loading from the local server. The entire code implementation will be very concise and consistent.
Now, the design and implementation of the chat record module are similar. According to this idea, it is very easy to add the chat record function in your IM system. Finally, the last chat record query interface of the oraytalk client:
Here we are. If you have any questions, please leave a message and I will reply in time.