using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Configuration; using SuperSocket.SocketBase; using SuperWebSocket; using SuperSocket.SocketBase.Config; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace CallCenter.WebChatServer { public class ChatServer { WebSocketServer server = new WebSocketServer(); ChatSql cs = new ChatSql(); public List Servicers = new List(); public List Customers = new List(); public ChatServer() { } /// /// 初始化服务 /// /// public bool Setup() { ServerConfig serverConfig = new ServerConfig { Ip = ConfigurationManager.AppSettings["ip"], Port = Int32.Parse(ConfigurationManager.AppSettings["port"]),//set the listening port MaxConnectionNumber = Int32.Parse(ConfigurationManager.AppSettings["maxnumber"]) }; //WebSocket服务器端启动 if (!server.Setup(serverConfig)) { server.Logger.Error("WebSocket服务器端启动失败"); //处理启动失败消息 return false; } //新的会话连接时 server.NewSessionConnected += server_NewSessionConnected; //会话关闭 server.SessionClosed += server_SessionClosed; //接收到新的消息时 server.NewMessageReceived += server_NewMessageReceived; return true; } /// /// 开启服务 /// /// public int Start() { if (server.State == ServerState.NotStarted) { if (!server.Start()) { server.Logger.Error(string.Format("开启WebSocket服务侦听失败:{0}:{1}", server.Config.Ip, server.Config.Port)); //处理监听失败消息 return 3; } } else { return 2; } return 1; } /// /// 关闭服务 /// /// public int Stop() { if (server.State == ServerState.Running) { server.Stop(); } else { return 2; } return 1; } /// /// 关闭服务 /// /// public ServerState State() { return server.State; } /// /// 接收到消息 /// /// /// private void server_NewMessageReceived(WebSocketSession session, string value) { try { var ip = session.RemoteEndPoint.Address.ToString(); ChatClass.Message msg = JsonConvert.DeserializeObject(value); msg.state = 1; switch (msg.action.ToLower()) { case "cusconn": #region 客户连接 if (!cs.IsBlack(ip)) { ChatClass.Customer cus = new ChatClass.Customer(); //添加到客户组 string code = msg.code; if (string.IsNullOrEmpty(code))//为空是网站,不为空是微信 { code = cs.GetCode(); } msg.code = code; var cusconn = Customers.Where(p => p.Code == code).FirstOrDefault(); if (cusconn == null) { var cususer = cs.GetCusUser(code);//获取是否存在此客户 if (cususer == null) { ChatSql.T_Chat_User user = new ChatSql.T_Chat_User(); user.F_OpenId = code; user.F_Account = code; user.F_Type = 1; user.F_State = 0; user.F_IsDelete = 0; user.F_CreateTime = DateTime.Now; user.F_Id = cs.AddUser(user); cususer = user; } if (string.IsNullOrEmpty(cususer.F_Name)) { cususer.F_Name = ConfigurationManager.AppSettings["anyname"]; } if (string.IsNullOrEmpty(cususer.F_IP)) { cususer.F_IP = ip; } cs.UpdateUser(cususer); cus.Name = cususer.F_Name; cus.HeadImgUrl = cususer.F_HeadImgUrl; msg.name = cus.Name; msg.headimgurl = cus.HeadImgUrl; cus.SessionID = session.SessionID; cus.Code = code; cus.IsSend = 0; //if (Servicers.Count <= 0) //{ // ChatClass.Message newmsg = new ChatClass.Message(); // newmsg.action = "ServicersAllOff"; // newmsg.msg = ConfigurationManager.AppSettings["busy"]; // session.Send(JsonConvert.SerializeObject(newmsg));//向客户发送客服不在线 //} if (Servicers.Count > 0) { cus.ServicerSessionID = SplitCustomer(cus); } ChatSql.T_Chat_IPList ipmodel = new ChatSql.T_Chat_IPList(); ipmodel = cs.GetIPInfo(ip, code); if (ipmodel == null) { #region ip记录 ipmodel = new ChatSql.T_Chat_IPList(); //string ipinfojson = ChatCommon.HttpGet(ConfigurationManager.AppSettings["ipurl"] + "?ip=" + ip); //var ipinfos = JsonConvert.DeserializeObject(ipinfojson); //var ipinfo = JsonConvert.DeserializeObject(ipinfos["data"].ToString()); ipmodel.F_IP = ip; ipmodel.F_OpenId = cus.Code; ipmodel.F_Type = 2; //ipmodel.F_Country = ipinfo["country"].ToString(); //ipmodel.F_CountryCode = ipinfo["country_id"].ToString(); //ipmodel.F_Area = ipinfo["area"].ToString(); //ipmodel.F_AreaCode = ipinfo["area_id"].ToString(); //ipmodel.F_Region = ipinfo["region"].ToString(); //ipmodel.F_RegionCode = ipinfo["region_id"].ToString(); //ipmodel.F_City = ipinfo["city"].ToString(); //ipmodel.F_CityCode = ipinfo["city_id"].ToString(); //ipmodel.F_County = ipinfo["county"].ToString(); //ipmodel.F_CountyCode = ipinfo["county_id"].ToString(); //ipmodel.F_ISP = ipinfo["isp"].ToString(); //ipmodel.F_ISPCode = ipinfo["isp_id"].ToString(); ipmodel.F_CreateTime = DateTime.Now; cs.AddIP(ipmodel); #endregion } msg.data = ipmodel; #region 签入时间 ChatSql.T_Chat_InOut inoutmodel = new ChatSql.T_Chat_InOut(); inoutmodel.F_OpenId = cus.Code; inoutmodel.F_IP = ip; inoutmodel.F_Type = 2; inoutmodel.F_InTime = DateTime.Now; cs.AddInOut(inoutmodel); #endregion cus.IPData = ipmodel; Customers.Add(cus);//将客户新增到在线客户列表 ChatClass.Message serntcmsg = new ChatClass.Message(); serntcmsg.action = "serreceive"; serntcmsg.msg = cus.Name + " 上线"; serntcmsg.code = cus.Code; serntcmsg.name = cus.Name; serntcmsg.data = ipmodel; serntcmsg.state = 0; SendMsgToRemotePoint(cus.ServicerSessionID, serntcmsg); } else { msg.code = ""; msg.state = 0; msg.msg = "请不要打开多个聊天窗口"; } } else { msg.state = 0; msg.msg = ConfigurationManager.AppSettings["black"]; } #endregion break; case "cussend": #region 客户发送消息 if (!cs.IsBlack(ip)) { var cussend = Customers.Where(p => p.SessionID == session.SessionID).FirstOrDefault(); if (cussend != null) { if (Servicers.Count <= 0) { cussend.IsSend = 1; msg.state = 0; msg.msg = ConfigurationManager.AppSettings["busy"]; } else { if (string.IsNullOrEmpty(cussend.ServicerSessionID)) { cussend.ServicerSessionID = SplitCustomer(cussend); } ChatClass.Message serrecmsg = new ChatClass.Message(); serrecmsg.action = "serreceive"; serrecmsg.msg = msg.msg; serrecmsg.code = cussend.Code; serrecmsg.name = cussend.Name; serrecmsg.headimgurl = cussend.HeadImgUrl; serrecmsg.state = 1; if (SendMsgToRemotePoint(cussend.ServicerSessionID, serrecmsg)) { var serreceive = Servicers.Where(p => p.SessionID == cussend.ServicerSessionID).FirstOrDefault(); ChatSql.T_Chat_Message cusmsg = new ChatSql.T_Chat_Message(); cusmsg.F_FromUser = cussend.Code; cusmsg.F_ToUser = serreceive.Code; cusmsg.F_Message = msg.msg; cusmsg.F_IP = ip; cusmsg.F_SourceType = 1; cusmsg.F_MessageType = 1; cusmsg.F_State = 0; cusmsg.F_IsDelete = 0; cusmsg.F_CreateTime = DateTime.Now; cusmsg.F_CreateUser = serreceive.Code; cs.AddMsg(cusmsg); } else { //ChatClass.Message newmsg = new ChatClass.Message(); //newmsg.action = "CusSendError"; //newmsg.msg = "发送失败"; //session.Send(JsonConvert.SerializeObject(newmsg)); msg.state = 0; msg.msg = "发送失败"; } } } else { msg.state = 0; msg.msg = "发送失败"; } } else { msg.state = 0; msg.msg = ConfigurationManager.AppSettings["black"]; } #endregion break; case "loglist": #region 聊天记录 int count = Int32.Parse(ConfigurationManager.AppSettings["pagenumer"]); long num = 0; long.TryParse(msg.msg, out num); int isfirst = 0; var dt = cs.GetChatLog(msg.code, out num, out isfirst, count, num); var obj = new { rows = dt, num = num, isfirst = isfirst }; msg.data = obj; #endregion break; case "serconn": #region 客服连接 var serconn = Servicers.Where(p => p.Code == msg.code).FirstOrDefault(); if (serconn == null) { ChatClass.Servicer svc = new ChatClass.Servicer(); svc.SessionID = session.SessionID; svc.Code = msg.code; svc.Name = cs.GetUserName(msg.code); svc.Count = 0; svc.State = 1; Servicers.Add(svc); session.Send(JsonConvert.SerializeObject(msg)); if (Servicers.Count == 1) { foreach (var cuson in Customers) { cuson.ServicerSessionID= session.SessionID; ChatClass.Message newmsg = new ChatClass.Message(); newmsg.action = "serreceive"; newmsg.msg = cuson.Name + " 上线"; newmsg.code = cuson.Code; newmsg.name = cuson.Name; newmsg.data = cuson.IPData; newmsg.state = 0; SendMsgToRemotePoint(session.SessionID, newmsg);//向客服发送客户上线通知 } } if (!cs.IsExitIP(ip, msg.code)) { #region IP记录 //string ipinfojson = ChatCommon.HttpGet(ConfigurationManager.AppSettings["ipurl"] + "?ip=" + ip); //var ipinfos = JsonConvert.DeserializeObject(ipinfojson); //var ipinfo = JsonConvert.DeserializeObject(ipinfos["data"].ToString()); ChatSql.T_Chat_IPList ipmodel = new ChatSql.T_Chat_IPList(); ipmodel.F_IP = ip; ipmodel.F_OpenId = msg.code; ipmodel.F_Type = 1; //ipmodel.F_Country = ipinfo["country"].ToString(); //ipmodel.F_CountryCode = ipinfo["country_id"].ToString(); //ipmodel.F_Area = ipinfo["area"].ToString(); //ipmodel.F_AreaCode = ipinfo["area_id"].ToString(); //ipmodel.F_Region = ipinfo["region"].ToString(); //ipmodel.F_RegionCode = ipinfo["region_id"].ToString(); //ipmodel.F_City = ipinfo["city"].ToString(); //ipmodel.F_CityCode = ipinfo["city_id"].ToString(); //ipmodel.F_County = ipinfo["county"].ToString(); //ipmodel.F_CountyCode = ipinfo["county_id"].ToString(); //ipmodel.F_ISP = ipinfo["isp"].ToString(); //ipmodel.F_ISPCode = ipinfo["isp_id"].ToString(); ipmodel.F_CreateTime = DateTime.Now; cs.AddIP(ipmodel); #endregion } #region 签入时间 ChatSql.T_Chat_InOut inoutmodel = new ChatSql.T_Chat_InOut(); inoutmodel.F_OpenId = msg.code; inoutmodel.F_IP = ip; inoutmodel.F_Type = 1; inoutmodel.F_InTime = DateTime.Now; cs.AddInOut(inoutmodel); #endregion } else { //ChatClass.Message newmsg = new ChatClass.Message(); //newmsg.action = "SerConnError"; //newmsg.msg = "此工号已经存在"; //session.Send(JsonConvert.SerializeObject(newmsg)); msg.state = 0; msg.msg = "此工号已经存在"; session.Send(JsonConvert.SerializeObject(msg)); } #endregion break; case "sersend": #region 客服发送消息 var cusreceive = Customers.Where(p => p.Code == msg.code).FirstOrDefault(); if (cusreceive != null) { var sersend = Servicers.Where(p => p.SessionID == session.SessionID).FirstOrDefault(); ChatClass.Message recmsg = new ChatClass.Message(); recmsg.action = "cusreceive"; recmsg.msg = msg.msg; recmsg.code = sersend.Code; recmsg.name = sersend.Name; recmsg.headimgurl = sersend.HeadImgUrl; if (SendMsgToRemotePoint(cusreceive.SessionID, recmsg)) { ChatSql.T_Chat_Message sermsg = new ChatSql.T_Chat_Message(); sermsg.F_FromUser = sersend.Code; sermsg.F_ToUser = cusreceive.Code; sermsg.F_Message = msg.msg; sermsg.F_IP = ip; sermsg.F_SourceType = 1; sermsg.F_MessageType = 1; sermsg.F_State = 0; sermsg.F_IsDelete = 0; sermsg.F_CreateTime = DateTime.Now; sermsg.F_CreateUser = sersend.Code; cs.AddMsg(sermsg); } else { //ChatClass.Message newmsg = new ChatClass.Message(); //newmsg.action = "SerSendError"; //newmsg.msg = "发送失败"; //session.Send(JsonConvert.SerializeObject(newmsg)); msg.state = 0; msg.msg = "发送失败"; } } else { //ChatClass.Message newmsg = new ChatClass.Message(); //newmsg.action = "SerSendError"; //newmsg.msg = "客户已下线"; //session.Send(JsonConvert.SerializeObject(newmsg)); msg.state = 0; msg.msg = "客户已下线"; } #endregion break; case "cusmass": #region 群发客户 var cusss = Customers; if (!string.IsNullOrEmpty(msg.code)) { cusss = Customers.Where(p => msg.code.Split(',').Contains(p.Code)).ToList(); } foreach (var cuss in cusss) { ChatClass.Message recmsg = new ChatClass.Message(); recmsg.action = "cusreceive"; recmsg.msg = msg.msg; recmsg.code = cuss.Code; recmsg.name = cuss.Name; recmsg.headimgurl = cuss.HeadImgUrl; recmsg.state = 0; if (SendMsgToRemotePoint(cuss.SessionID, recmsg)) { //ChatSql.T_Chat_Message sermsg = new ChatSql.T_Chat_Message(); //sermsg.F_FromUser = msg.code; //sermsg.F_ToUser = cuss.Code; //sermsg.F_Message = msg.msg; //sermsg.F_IP = session.RemoteEndPoint.Address.ToString(); //sermsg.F_SourceType = 1; //sermsg.F_MessageType = 1; //sermsg.F_State = 0; //sermsg.F_IsDelete = 0; //sermsg.F_CreateTime = DateTime.Now; //sermsg.F_CreateUser = msg.code; //cs.AddMsg(sermsg); } } #endregion break; case "sermass": #region 群发客服 var serss = Servicers; if (!string.IsNullOrEmpty(msg.code)) { serss = Servicers.Where(p => msg.code.Split(',').Contains(p.Code)).ToList(); } foreach (var sers in serss) { ChatClass.Message recmsg = new ChatClass.Message(); recmsg.action = "serreceive"; recmsg.msg = msg.msg; recmsg.code = sers.Code; recmsg.name = sers.Name; recmsg.headimgurl = sers.HeadImgUrl; recmsg.state = 0; if (SendMsgToRemotePoint(sers.SessionID, recmsg)) { //ChatSql.T_Chat_Message sermsg = new ChatSql.T_Chat_Message(); //sermsg.F_FromUser = msg.code; //sermsg.F_ToUser = sers.Code; //sermsg.F_Message = msg.msg; //sermsg.F_IP = session.RemoteEndPoint.Address.ToString(); //sermsg.F_SourceType = 1; //sermsg.F_MessageType = 1; //sermsg.F_State = 0; //sermsg.F_IsDelete = 0; //sermsg.F_CreateTime = DateTime.Now; //sermsg.F_CreateUser = msg.code; //cs.AddMsg(sermsg); } } #endregion break; case "custran": #region 转移客户 var scus = Customers.Where(p => p.Code == msg.code).FirstOrDefault(); var tser = Servicers.Where(p => p.Code == msg.data.ToString()).FirstOrDefault(); if (scus == null) { msg.state = 0; msg.msg = "客户已下线,不能转移"; } if (tser == null) { msg.state = 0; msg.msg = "客服已下线,不能转移"; } if (tser.State == 0) { msg.state = 0; msg.msg = "客服已置忙,不能转移"; } if (scus != null && tser != null && tser.State == 1) { var yser = Servicers.Where(p => p.SessionID==session.SessionID).FirstOrDefault(); scus.ServicerSessionID = tser.SessionID; yser.Count = yser.Count - 1; tser.Count = tser.Count + 1; ChatClass.Message newmsg = new ChatClass.Message(); newmsg.action = "serreceive"; newmsg.msg = yser.Name + " 转移给你 " + scus.Name; newmsg.code = scus.Code; newmsg.name = scus.Name; newmsg.state = 0; SendMsgToRemotePoint(scus.ServicerSessionID, newmsg);//向客服发送客户转移通知 } #endregion break; case "serbusy"://客服置忙 Servicers.Where(p => p.Code == msg.code).FirstOrDefault().State = 0; break; case "serfree"://客服置闲 Servicers.Where(p => p.Code == msg.code).FirstOrDefault().State = 1; break; case "cuslist"://当前在线客户 msg.data = Customers; break; case "serlist"://当前在线客服 msg.data = Servicers; break; } if (msg.action.ToLower() != "serconn") { msg.time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); session.Send(JsonConvert.SerializeObject(msg)); } } catch { try { ChatClass.Message msg = JsonConvert.DeserializeObject(value); msg.state = 0; msg.msg = "操作失败"; msg.time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); session.Send(JsonConvert.SerializeObject(msg)); } catch { session.Send(value); } } } /// /// 会话关闭 /// /// /// private void server_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value) { var ses = Customers.Where(p => p.SessionID == session.SessionID).FirstOrDefault(); if (ses != null) { Customers.Remove(ses); //Customers = Customers.Where(p => p.SessionID != session.SessionID).ToList(); ChatClass.Message msg = new ChatClass.Message(); msg.action = "serreceive"; msg.code = ses.Code; msg.name = ses.Name; msg.state = 0; msg.msg = ses.Name+" 下线"; SendMsgToRemotePoint(ses.ServicerSessionID, msg); cs.UpdateOutTime(ses.Code); } else { var ses1 = Servicers.Where(p => p.SessionID == session.SessionID).FirstOrDefault(); if (ses1 != null) { Servicers.Remove(ses1); Servicers = Servicers.Where(p => p.SessionID != session.SessionID).ToList(); int sercon = Servicers.Count; var cuss = Customers.Where(p => p.ServicerSessionID == session.SessionID); foreach (var cus in cuss) { if (sercon > 0) { cus.ServicerSessionID = SplitCustomer(cus); ChatClass.Message newmsg = new ChatClass.Message(); newmsg.action = "serreceive"; newmsg.msg = ses1.Name + " 下线," + cus.Name + " 转移给你"; newmsg.code = cus.Code; newmsg.name = cus.Name; newmsg.state = 0; SendMsgToRemotePoint(cus.ServicerSessionID, newmsg);//向客服发送客户转移通知 } else { cus.ServicerSessionID = ""; } } cs.UpdateOutTime(ses1.Code); } } server.Logger.Info(string.Format("会话关闭,关闭原因:{0} 来自:{1} SessionID:{2} 时间:{3:HH:MM:ss}", value, session.RemoteEndPoint, session.SessionID, DateTime.Now)); } /// /// 新的会话链接 /// /// private void server_NewSessionConnected(WebSocketSession session) { server.Logger.Info(string.Format("新的会话连接 来自:{0} SessionID:{1} 时间:{2:HH:MM:ss}", session.RemoteEndPoint, session.SessionID, DateTime.Now)); } /// /// 发送消息到 /// /// /// private bool SendMsgToRemotePoint(string sessionId, ChatClass.Message newmsg) { newmsg.time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string msg = JsonConvert.SerializeObject(newmsg); bool bl = false; var selsession = server.GetSessionByID(sessionId); if (selsession != null) { selsession.Send(msg); bl = true; } return bl; } /// /// 发送消息到客户 /// /// 为空全部发送,多个用逗号隔开 /// private void SendMsgToCustomer(string codes, ChatClass.Message newmsg) { newmsg.time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string msg = JsonConvert.SerializeObject(newmsg); var cuss = Customers; if (!string.IsNullOrEmpty(codes)) { cuss = Customers.Where(p => codes.Split(',').Contains(p.Code)).ToList(); } foreach (var cus in cuss) { var selsession = server.GetSessionByID(cus.SessionID); if (selsession != null) { selsession.Send(msg); } } } /// /// 发送消息到客服 /// /// 为空全部发送,多个用逗号隔开 /// private void SendMsgToServicer(string codes, ChatClass.Message newmsg) { newmsg.time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string msg = JsonConvert.SerializeObject(newmsg); var sers = Servicers; if (!string.IsNullOrEmpty(codes)) { sers = Servicers.Where(p => codes.Split(',').Contains(p.Code)).ToList(); } foreach (var ser in sers) { var selsession = server.GetSessionByID(ser.SessionID); if (selsession != null) { selsession.Send(msg); } } } /// /// 分配客户给客服 /// /// /// private string SplitCustomer(ChatClass.Customer cussend) { var cususer = cs.GetCusUser(cussend.Code);//获取是否存在此客户 ChatClass.Servicer SerFirst = Servicers.Where(p => p.State == 1).OrderBy(p => p.Count).FirstOrDefault();//获取当前在线客服的用户量最少的一个 if (string.IsNullOrEmpty(cususer.F_MainUserCode)) { cususer.F_MainUserCode = SerFirst.Code; cs.UpdateUser(cususer);//此次负责的客服更新到主要负责客服里面 } else { var mser = Servicers.Where(p => p.Code == cususer.F_MainUserCode && p.State==1).FirstOrDefault();//获取此客户的主要负责客服是否在线 if (mser != null) { SerFirst = mser; } else//主要负责客服不在线 { var oser = Servicers.Where(p => cususer.F_OtherUserCode.Split(',').Contains(p.Code) && p.State == 1).FirstOrDefault();//获取此客户的次要负责客服是否在线 if (oser != null) { SerFirst = mser; } else//次要负责客服不在线 { string ouc = cususer.F_OtherUserCode; if (string.IsNullOrEmpty(ouc)) { cususer.F_OtherUserCode = ouc; } else { cususer.F_OtherUserCode = ouc + "," + SerFirst.Code; } cs.UpdateUser(cususer);//此次负责的客服更新到次要负责客服里面 } } } SerFirst.Count = SerFirst.Count + 1; return SerFirst.SessionID; } } }