public ActionResult UpdateReadState(string accesstoken, string msg_uids) { //先验证访问权限 var userid = IMRedisDAL.GetUserIdByAccessToken(accesstoken); if (!String.IsNullOrEmpty(msg_uids)) { var msg_uid_list = msg_uids.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var redis_msgpost = new FaceHand.Common.ResdisExecutor(RedisConfig.REDIS_MSGPOST_KEY); redis_msgpost.Exec(db => { var chatMsgList = new List <Dictionary <string, string> >(); //更新整体的未读消息数量 var batch = db.CreateBatch(); foreach (string msg_uid in msg_uid_list) { var readtime = db.SortedSetScore($"readtime_{msg_uid}", userid); if (!readtime.HasValue) { //从未读消息列表中移除 batch.SortedSetRemoveAsync($"notreadlist_{userid}", msg_uid, CommandFlags.FireAndForget); //更新未读消息统计计数 var msg = IMRedisDAL.GetMsg(msg_uid); var msgtype_str = msg.GetStringValue(RedisFields.MSG_TYPE); if (!String.IsNullOrEmpty(msgtype_str)) { var count_rv = db.HashGet($"notreadcount_{userid}", msgtype_str); if (count_rv.HasValue && !count_rv.IsNullOrEmpty) { long count_lng = 0; if (count_rv.TryParse(out count_lng)) { if (count_lng > 0) { batch.HashDecrementAsync($"notreadcount_{userid}", msgtype_str, 1, CommandFlags.FireAndForget); } else { batch.HashSetAsync($"notreadcount_{userid}", msgtype_str, 0); } } } //如果是聊天消息,更新聊天消息的阅读情况 var msgtype_int = Convert.ToInt32(msgtype_str); if (msgtype_int < 60) { chatMsgList.Add(msg); } } //更新阅读时间 batch.SortedSetAddAsync($"readtime_{msg_uid}", new SortedSetEntry[] { new SortedSetEntry(userid, DateTime.Now.AsUnixTimestamp()) }, CommandFlags.FireAndForget); } } batch.Execute(); //更新聊天消息和接收者之间的的未读数量 if (chatMsgList.Count > 0) { var batch2 = db.CreateBatch(); foreach (var msg in chatMsgList) { var msg_senderid = msg.GetStringValue(RedisFields.MSG_SEND_USERID); var receivers = msg.GetStringValue(RedisFields.MSG_SUCCESS_RECEIVERS); if (!String.IsNullOrEmpty(receivers)) { var receivers_list = receivers.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (var receiver_userid in receivers_list) { var k = $"chatnotreadcount_{msg_senderid}_{receiver_userid}"; var count_rv = db.Execute("get", k); if (count_rv.HasValue() && !count_rv.IsNull && !count_rv.IsEmpty()) { //这个key必须大于0才执行递减操作 //否则不变 if (count_rv.AsInt() > 0) { batch2.ExecuteAsync("DECRBY", k, 1); } else { batch2.ExecuteAsync("set", k, 0); } } else { //这个key还不存在 batch2.ExecuteAsync("set", k, 0); } } } } batch2.Execute(); } }); } return(JsonContent(true)); }
//投送消息 private static void SendMsg(string msg_uid, bool isRemoveFromMQ) { //获取消息以验证消息的有效性 var msg = IMRedisDAL.GetMsg(msg_uid); if (msg == null || msg.Count == 0) { throw new BusinessException($"message {msg_uid} not found"); } var state = msg.GetStringValue(RedisFields.MSG_STATE).AsEnum <MsgSendState>(); if (state != MsgSendState.Sending) { //消息ID被取到,但是又不是正在发送的状态 //说明消息已被其它进程处理,这时应该从消息队列中删除这个ID var redis_msmq = new FaceHand.Common.ResdisExecutor(RedisConfig.REDIS_MSGMQ_KEY); redis_msmq.Exec(db => db.ListRemove(MessageSendStateQueue.SENDING, msg_uid, 0, CommandFlags.FireAndForget)); } else { //验证接收人,把有效的人和无效的人分离出来 var receiver_valid = new List <string>(); var receiver_invalid = new List <string>(); ValidateReceiver(msg[RedisFields.MSG_RECEIVERS], ref receiver_valid, ref receiver_invalid); //没有有效接收人,消息发送失败 if (receiver_valid.Count == 0) { //更新消息发送状态为失败 FaceHand.Common.ResdisExecutor.ExecCommand(db => db.HashSet($"msg_{msg_uid}", new HashEntry[] { //更新发送失败的人 new HashEntry(RedisFields.MSG_FAILED_RECEIVERS, String.Join(",", receiver_invalid)), //更新消息发送状态 new HashEntry(RedisFields.MSG_STATE, (int)MsgSendState.Failed), //更新消息发送状态 new HashEntry(RedisFields.MSG_ERROR_MSG, "available receivers count is zero") }, CommandFlags.FireAndForget), RedisConfig.REDIS_MSGCACHE_KEY); //从队列中删除消息 if (isRemoveFromMQ) { var redis_msmq = new FaceHand.Common.ResdisExecutor(RedisConfig.REDIS_MSGMQ_KEY); redis_msmq.Exec(db => db.ListRemove(MessageSendStateQueue.SENDING, msg_uid, 0, CommandFlags.FireAndForget)); } //抛出错误,以便控制台能看到发送失败 throw new BusinessException($"available receivers count is zero"); } else { //投送消息 var redis_msgpost = new FaceHand.Common.ResdisExecutor(RedisConfig.REDIS_MSGPOST_KEY); redis_msgpost.Exec(db => { var batch = db.CreateBatch(); var msg_sendtime = msg.GetStringValue(RedisFields.MSG_SEND_TIME).AsLong(); var msg_senderid = msg.GetStringValue(RedisFields.MSG_SEND_USERID); var msg_type = (int)msg.GetStringValue(RedisFields.MSG_TYPE).AsEnum <MsgType>(); var isChatMsg = msg_type < 60; var now = DateTime.Now; var nowUnixTimestmp = now.AsUnixTimestamp(); foreach (var receiver_userid in receiver_valid) { //更新未读消息数,未读消息数按消息类型分别存 batch.HashIncrementAsync($"notreadcount_{receiver_userid}", msg[RedisFields.MSG_TYPE], 1D, CommandFlags.FireAndForget); //将消息ID放入对应人的未读消息清单 batch.SortedSetAddAsync($"notreadlist_{receiver_userid}", msg_uid, nowUnixTimestmp, When.Always, CommandFlags.FireAndForget); //单独统计聊天消息的数量 if (isChatMsg) { var chatnotreadcount_k = $"chatnotreadcount_{msg_senderid}_{receiver_userid}"; var chatnotreadcount = db.Execute("GET", chatnotreadcount_k).AsInt(); if (chatnotreadcount < 0) { batch.ExecuteAsync("SET", 1); } else { batch.ExecuteAsync("INCRBY", chatnotreadcount_k, 1D); } } } batch.Execute(); }); //更新消息发送状态 FaceHand.Common.ResdisExecutor.ExecCommand(db => db.HashSet($"msg_{msg_uid}", new HashEntry[] { //更新发送成功的人 new HashEntry(RedisFields.MSG_SUCCESS_RECEIVERS, String.Join(",", receiver_valid)), //更新发送失败的人 new HashEntry(RedisFields.MSG_FAILED_RECEIVERS, String.Join(",", receiver_invalid)), //更新消息发送状态 new HashEntry(RedisFields.MSG_STATE, (int)MsgSendState.Success) }, CommandFlags.FireAndForget), RedisConfig.REDIS_MSGCACHE_KEY); var redis_msmq = new FaceHand.Common.ResdisExecutor(RedisConfig.REDIS_MSGMQ_KEY); //从队列中删除消息 if (isRemoveFromMQ) { redis_msmq.Exec(db => db.ListRemove(MessageSendStateQueue.SENDING, msg_uid, 0, CommandFlags.FireAndForget)); } //通过订阅器通知客户端有新消息 if (receiver_valid.Count > 0) { Task.Factory.StartNew(() => { try { redis_msmq.Exec(db => db.Publish( RedisChannelName.NEW_MESSAGE_CHANNEL_TOCLIENT, $"{msg_uid},{String.Join(",", receiver_valid)}", //通知client manager CommandFlags.FireAndForget)); } catch (Exception ex) { WriteErrorLog($"notify {msg_uid} to client failed. {ex.Message}"); } }); } //将消息持久化到数据库 Task.Factory.StartNew(() => { try { using (var context = new DataContext(MysqlDbConfig.IMCONN)) { IMMySqlDAL.Instance.InsertMsg(msg, receiver_valid); } } catch (Exception ex) { WriteErrorLog($"save message {msg_uid} to database failed. {ex.Message}"); } }); //如果是应用消息,还要考虑是否通知到企业微信端 if (msg[RedisFields.MSG_TYPE].AsEnum <MsgType>() == MsgType.system_app) { } WriteLog($"post message success。msg_uid:{msg_uid}"); } } }