using System; using System.Security.Cryptography.X509Certificates; using Microsoft.EntityFrameworkCore; using sodoff.Model; using sodoff.Schema; using sodoff.Util; using ZstdSharp.Unsafe; namespace sodoff.Services; public class MessagingService { private readonly DBContext ctx; private readonly MMOClientService mMOClientService; public MessagingService(DBContext ctx, MMOClientService mMOClientService) { this.ctx = ctx; this.mMOClientService = mMOClientService; } public Model.Message AddMessageToViking(Viking? viking, Viking toViking, MessageType messageType, MessageTypeID messageTypeID, MessageLevel messageLevel, string data, string memberMessage = "", string nonMemberMessage = "", bool IsNew = true, bool IsDeleted = false, bool isReply = false, bool isPrivate = false, int parentMessageId = 0) { // get execution UTC timestamp DateTime now = DateTime.UtcNow; // for generating ConversationId and QueueId Random rnd = new Random(); // construct message Model.Message message = new Model.Message { ToViking = toViking, ToVikingId = toViking.Id, QueueID = rnd.Next(1000, 9999), ConversationID = rnd.Next(1000, 9999), MessageType = messageType, MessageTypeID = messageTypeID, MessageLevel = messageLevel, Data = data, MemberMessage = memberMessage, NonMemberMessage = nonMemberMessage, CreatedAt = now, LastUpdatedAt = now, IsDeleted = IsDeleted, IsNew = IsNew, IsPrivate = isPrivate }; if (viking == null) { message.Viking = null; message.VikingId = null; } else { message.Viking = viking; message.VikingId = viking.Id; } if (isReply && parentMessageId > 0) { // get message this is in reply to Model.Message? messageToReplyTo = ctx.Messages.FirstOrDefault(e => e.Id == parentMessageId); if (messageToReplyTo != null) { message.ParentMessage = messageToReplyTo; message.ParentMessageId = messageToReplyTo.Id; message.ConversationID = messageToReplyTo.ConversationID; // add a message to the replier's board saying a thread update has occured (if reply isn't to self) if (message.VikingId != message.ToVikingId) AddMessageToViking(message.Viking, message.ToViking, MessageType.Data, MessageTypeID.ThreadUpdate, MessageLevel.WhiteList, "[[Line1]]=[[{{BuddyUserName}} Replied To Your Message In {{BuddyUserName}}'s Message Board!]]", "[[Line1]]=[[{{BuddyUserName}} Replied To Your Message In {{BuddyUserName}}'s Message Board!]]", "[[Line1]]=[[{{BuddyUserName}} Replied To Your Message In {{BuddyUserName}}'s Message Board!]]", isPrivate: true); } else throw new InvalidOperationException("Tried To Reply To A Message That Doesn't Exist"); } // add message to database ctx.Messages.Add(message); ctx.SaveChanges(); // update receiving users messages mMOClientService.SendCommandToUser(toViking.Uid.ToString(), "SPMN", new string[] { "SPMN" }); mMOClientService.SendCommandToUser(toViking.Uid.ToString(), "NMP", new string[] { "NMP", "-1", "1", "1" }); // return constructed message return message; } public void RemoveMessage(int id) { // find message Model.Message? message = ctx.Messages.FirstOrDefault(e => e.Id == id); if (message != null) { // remove it ctx.Messages.Remove(message); ctx.SaveChanges(); } else throw new InvalidOperationException("Tried To Delete A Message That Doesn't Exist"); } public Model.Message? UpdateMessageByQueueID(int queueId, bool isNew, bool IsDeleted) { // get execution UTC timestamp DateTime now = DateTime.UtcNow; // find message Model.Message? message = ctx.Messages.FirstOrDefault(e => e.QueueID == queueId); if (message != null) { // set params (TODO - figure out what else the clients update in messages) message.IsNew = isNew; message.IsDeleted = IsDeleted; message.LastUpdatedAt = now; ctx.SaveChanges(); return message; } else return null; } public ArrayOfCombinedListMessage ConstructCombinedMessageArray(Viking viking, Viking publicViking) { // get all messages in viking board List messages = ctx.Messages.Where(e => e.ToVikingId == publicViking.Id).ToList(); List combinedListMessages = new List(); ArrayOfCombinedListMessage response = new ArrayOfCombinedListMessage(); foreach(var message in messages) { if (message.IsDeleted) { ctx.Messages.Remove(message); continue; } if (message.IsPrivate && (viking.Id != publicViking.Id) || message.VikingId == -1) continue; Viking? msgAuthor = ctx.Vikings.FirstOrDefault(e => e.Id == message.VikingId) ?? new Viking(); // construct a CombinedListMessage based on Model.Message CombinedListMessage clm = new CombinedListMessage { MessageType = (int?)message.MessageType ?? 0, MessageDate = message.CreatedAt }; // if type id is messaging, use Schema.Message, otherwise treat it as Schema.MessageInfo if (message.MessageTypeID == MessageTypeID.Messaging) { clm.MessageBody = XmlUtil.SerializeXml(new Schema.Message { MessageID = message.Id, ConversationID = message.ConversationID ?? 0, ReplyToMessageID = message.ParentMessageId, Creator = msgAuthor.Uid.ToString() ?? new Guid().ToString(), CreateTime = message.CreatedAt, UpdateDate = message.LastUpdatedAt, MessageType = message.MessageType.Value, MessageLevel = message.MessageLevel, Content = message.Data ?? "No Data Found In This Message. This Might Be An Error.", DisplayAttribute = "C=White" // still having it always white :) }); } else if (message.Data.StartsWith("(message.Data); string data = ""; List pairList = new List(); for(int i = 0; i < arrayOfKVP.KeyValuePairOfStringString.Length; i++) { pairList.Add(arrayOfKVP.KeyValuePairOfStringString[i]); } foreach(KeyValuePairOfStringString pair in pairList) { data = data + $"[[{pair.Key}]]=[[{pair.Value}]]"; } clm.MessageBody = XmlUtil.SerializeXml(new MessageInfo { UserMessageQueueID = message.QueueID, MessageID = message.Id, MessageTypeID = (int?)message.MessageTypeID, FromUserID = msgAuthor.Uid.ToString() ?? new Guid().ToString(), MemberMessage = message.MemberMessage ?? "NoData", NonMemberMessage = message.NonMemberMessage ?? "NoData", Data = data }); } else { clm.MessageBody = XmlUtil.SerializeXml(new MessageInfo { UserMessageQueueID = message.QueueID, MessageID = message.Id, MessageTypeID = (int?)message.MessageTypeID, FromUserID = msgAuthor.Uid.ToString() ?? new Guid().ToString(), MemberMessage = message.MemberMessage ?? "NoData", NonMemberMessage = message.NonMemberMessage ?? "NoData", Data = message.Data }); } // add clm to list combinedListMessages.Add(clm); // ensure all replies are included in response foreach(var reply in message.Replies) { Viking? replyAuthor = ctx.Vikings.FirstOrDefault(e => e.Id == reply.VikingId) ?? new Viking(); CombinedListMessage clmReply = new CombinedListMessage { MessageType = (int)reply.MessageType, MessageBody = XmlUtil.SerializeXml(new Schema.Message { MessageID = reply.Id, ConversationID = reply.ConversationID ?? 0, ReplyToMessageID = reply.ParentMessageId, Creator = replyAuthor.Uid.ToString() ?? new Guid().ToString(), CreateTime = reply.CreatedAt, UpdateDate = reply.LastUpdatedAt, MessageType = reply.MessageType.Value, MessageLevel = reply.MessageLevel, Content = reply.Data ?? "No Data Found In This Message. This Might Be An Error.", DisplayAttribute = "C=White" // still having it always white :) }), MessageDate = reply.CreatedAt }; combinedListMessages.Add(clmReply); } } // save any changes made to db ctx.SaveChanges(); // reverse list combinedListMessages.Reverse(); // add list as array to response response.CombinedListMessage = combinedListMessages.ToArray(); // return response return response; } public ArrayOfMessageInfo ConstructUserMessageInfoArray(Viking viking, bool showOldMessages, bool showDeletedMessages) { // get execution UTC timestamp DateTime now = DateTime.UtcNow; // get all recent messages List messages = ctx.Messages.Where(e => e.ToVikingId == viking.Id) .OrderBy(e => e.CreatedAt) .OrderBy(e => e.QueueID) .ToList(); List messageInfos = new List(); ArrayOfMessageInfo response = new ArrayOfMessageInfo(); foreach(var message in messages) { Viking? msgAuthor = ctx.Vikings.FirstOrDefault(e => e.Id == message.VikingId) ?? new Viking(); if(message.IsDeleted && !showDeletedMessages) { ctx.Messages.Remove(message); continue; } if(DateTime.Compare(now, message.CreatedAt.AddMinutes(30)) > 0 && !showOldMessages) { message.IsNew = false; continue; } // sometimes clients won't set IsNew flag when updating messages, so do not add messages more than 30 minutes old to response if(!message.IsNew && !showOldMessages) continue; MessageInfo messageInfo = new MessageInfo { MessageID = message.Id, UserMessageQueueID = message.QueueID, FromUserID = msgAuthor.Uid.ToString() ?? new Guid().ToString(), MessageTypeID = (int?)message.MessageTypeID, Data = message.Data ?? "NoData", MemberMessage = message.MemberMessage ?? "NoMessage", NonMemberMessage = message.NonMemberMessage ?? "NoMessage", MemberAudioUrl = "", NonMemberAudioUrl = "", MemberImageUrl = "", NonMemberImageUrl = "" }; messageInfos.Add(messageInfo); } // save any database changes ctx.SaveChanges(); // add list as array to response response.MessageInfo = messageInfos.ToArray(); // return response return response; } }