/// <summary> /// Broadcasts a <see cref="ChatMessagePacket"/> to all currently logged-in users. /// </summary> /// <param name="senderUuid">Sender's UUID</param> /// <param name="messageId">Message ID</param> /// <param name="message">Message content</param> /// <param name="timestamp">Timestamp</param> /// <param name="excludedConnectionIds">Array of connection IDs to be excluded from the broadcast</param> private void broadcastChatMessage(string senderUuid, string messageId, string message, DateTime timestamp, string[] excludedConnectionIds = null) { // Create and pack a ChatMessagePacket ChatMessagePacket packet = new ChatMessagePacket { Uuid = senderUuid, MessageId = messageId, Message = message, Timestamp = timestamp.ToTimestamp() }; Any packedPacket = ProtobufPacketHelper.Pack(packet); // Get an array of connection IDs for each logged in user string[] connectionIds = userManager.GetConnections(); // Remove the connection IDs to be excluded from the broadcast (if any) if (excludedConnectionIds != null) { connectionIds = connectionIds.Except(excludedConnectionIds).ToArray(); } // Send it to each of the remaining connection IDs foreach (string connectionId in connectionIds) { // Try send the chat message if (!netServer.TrySend(connectionId, MODULE_NAME, packedPacket.ToByteArray())) { RaiseLogEntry(new LogEventArgs("Failed to send ChatMessagePacket to connection " + connectionId.Highlight(HighlightType.ConnectionID), LogLevel.ERROR)); } } }
/// <summary> /// Handles incoming <see cref="ChatMessagePacket"/>s. /// </summary> /// <param name="connectionId">Original connection ID</param> /// <param name="packet">Incoming packet</param> private void chatMessagePacketHandler(string connectionId, ChatMessagePacket packet) { lock (messageHistoryLock) { // Store the message in chat history messageHistory.Add(new ClientChatMessage(packet.MessageId, packet.Uuid, packet.Message, packet.Timestamp.ToDateTime(), ChatMessageStatus.CONFIRMED)); } OnChatMessageReceived?.Invoke(this, new ChatMessageEventArgs(packet.Message, packet.Uuid, packet.Timestamp.ToDateTime())); }
/// <summary> /// Sends a message to the chat. /// </summary> /// <param name="message">Message</param> /// <exception cref="ArgumentException">Message cannot be null or empty</exception> public void Send(string message) { if (string.IsNullOrEmpty(message)) { throw new ArgumentException("Message cannot be null or empty", nameof(message)); } // Check if we aren't authenticated if (!authenticator.Authenticated) { RaiseLogEntry(new LogEventArgs("Cannot send chat message: Not authenticated")); return; } // Check if we aren't logged in if (!userManager.LoggedIn) { RaiseLogEntry(new LogEventArgs("Cannot send chat message: Not logged in")); return; } // Create a random message ID string messageId = Guid.NewGuid().ToString(); // Create and store a chat message locally ClientChatMessage localMessage = new ClientChatMessage(messageId, userManager.Uuid, message); lock (messageHistoryLock) { messageHistory.Add(localMessage); } // Create and pack the chat message packet ChatMessagePacket packet = new ChatMessagePacket { SessionId = authenticator.SessionId, Uuid = userManager.Uuid, MessageId = messageId, Message = message }; Any packedPacket = ProtobufPacketHelper.Pack(packet); // Send it on its way netClient.Send(MODULE_NAME, packedPacket.ToByteArray()); }
/// <summary> /// Sends a <see cref="ChatMessagePacket"/> to the user. /// </summary> /// <param name="connectionId">Destination connection ID</param> /// <param name="senderUuid">Sender's UUID</param> /// <param name="messageId">Message ID</param> /// <param name="message">Message content</param> /// <param name="timestamp">Timestamp</param> private void sendChatMessage(string connectionId, string senderUuid, string messageId, string message, DateTime timestamp) { // Create and pack our chat message packet ChatMessagePacket packet = new ChatMessagePacket { MessageId = messageId, Uuid = senderUuid, Message = message, Timestamp = timestamp.ToTimestamp() }; Any packedPacket = ProtobufPacketHelper.Pack(packet); // Send it on its way if (!netServer.TrySend(connectionId, MODULE_NAME, packedPacket.ToByteArray())) { RaiseLogEntry(new LogEventArgs("Failed to send ChatMessagePacket to connection " + connectionId.Highlight(HighlightType.ConnectionID), LogLevel.ERROR)); } }
/// <summary> /// Handles incoming <see cref="ChatMessagePacket"/>s. /// </summary> /// <param name="connectionId">Original connection ID</param> /// <param name="packet">Incoming <see cref="ChatMessagePacket"/></param> private void chatMessagePacketHandler(string connectionId, ChatMessagePacket packet) { // Refuse packets from non-authenticated sessions if (!authenticator.IsAuthenticated(connectionId, packet.SessionId)) { sendFailedChatMessageResponse(connectionId, packet.MessageId); // Stop here return; } // Refuse packets from non-logged in users if (!userManager.IsLoggedIn(connectionId, packet.Uuid)) { sendFailedChatMessageResponse(connectionId, packet.MessageId); // Stop here return; } // Get a copy of the packet's original message ID string originalMessageId = packet.MessageId; // Generate a new, guaranteed-to-be-unique message ID since we can't trust clients string newMessageId = Guid.NewGuid().ToString(); // Sanitise the message content string sanitisedMessage = TextHelper.SanitiseRichText(packet.Message); // Get the current time DateTime timestamp = DateTime.UtcNow; // Add the message to the message history addMessageToHistory(new ChatMessage(newMessageId, packet.Uuid, sanitisedMessage, timestamp)); // Send a response to the sender sendChatMessageResponse(connectionId, true, originalMessageId, newMessageId, sanitisedMessage); // Broadcast the chat packet to everyone but the sender broadcastChatMessage(packet.Uuid, newMessageId, sanitisedMessage, timestamp, new[] { connectionId }); }