zoukankan      html  css  js  c++  java
  • InChatter系统之客户端消息处理中心

    一、模块结构

    首先来看下客户端消息处理中心模块的简单结构:

    ChatCallback:服务器端我们定义的回调接口IChatCallback的客户端实现

    ChatMsgCenter:服务端的消息处理中心,所有的消息都将在这里进行分发处理,可以比作人的大脑中枢

    ClientContext:登录信息描述,也可以理解为客户端唯一标识

    DataHelper:数据库操作类,这里我们使用NDatabase的开源对象数据库,使用方法参考关法文档

    Messager:消息类封装,在消息的基础上,添加了ID属性和IsRead属性

    二、技术实现

    1.ChatCallbck的实现原理

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InChatter.Client.Service
    {
        public class ChatCallback:ChatServer.IChatCallback
        {
            public event Action<ChatServer.InChatterMessage> OnMessgeReceived;
    
            public void ReceiveMsg(ChatServer.InChatterMessage message)
            {
                if (OnMessgeReceived != null)
                {
                    OnMessgeReceived(message);
                }
            }
        }
    }

    在ChatcallBack类中,我们添加了OnMessageReceived事件处理,由于回调的触发在服务器端,所以当服务器端调用ReceiveMsg方法时,我们为ChatCallback注册的事件,便可以执行并捕获对应的数据。

    2.Messager消息类的封装

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InChatter.Client.Service
    {
        public class Messager
        {
            public string Id { set; get; }
            public bool IsRead { set; get; }
            public ChatServer.InChatterMessage Message { set; get; }
            public Messager()
            {
                Id = Guid.NewGuid().ToString();
            }
        }
    }

    正如我前面解释的那样,这里对InChatterMessage进行了封装,添加了Id以便于我们进行相应的数据库等操作,而IsRead标识了消息的阅读状态

    3.DataHelper类的实现

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InChatter.Client.Service
    {
        public class DataHelper
        {
            #region Save
            public static bool Save(Messager message)
            {
                try
                {
                    lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                    {
                        using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                        {
                            db.Store(message);
                        }
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
            public static bool Save(IEnumerable<Messager> msgList)
            {
                try
                {
                    lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                    {
                        using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                        {
                            foreach (var msg in msgList)
                            {
                                db.Store(msg);
                            }
                        }
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
            #endregion
    
            public static bool Update(Messager message)
            {
                try
                {
                    lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                    {
                        using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                        {
                            var msg = (from item in db.AsQueryable<Messager>()
                                       where item.Id == message.Id
                                       select item).Single();
                            msg.IsRead = message.IsRead;
                            msg.Message = message.Message;
                            db.Store(msg);
                        }
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
    
            public static bool Delete(string msgId)
            {
                try
                {
                    lock (string.Intern(ChatMsgCenter.Instance.DbUrl))
                    {
                        using (var db = NDatabase.OdbFactory.Open(ChatMsgCenter.Instance.DbUrl))
                        {
                            var msg = (from item in db.AsQueryable<Messager>()
                                       where item.Id == msgId
                                       select item).Single();
                            db.Delete(msg);
                        }
                    }
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }
    }

    这里我们使用的NDatabase的开源对象数据库,这里有一个需要注意的地方是NDatabase没有明确的update方法,它使用的是读取并更新的方式,即从数据库中读取的数据,而后直接进行的操作并调用Store方法,将处理为更新(操作代码在同一个区域块内),这里需要特别注意,否则将会存储很多相同的实例,而无法应用更新。

    4.ClientContext类的实现原理

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InChatter.Client.Service
    {
        public class ClientContext
        {
            static Lazy<ClientContext> _Instance = new Lazy<ClientContext>();
            public static ClientContext Instance
            {
                get
                {
                    return _Instance.Value;
                }
            }
            public string LoginId { set; get; }
            public string LoginName { set; get; }
        }
    }

    这里目前通过LoginId和LoginName标识登录状态,而Login将被用来标识客户端Id

    5.ChatMsgCenter消息处理中心类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace InChatter.Client.Service
    {
        public class ChatMsgCenter
        {
            private static Lazy<ChatMsgCenter> _Instance = new Lazy<ChatMsgCenter>();
    
            public static ChatMsgCenter Instance
            {
                get
                {
                    return _Instance.Value;
                }
            }
    
            public string DbUrl { set; get; }
    
            public ChatServer.ChatClient Client { set; get; }
    
            private ChatCallback callback { set; get; }
    
            public event Action<ChatServer.InChatterMessage> OnMessageReceived;
    
            public event Action<Messager> OnUnReadMessageRead;
    
            private ChatMsgCenter()
            {
                callback = new ChatCallback();
                Client = new ChatServer.ChatClient(new System.ServiceModel.InstanceContext(callback), "NetTcpBinding_IChat");
                callback.OnMessgeReceived+=callback_OnMessgeReceived;
            }
    
            private void callback_OnMessgeReceived(ChatServer.InChatterMessage message)
            {
                Messager msg = new Messager()
                {
                    IsRead = false,
                    Message = message,
                };
                DataHelper.Save(msg);
                if (OnMessageReceived != null)
                {
                    OnMessageReceived(message);
                }
            }
    
            public void Login(string clientId)
            {
                Client.Login(clientId);
                DbUrl = "Messages\"+clientId+".db";
            }
    
            public void SendMsg(ChatServer.InChatterMessage message)
            {
                Messager msg = new Messager()
                {
                    IsRead = true,
                    Message = message,
                };
                DataHelper.Save(msg);
                Client.SendMsg(msg.Message);
            }
    
            public void Logout(string clientId)
            {
                Client.Logout(clientId);
            }
        }
    }

    这里是使用单件来实现的系统类,并且还应用了延迟加载类的辅助LazyLoad,LazyLoad类的具体用法参考这里

    在Login时,我们向服务器发送Login请求,并设置当前登录ClientContext的信息,同时设置数据存储地址,客户端将根据登录人ID来标识,每个人的存储都对应到自己Id地址的数据库中。

    以上是整个客户端系统的重要部分,欢迎大家讨论,并提供宝贵意见

    源码提供给大家:下载源码到CodePlex下载最新版本

  • 相关阅读:
    各种数字证书区别
    微信支付前端对接流程
    ts笔记 流动类型
    支付宝支付前端对接流程
    ts笔记索引签名
    [翻译]Selenium API 命令和操作(JAVA)
    玩一玩yolo目标检测
    快速上手MyBatis
    Swift快速入门
    Windows远程桌面后不能粘贴问题处理
  • 原文地址:https://www.cnblogs.com/wpfworld/p/3418645.html
Copyright © 2011-2022 走看看