using System.Linq; using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; using Content.Shared.DeviceNetwork.Events; using Content.Shared._Sunrise.Messenger; namespace Content.Server._Sunrise.Messenger; /// /// Часть системы мессенджера, отвечающая за обработку сообщений /// public sealed partial class MessengerServerSystem { private void HandleSendMessage(EntityUid uid, MessengerServerComponent component, DeviceNetworkPacketEvent args) { if (!args.Data.TryGetValue(MessengerCommands.CmdSendMessage, out NetworkPayload? messageData)) return; if (!messageData.TryGetValue("content", out string? content)) return; string? imagePath = null; if (messageData.TryGetValue("image_path", out string? imgPath) && !string.IsNullOrWhiteSpace(imgPath)) { imagePath = imgPath; } if (string.IsNullOrWhiteSpace(content) && string.IsNullOrWhiteSpace(imagePath)) return; if (!component.Users.TryGetValue(args.SenderAddress, out var sender)) return; UpdateUserInfoFromPda(uid, component, args.SenderAddress, sender); var timestamp = GetStationTime(); if (messageData.TryGetValue("group_id", out string? groupId) && !string.IsNullOrWhiteSpace(groupId)) { SendGroupMessage(uid, component, sender, groupId, content, timestamp, imagePath); } else if (messageData.TryGetValue("recipient_id", out string? recipientId) && !string.IsNullOrWhiteSpace(recipientId)) { SendPersonalMessage(uid, component, sender, recipientId, content, timestamp, imagePath); } } private void SendPersonalMessage(EntityUid uid, MessengerServerComponent component, MessengerUser sender, string recipientId, string content, TimeSpan timestamp, string? imagePath = null) { if (!component.Users.ContainsKey(recipientId)) return; var messageId = GetNextMessageId(uid, component); var message = new MessengerMessage(sender.UserId, sender.Name, content, timestamp, null, recipientId, isRead: false, messageId, sender.JobIconId, imagePath); var chatId = GetPersonalChatId(sender.UserId, recipientId); if (!component.MessageHistory.TryGetValue(chatId, out var history)) { history = new List(); component.MessageHistory[chatId] = history; } history.Add(message); TrimMessageHistory(history, component.MaxMessageHistory); var isChatOpen = component.OpenChats.TryGetValue(recipientId, out var openChatId) && openChatId == chatId; if (isChatOpen) { message.IsRead = true; } else { if (!component.UnreadCounts.TryGetValue(recipientId, out var recipientUnreads)) { recipientUnreads = new Dictionary(); component.UnreadCounts[recipientId] = recipientUnreads; } recipientUnreads.TryGetValue(chatId, out var currentCount); recipientUnreads[chatId] = currentCount + 1; } if (!TryComp(uid, out var serverDevice)) return; uint? pdaFrequency = null; if (_prototypeManager.TryIndex(component.PdaFrequencyId, out var pdaFreq)) { pdaFrequency = pdaFreq.Frequency; } var payload = new NetworkPayload { [DeviceNetworkConstants.Command] = MessengerCommands.CmdMessageReceived, ["sender_id"] = message.SenderId, ["sender_name"] = message.SenderName, ["content"] = message.Content, ["timestamp"] = message.Timestamp.TotalSeconds, ["group_id"] = message.GroupId ?? string.Empty, ["recipient_id"] = message.RecipientId ?? string.Empty, ["is_read"] = message.IsRead, ["message_id"] = message.MessageId, ["sender_job_icon_id"] = message.SenderJobIconId?.Id ?? string.Empty, ["image_path"] = message.ImagePath ?? string.Empty }; if (pdaFrequency.HasValue) { _deviceNetwork.QueuePacket(uid, recipientId, payload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); _deviceNetwork.QueuePacket(uid, sender.UserId, payload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); } else { _deviceNetwork.QueuePacket(uid, recipientId, payload); _deviceNetwork.QueuePacket(uid, sender.UserId, payload); } if (isChatOpen && pdaFrequency.HasValue) { var updatePayload = new NetworkPayload { [DeviceNetworkConstants.Command] = MessengerCommands.CmdMessagesList, ["messages"] = new List> { new () { ["sender_id"] = message.SenderId, ["sender_name"] = message.SenderName, ["content"] = message.Content, ["timestamp"] = message.Timestamp.TotalSeconds, ["group_id"] = message.GroupId ?? string.Empty, ["recipient_id"] = message.RecipientId ?? string.Empty, ["is_read"] = message.IsRead, ["message_id"] = message.MessageId, ["sender_job_icon_id"] = message.SenderJobIconId?.Id ?? string.Empty, ["image_path"] = message.ImagePath ?? string.Empty } }, ["chat_id"] = chatId }; _deviceNetwork.QueuePacket(uid, sender.UserId, updatePayload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); } } private void SendGroupMessage(EntityUid uid, MessengerServerComponent component, MessengerUser sender, string groupId, string content, TimeSpan timestamp, string? imagePath = null) { if (!component.Groups.TryGetValue(groupId, out var group)) return; if (!group.Members.Contains(sender.UserId)) return; var messageId = GetNextMessageId(uid, component); var message = new MessengerMessage(sender.UserId, sender.Name, content, timestamp, groupId, null, false, messageId, sender.JobIconId, imagePath); if (!component.MessageHistory.TryGetValue(groupId, out var history)) { history = new List(); component.MessageHistory[groupId] = history; } history.Add(message); TrimMessageHistory(history, component.MaxMessageHistory); if (!TryComp(uid, out var serverDevice)) return; uint? pdaFrequency = null; if (_prototypeManager.TryIndex(component.PdaFrequencyId, out var pdaFreq)) { pdaFrequency = pdaFreq.Frequency; } foreach (var memberId in group.Members) { if (memberId == sender.UserId) continue; var isMemberChatOpen = component.OpenChats.TryGetValue(memberId, out var memberOpenChatId) && memberOpenChatId == groupId; if (!isMemberChatOpen) { if (!component.UnreadCounts.TryGetValue(memberId, out var memberUnreads)) { memberUnreads = new Dictionary(); component.UnreadCounts[memberId] = memberUnreads; } memberUnreads.TryGetValue(groupId, out var currentCount); memberUnreads[groupId] = currentCount + 1; } } var payload = new NetworkPayload { [DeviceNetworkConstants.Command] = MessengerCommands.CmdMessageReceived, ["sender_id"] = message.SenderId, ["sender_name"] = message.SenderName, ["content"] = message.Content, ["timestamp"] = message.Timestamp.TotalSeconds, ["group_id"] = message.GroupId ?? string.Empty, ["recipient_id"] = message.RecipientId ?? string.Empty, ["is_read"] = message.IsRead, ["message_id"] = message.MessageId, ["sender_job_icon_id"] = message.SenderJobIconId?.Id ?? string.Empty, ["image_path"] = message.ImagePath ?? string.Empty }; foreach (var memberId in group.Members) { if (pdaFrequency.HasValue) { _deviceNetwork.QueuePacket(uid, memberId, payload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); } else { _deviceNetwork.QueuePacket(uid, memberId, payload); } } } /// /// Отправляет личное сообщение с изображением (используется PhotoCartridgeSystem) /// public void SendPersonalMessageWithImage(EntityUid uid, string senderUserId, string recipientId, string content, string imagePath, TimeSpan timestamp) { if (!TryComp(uid, out var component)) return; if (!component.Users.TryGetValue(senderUserId, out var sender)) return; SendPersonalMessage(uid, component, sender, recipientId, content, timestamp, imagePath); } /// /// Отправляет групповое сообщение с изображением (используется PhotoCartridgeSystem) /// public void SendGroupMessageWithImage(EntityUid uid, string senderUserId, string groupId, string content, string imagePath, TimeSpan timestamp) { if (!TryComp(uid, out var component)) return; if (!component.Users.TryGetValue(senderUserId, out var sender)) return; SendGroupMessage(uid, component, sender, groupId, content, timestamp, imagePath); } /// /// Отправляет системное сообщение в группу (используется для оповещений департаментов) /// public void SendSystemMessageToGroup(EntityUid uid, string groupId, string content) { if (!TryComp(uid, out var component)) return; if (!component.Groups.TryGetValue(groupId, out var group)) return; var timestamp = GetStationTime(); var messageId = GetNextMessageId(uid, component); var senderName = Loc.GetString("messenger-system-name"); var message = new MessengerMessage("system", senderName, content, timestamp, groupId, null, false, messageId); if (!component.MessageHistory.TryGetValue(groupId, out var history)) { history = new List(); component.MessageHistory[groupId] = history; } history.Add(message); TrimMessageHistory(history, component.MaxMessageHistory); if (!TryComp(uid, out var serverDevice)) return; uint? pdaFrequency = null; if (_prototypeManager.TryIndex(component.PdaFrequencyId, out var pdaFreq)) { pdaFrequency = pdaFreq.Frequency; } var payload = new NetworkPayload { [DeviceNetworkConstants.Command] = MessengerCommands.CmdMessageReceived, ["sender_id"] = message.SenderId, ["sender_name"] = message.SenderName, ["content"] = message.Content, ["timestamp"] = message.Timestamp.TotalSeconds, ["group_id"] = message.GroupId ?? string.Empty, ["recipient_id"] = message.RecipientId ?? string.Empty, ["is_read"] = message.IsRead, ["message_id"] = message.MessageId, ["sender_job_icon_id"] = string.Empty, ["image_path"] = string.Empty }; foreach (var memberId in group.Members) { var isMemberChatOpen = component.OpenChats.TryGetValue(memberId, out var memberOpenChatId) && memberOpenChatId == groupId; if (!isMemberChatOpen) { if (!component.UnreadCounts.TryGetValue(memberId, out var memberUnreads)) { memberUnreads = new Dictionary(); component.UnreadCounts[memberId] = memberUnreads; } memberUnreads.TryGetValue(groupId, out var currentCount); memberUnreads[groupId] = currentCount + 1; } if (pdaFrequency.HasValue) { _deviceNetwork.QueuePacket(uid, memberId, payload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); } else { _deviceNetwork.QueuePacket(uid, memberId, payload); } } } /// /// Обрабатывает удаление сообщения пользователем /// private void HandleDeleteMessage(EntityUid uid, MessengerServerComponent component, DeviceNetworkPacketEvent args) { if (!args.Data.TryGetValue(MessengerCommands.CmdDeleteMessage, out NetworkPayload? deleteData)) return; if (!deleteData.TryGetValue("message_id", out object? messageIdObj) || !deleteData.TryGetValue("chat_id", out string? chatId)) return; if (!long.TryParse(messageIdObj?.ToString(), out var messageId)) return; if (!component.Users.TryGetValue(args.SenderAddress, out var user)) return; if (!component.MessageHistory.TryGetValue(chatId, out var history)) return; var message = history.FirstOrDefault(m => m.MessageId == messageId); if (message == null) return; if (message.SenderId != user.UserId) return; history.Remove(message); if (!TryComp(uid, out var serverDevice)) return; uint? pdaFrequency = null; if (_prototypeManager.TryIndex(component.PdaFrequencyId, out var pdaFreq)) { pdaFrequency = pdaFreq.Frequency; } var recipients = new HashSet(); if (chatId.StartsWith("personal_")) { var parts = chatId.Split('_'); if (parts.Length >= 3) { recipients.Add(parts[1]); recipients.Add(parts[2]); } } else { if (component.Groups.TryGetValue(chatId, out var group)) { foreach (var memberId in group.Members) { recipients.Add(memberId); } } } var deletePayload = new NetworkPayload { [DeviceNetworkConstants.Command] = MessengerCommands.CmdMessageDeleted, ["message_id"] = messageId, ["chat_id"] = chatId }; foreach (var recipientId in recipients) { if (pdaFrequency.HasValue) { _deviceNetwork.QueuePacket(uid, recipientId, deletePayload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); } else { _deviceNetwork.QueuePacket(uid, recipientId, deletePayload); } } } /// /// Sends a fake message to a specific user (used for spam). /// public void SendFakePersonalMessage(EntityUid uid, string recipientId, string senderId, string senderName, string content) { if (!TryComp(uid, out var component)) return; if (!component.Users.ContainsKey(recipientId)) return; var timestamp = GetStationTime(); var messageId = GetNextMessageId(uid, component); var message = new MessengerMessage(senderId, senderName, content, timestamp, null, recipientId, isRead: false, messageId); var chatId = GetPersonalChatId(senderId, recipientId); if (!component.MessageHistory.TryGetValue(chatId, out var history)) { history = new List(); component.MessageHistory[chatId] = history; } history.Add(message); TrimMessageHistory(history, component.MaxMessageHistory); var isChatOpen = component.OpenChats.TryGetValue(recipientId, out var openChatId) && openChatId == chatId; if (isChatOpen) { message.IsRead = true; } else { if (!component.UnreadCounts.TryGetValue(recipientId, out var recipientUnreads)) { recipientUnreads = new Dictionary(); component.UnreadCounts[recipientId] = recipientUnreads; } recipientUnreads.TryGetValue(chatId, out var currentCount); recipientUnreads[chatId] = currentCount + 1; } if (!TryComp(uid, out var serverDevice)) return; uint? pdaFrequency = null; if (_prototypeManager.TryIndex(component.PdaFrequencyId, out var pdaFreq)) { pdaFrequency = pdaFreq.Frequency; } var payload = new NetworkPayload { [DeviceNetworkConstants.Command] = MessengerCommands.CmdMessageReceived, ["sender_id"] = message.SenderId, ["sender_name"] = message.SenderName, ["content"] = message.Content, ["timestamp"] = message.Timestamp.TotalSeconds, ["group_id"] = message.GroupId ?? string.Empty, ["recipient_id"] = message.RecipientId ?? string.Empty, ["is_read"] = message.IsRead, ["message_id"] = message.MessageId, ["sender_job_icon_id"] = string.Empty, ["image_path"] = string.Empty }; if (pdaFrequency.HasValue) { _deviceNetwork.QueuePacket(uid, recipientId, payload, frequency: pdaFrequency, network: serverDevice.DeviceNetId); } else { _deviceNetwork.QueuePacket(uid, recipientId, payload); } } }