using MadRunFabric.Model; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using OnLineChatApi.IRepositories; namespace OnLineChatApi.Class { public class ChatHub : Hub { private readonly ILogger _logger; private IChat_UserRepository _chatuserRepository; private IChat_InOutRepository _chatinoutRepository; private IChat_MessageRepository _chatmessageRepository; private IChat_ProcessRepository _chatprocessRepository; private IChat_SessionRepository _chatsessionRepository; private ISys_DictionaryValueRepository _sys_dictionaryValuerepository; public static List ConnectionIds = new List(); public static List Servicers = new List(); public static List Customers = new List(); private static readonly object lockobj = new object(); public ChatHub(IChat_UserRepository chatuserRepository, IChat_InOutRepository chatinoutRepository, IChat_MessageRepository chatmessageRepository, IChat_ProcessRepository chatprocessRepository, IChat_SessionRepository chatsessionRepository, ISys_DictionaryValueRepository sys_dictionaryValuerepository, ILogger logger) { _logger = logger; _chatuserRepository = chatuserRepository; _chatinoutRepository = chatinoutRepository; _chatmessageRepository = chatmessageRepository; _chatprocessRepository = chatprocessRepository; _chatsessionRepository = chatsessionRepository; _sys_dictionaryValuerepository = sys_dictionaryValuerepository; } /// /// 接收信息 /// /// /// public async Task ReceiveMessage(string message) { try { //_logger.LogError(message); var ip = getipaddress(); JObject msg = JsonConvert.DeserializeObject(message); msg["state"] = 1; int channel = msg["channel"] != null ? Int32.Parse(msg["channel"].ToString()) : 0; switch (msg["action"].ToString().ToLower()) { case "cusconn": #region 客户连接 if (msg["usercode"] == null || msg["usercode"].ToString() == "") { msg["usercode"] = "web" + DateTime.Now.Ticks; msg["name"] = "游客"; } //客户不存在,则创建 var cususer = _chatuserRepository.Get(p => p.usercode == msg["usercode"].ToString()).Result.FirstOrDefault(); if (cususer == null) { cususer = new Chat_User(); cususer.usercode = msg["usercode"].ToString(); cususer.name = msg["name"] != null ? msg["name"].ToString() : ""; cususer.headimgurl = msg["headimgurl"] != null ? msg["headimgurl"].ToString() : ""; cususer.ip = new List() { ip }; cususer.type = 1; cususer.createuser = msg["usercode"].ToString(); cususer.createtime = DateTime.Now; cususer.isdelete = 0; await _chatuserRepository.Add(cususer); } //新增客户上线记录 Chat_InOut cio = new Chat_InOut(); cio.channel = msg["channel"] != null ? Int32.Parse(msg["channel"].ToString()) : 0; cio.intime = DateTime.Now; cio.ip = ip; cio.connectionid = Context.ConnectionId; cio.type = 1; cio.usercode = msg["usercode"].ToString(); cio.name = msg["name"] != null ? msg["name"].ToString() : ""; cio.headimgurl = msg["headimgurl"] != null ? msg["headimgurl"].ToString() : ""; cio.isdelete = 0; cio.createtime = DateTime.Now; cio.createuser = msg["usercode"].ToString(); await _chatinoutRepository.Add(cio); //新增客户会话记录 Chat_Session ses = new Chat_Session(); ses.chatusers = new List(); chatuser cuser = new chatuser(); cuser.connectionid = Context.ConnectionId; cuser.usercode = cususer.usercode; cuser.name = cususer.name; cuser.headimgurl = cususer.headimgurl; cuser.ip = ip; cuser.isonline = 1; cuser.type = 1; ses.chatusers.Add(cuser); ses.state = 1; ses.isdelete = 0; ses.createtime = DateTime.Now; ses.type = 1; ses.step = 1; ses.sertype = 1; ses.stepresult = new List(); ses.id = await _chatsessionRepository.AddRetID(ses); msg["sessionid"] = ses.id; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); await SystemReply(ses); Customers.Remove(Customers.Where(p => p.UserCode == cususer.usercode).FirstOrDefault()); Customers.Remove(Customers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault()); ChatClass.Customer customer = new ChatClass.Customer(); customer.ConnectionId= Context.ConnectionId; customer.SessionID = ses.id; customer.UserCode= cususer.usercode; Customers.Add(customer); #endregion break; case "cussend": #region 客户发送消息 var sessionid = msg["sessionid"].ToString(); var cussendsession = _chatsessionRepository.GetSingle(sessionid).Result; var sessionusers = cussendsession.chatusers; var conncususer = sessionusers.Where(p => p.connectionid == Context.ConnectionId).FirstOrDefault(); await AddMessage(cussendsession.id, channel, conncususer.usercode, msg["message"].ToString(), new List(), cussendsession.step); if (cussendsession.sertype == 1)//系统客服 { #region 系统客服 await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); bool bl = true; bool iscomplete = true; string value = msg["message"].ToString(); var options = new List(); var step = _chatprocessRepository.Get(p => p.isdelete == 0 && p.step == cussendsession.step).Result.FirstOrDefault(); if (step != null) { if (step.optiontype == 1) { var optionlist = await _sys_dictionaryValuerepository.Get(p => p.dictionarycode == step.dictionarycode && p.statetype == true); options = optionlist.Select(p => p.name).ToList(); } if (step.optiontype == 2) { options = step.options; } if (options.Count() > 0) { try { int num = Int32.Parse(value); int count = options.Count; if (num > count || num < 1)//数字选择验证 { bl = false; } else { value = options[num - 1]; } } catch { if (!options.Contains(value))//文字选择验证 { bl = false; } } } if (!bl) { iscomplete = false; string msgcontent = "输入有误,请重新输入"; var cusmsg = new { action = "cusreceive", message = msgcontent, state = 1 }; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(cusmsg)); await AddMessage(cussendsession.id, channel, "", msgcontent, new List(), cussendsession.step); } if (bl) { var stepcount = await _chatprocessRepository.Count(p => p.isdelete == 0); var stepresultcount = cussendsession.stepresult.Count(); cussendsession.step = stepresultcount + 2; if (stepresultcount < stepcount) { cussendsession.stepresult.Add(value); if (stepresultcount + 1 < stepcount) { iscomplete = false; await SystemReply(cussendsession); } } await _chatsessionRepository.UpdateOne(cussendsession); } } if(iscomplete) { var cusmsg = new { action = "cusreceive", message = "你的诉求已经记录,请等待处理结果!", state = 1 }; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(cusmsg)); } #endregion } if (cussendsession.sertype == 2)//人工客服 { #region 人工客服 var connseruser = sessionusers.Where(p => p.type == 2).FirstOrDefault(); if (connseruser.isonline == 0)//客服不在线 { msg["state"] = 0; msg["message"] = "客服忙,请稍后!"; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); } else//客服在线 { await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); var serntcmsg = new { action = "serreceive", message = msg["message"].ToString(), sessionid = cussendsession.id, conncususer.usercode, conncususer.name, conncususer.headimgurl, state = 1 }; await SendMsgToRemotePoint(connseruser.connectionid, JsonConvert.SerializeObject(serntcmsg)); } #endregion } #endregion break; case "custurn": #region 客户转人工或转系统 var turnsessionid = msg["sessionid"].ToString(); var turnsendsession = _chatsessionRepository.GetSingle(turnsessionid).Result; var turnsessionusers = turnsendsession.chatusers; var connturnuser = turnsessionusers.Where(p => p.connectionid == Context.ConnectionId).FirstOrDefault(); string turnmessage = string.Empty; if (turnsendsession.sertype == 1)//系统客服 { #region 转人工回复 msg["state"] = 0; if (await SplitCustomer(turnsendsession)) { msg["message"] = "转人工回复!"; turnmessage = "转人工回复成功"; } else { msg["message"] = "客服忙,请稍后!"; turnmessage = "转人工回复失败"; } await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); await AddMessage(turnsendsession.id, channel, connturnuser.usercode, turnmessage, new List(), turnsendsession.step); #endregion } else if (turnsendsession.sertype == 2)//人工客服 { #region 转机器回复 await AddMessage(turnsendsession.id, channel, connturnuser.usercode, "转机器回复成功", new List(), turnsendsession.step); var stepcount = await _chatprocessRepository.Count(p => p.isdelete == 0); if (turnsendsession.step > stepcount) { msg["state"] = 0; msg["message"] = "转机器回复!"; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); await SystemReply(turnsendsession); } else { msg["state"] = 1; msg["message"] = "你的诉求已经记录,请等待处理结果!"; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); } #endregion } #endregion break; case "serconn": #region 客服连接 Chat_InOut sercio = new Chat_InOut(); sercio.channel = msg["channel"] != null ? Int32.Parse(msg["channel"].ToString()) : 0; sercio.intime = DateTime.Now; sercio.ip = ip; sercio.connectionid = Context.ConnectionId; sercio.type = 2; sercio.isseat = 1; sercio.usercode = msg["usercode"]?.ToString() ?? ""; sercio.name = msg["name"]?.ToString() ?? ""; sercio.headimgurl = msg["headimgurl"]?.ToString() ?? ""; sercio.isdelete = 0; sercio.createtime = DateTime.Now; sercio.createuser = msg["usercode"]?.ToString() ?? ""; await _chatinoutRepository.Add(sercio); await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); Servicers.Remove(Servicers.Where(p => p.UserCode == sercio.usercode).FirstOrDefault()); Servicers.Remove(Servicers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault()); ChatClass.Servicer servicer = new ChatClass.Servicer(); servicer.ConnectionId = Context.ConnectionId; servicer.UserCode = sercio.usercode; Servicers.Add(servicer); #endregion break; case "sersession": #region 客服会话 var usercode = msg["usercode"].ToString(); var connusercode = msg["connusercode"].ToString(); var inout = _chatinoutRepository.Get(p => p.usercode == usercode && p.outtime == null).Result.OrderByDescending(p=>p.intime).FirstOrDefault(); var conninout = _chatinoutRepository.Get(p => p.usercode == connusercode && p.outtime == null).Result.OrderByDescending(p => p.intime).FirstOrDefault(); var sersess = _chatsessionRepository.Get(p => p.type == 2).Result.ToList(); var serses = sersess.Where(p => p.chatusers.Select(q => q.usercode).Contains(usercode) && p.chatusers.Select(q => q.usercode).Contains(connusercode)).ToList().FirstOrDefault(); if (serses == null) { serses = new Chat_Session(); chatuser fuser = new chatuser(); fuser.connectionid = Context.ConnectionId; fuser.usercode = usercode; fuser.name = inout.name; fuser.headimgurl = inout.headimgurl; fuser.ip = ip; fuser.isonline = 1; serses.chatusers.Add(fuser); chatuser tuser = new chatuser(); tuser.usercode = connusercode; if (conninout != null) { tuser.connectionid = conninout.connectionid; tuser.name = conninout.name; tuser.headimgurl = conninout.headimgurl; tuser.ip = conninout.ip; tuser.isonline = 1; } else { tuser.isonline = 0; } serses.chatusers.Add(tuser); serses.state = 1; serses.isdelete = 0; serses.createtime = DateTime.Now; serses.type = 2; serses.sertype = 1; serses.step = 1; serses.stepresult = new List(); serses.id = await _chatsessionRepository.AddRetID(serses); } else { serses.chatusers = new List(); chatuser fuser = new chatuser(); fuser.connectionid = Context.ConnectionId; fuser.usercode = usercode; fuser.name = inout.name; fuser.headimgurl = inout.headimgurl; fuser.ip = ip; fuser.isonline = 1; serses.chatusers.Add(fuser); chatuser tuser = new chatuser(); tuser.usercode = connusercode; if (conninout != null) { tuser.connectionid = conninout.connectionid; tuser.name = conninout.name; tuser.headimgurl = conninout.headimgurl; tuser.ip = conninout.ip; tuser.isonline = 1; } else { tuser.isonline = 0; } serses.chatusers.Add(tuser); await _chatsessionRepository.UpdateOne(serses); } msg["sessionid"] = serses.id; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); #endregion break; case "sersend": #region 客服发送消息 var sersessionid = msg["sessionid"].ToString(); var sersendsession = _chatsessionRepository.GetSingle(sersessionid).Result; var sersessionusers = sersendsession.chatusers; var connsersenduser = sersessionusers.Where(p => p.connectionid == Context.ConnectionId).FirstOrDefault(); await AddMessage(sersendsession.id, channel, connsersenduser.usercode, msg["message"].ToString(), new List(), sersendsession.step); if (sersendsession.type == 1) { var conncussenduser = sersessionusers.Where(p => p.type == 1).FirstOrDefault(); //if (conncussenduser.isonline == 0) if (Customers.Where(p => p.ConnectionId == conncussenduser.connectionid).FirstOrDefault() == null) { msg["state"] = 0; msg["message"] = "客户已下线"; } else { var serntcmsg = new { action = "cusreceive", message = msg["message"].ToString(), state = 1 }; await SendMsgToRemotePoint(conncussenduser.connectionid, JsonConvert.SerializeObject(serntcmsg)); } } else { var conncussenduser = sersessionusers.Where(p => p.connectionid != Context.ConnectionId).FirstOrDefault(); //if(conncussenduser.isonline == 0) if (Servicers.Where(p => p.ConnectionId == conncussenduser.connectionid).FirstOrDefault() == null) { msg["state"] = 0; msg["message"] = conncussenduser.name + "已下线"; } else { var serntcmsg = new { action = "serreceive", message = msg["message"].ToString(), sessionid = sersessionid, conncussenduser.usercode, conncussenduser.name, conncussenduser.headimgurl, state = 1 }; await SendMsgToRemotePoint(conncussenduser.connectionid, JsonConvert.SerializeObject(serntcmsg)); } } await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); #endregion break; default: await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg));break; } } catch(Exception ex) { _logger.LogError(ex.Message.ToString()); try { JObject msg = JsonConvert.DeserializeObject(message); msg["state"] = 0; msg["message"] = "操作失败"; await Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)); } catch { await Clients.Caller.SendAsync("ReceiveMessage", message); } } } /// /// 加入组 /// /// /// public async Task JoinGroup(string groupName) { await Groups.AddToGroupAsync(Context.ConnectionId, groupName); } /// /// 离开组 /// /// /// public async Task LeaveGroup(string groupName) { await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName); } /// /// 连接事件 /// /// public override async Task OnConnectedAsync() { lock (lockobj) { ConnectionIds.Add(Context.ConnectionId); var msg = new { action = "conn", state = 1 }; Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)).Wait(); } await base.OnConnectedAsync(); } /// /// 断开连接事件 /// /// /// public override async Task OnDisconnectedAsync(Exception exception) { await base.OnDisconnectedAsync(exception); lock (lockobj) { ConnectionIds.Remove(Context.ConnectionId); var cus = Customers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault(); if (cus != null)//客户断线 { var session = _chatsessionRepository.GetSingle(cus.SessionID).Result; session.state = 0; _chatsessionRepository.UpdateOne(session).Wait(); if (!string.IsNullOrEmpty(cus.ServicerConnectionId)) { var ser = Servicers.Where(p => p.ConnectionId == cus.ServicerConnectionId).FirstOrDefault(); if (ser != null) { var serntcmsg = new { action = "serreceive", message = "客户下线", sessionid = cus.SessionID, state = 0 }; SendMsgToRemotePoint(cus.ServicerConnectionId, JsonConvert.SerializeObject(serntcmsg)).Wait(); ser.Count = ser.Count - 1; } } Customers.Remove(cus); } else { var ser = Servicers.Where(p => p.ConnectionId == Context.ConnectionId).FirstOrDefault(); if (ser != null)//客服断线 { Servicers.Remove(ser); var cuss = Customers.Where(p => p.ServicerConnectionId == Context.ConnectionId); foreach (var cusa in cuss) { var session = _chatsessionRepository.GetSingle(cusa.SessionID).Result; if (Servicers.Count == 0) { cusa.ServicerConnectionId = ""; var cusntcmsg = new { action = "cusreceive", message = "客服忙,已经转为机器回复!", sessionid = cusa.SessionID, state = 0 }; SendMsgToRemotePoint(cusa.ConnectionId, JsonConvert.SerializeObject(cusntcmsg)).Wait(); SystemReply(session).Wait(); } else { SplitCustomer(session).Wait(); } } } } var inout = _chatinoutRepository.Get(p => p.connectionid == Context.ConnectionId).Result.FirstOrDefault(); if (inout != null) { inout.outtime = DateTime.Now; _chatinoutRepository.UpdateOne(inout).Wait(); } var msg = new { action = "disconn", state = 1 }; Clients.Caller.SendAsync("ReceiveMessage", JsonConvert.SerializeObject(msg)).Wait(); } } /// /// 获取ip /// /// public string getipaddress() { var context = Context.GetHttpContext(); var ip = context.Request.Headers["X-Forwarded-For"]; if (string.IsNullOrEmpty(ip)) { ip = context.Connection.RemoteIpAddress.ToString(); } return ip; } /// /// 发送消息到 /// /// /// private async Task SendMsgToRemotePoint(string ConnectionId, string msg) { try { await Clients.Client(ConnectionId).SendAsync("ReceiveMessage", msg); return true; } catch { return false; } } /// /// 系统流程回复 /// /// /// private async Task SystemReply(Chat_Session session) { //系统流程回复 var tuser = session.chatusers.Where(p => p.type == 1).FirstOrDefault(); if (session.sertype == 2) { session.sertype = 1; session.chatusers = new List { tuser }; await _chatsessionRepository.UpdateOne(session); } var step = _chatprocessRepository.Get(p => p.isdelete == 0 && p.step == session.step).Result.FirstOrDefault(); if (step != null) { var options = new List(); if (step.optiontype == 1) { var optionlist = await _sys_dictionaryValuerepository.Get(p => p.dictionarycode == step.dictionarycode && p.statetype == true); options = optionlist.Select(p => p.name).ToList(); } if (step.optiontype == 2) { options = step.options; } var cusmsg = new { action = "cusreceive", message = step.content, options, state = 1 }; await SendMsgToRemotePoint(tuser.connectionid, JsonConvert.SerializeObject(cusmsg)); await AddMessage(session.id, 0, "", step.content, options, step.step); return true; } else { return false; } } /// /// 分配客服 /// /// /// /// private async Task SplitCustomer(Chat_Session session) { var fuser = session.chatusers.Where(p => p.type == 1).FirstOrDefault(); //var serusers = await _chatinoutRepository.Get(p => p.type == 2 && p.isseat == 1 && p.outtime == null); var serusers = Servicers; if (serusers.Count() > 0) { //var cus = _chatsessionRepository.Get(q => q.state == 1 && q.type == 1).Result.ToList(); //var sercuscount = serusers.ToList().Select(p => new //{ // p.connectionid, // p.headimgurl, // p.intime, // p.name, // p.usercode, // cuscount = cus.Count(q => q.chatusers.Where(x => x.type == 2).Select(x => x.connectionid).Contains(p.connectionid)) //}); //var seruser = sercuscount.OrderBy(p => p.cuscount).ThenBy(p => p.intime).FirstOrDefault(); var selseruser = serusers.OrderBy(p => p.Count).FirstOrDefault(); var seruser = _chatinoutRepository.Get(p => p.connectionid == selseruser.ConnectionId).Result.FirstOrDefault(); var tuser = session.chatusers.Where(p => p.type == 2).FirstOrDefault(); if (tuser != null) { tuser.connectionid = seruser.connectionid; tuser.usercode = seruser.usercode; tuser.name = seruser.name; tuser.headimgurl = seruser.headimgurl; tuser.isonline = 1; tuser.type = 2; } else { tuser = new chatuser(); tuser.connectionid = seruser.connectionid; tuser.usercode = seruser.usercode; tuser.name = seruser.name; tuser.headimgurl = seruser.headimgurl; tuser.isonline = 1; tuser.type = 2; session.chatusers.Add(tuser); } session.sertype = 2; var msg = new { action = "serreceive", message = "客户上线", sessionid = session.id, fuser.usercode, fuser.name, fuser.headimgurl, state = 0 }; await SendMsgToRemotePoint(tuser.connectionid, JsonConvert.SerializeObject(msg)); await _chatsessionRepository.UpdateOne(session); var cususer = Customers.Where(p => p.ConnectionId == fuser.connectionid).FirstOrDefault(); cususer.ServicerConnectionId = seruser.connectionid; selseruser.Count = selseruser.Count + 1; return true; } else { return false; } } /// /// 新增聊天记录 /// /// /// private async Task AddMessage(string sessionid,int channel,string senduser, string content, List options,int step) { Chat_Message chatmsg = new Chat_Message(); chatmsg.sessionid = sessionid; chatmsg.channel = channel; chatmsg.senduser = senduser; chatmsg.content = content; chatmsg.options = options; chatmsg.step = step; chatmsg.state = 1; chatmsg.type = 1; chatmsg.channel = 0; chatmsg.isdelete = 0; chatmsg.createtime = DateTime.Now; await _chatmessageRepository.Add(chatmsg); } } }