From 23204dfecbdb0f7141eeadc1024dd98c8f1aaa5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sierpi=C5=84ski?= Date: Fri, 12 Apr 2024 16:26:58 +0200 Subject: [PATCH] Reduce memory allocations (#144) --- .../StreamChat/Core/Helpers/ICollectionExt.cs | 18 ++++++++++++++++++ .../InternalDTO/Models/APIErrorInternalDTO.cs | 9 --------- .../Core/LowLevelClient/Models/APIError.cs | 1 - .../LowLevelClient/StreamChatLowLevelClient.cs | 7 +++++-- .../Core/StatefulModels/StreamChannel.cs | 15 +++++++++------ Assets/Plugins/StreamChat/Core/WSEventType.cs | 1 + 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/Assets/Plugins/StreamChat/Core/Helpers/ICollectionExt.cs b/Assets/Plugins/StreamChat/Core/Helpers/ICollectionExt.cs index b7eacc82..f865ab17 100644 --- a/Assets/Plugins/StreamChat/Core/Helpers/ICollectionExt.cs +++ b/Assets/Plugins/StreamChat/Core/Helpers/ICollectionExt.cs @@ -10,6 +10,24 @@ namespace StreamChat.Core.Helpers /// internal static class ICollectionExt { + + /// + /// In Unity 2019.4.40f1 List.Contains allocates memory. Use this allocation free alternative + /// + [Pure] + public static bool ContainsNoAlloc(this List source, TItem item) + { + for (var i = 0; i < source.Count; i++) + { + if (EqualityComparer.Default.Equals(source[i], item)) + { + return true; + } + } + + return false; + } + [Pure] public static List TrySaveToDtoCollection(this List source) where TSource : ISavableTo diff --git a/Assets/Plugins/StreamChat/Core/InternalDTO/Models/APIErrorInternalDTO.cs b/Assets/Plugins/StreamChat/Core/InternalDTO/Models/APIErrorInternalDTO.cs index 8095614d..3f4049c7 100644 --- a/Assets/Plugins/StreamChat/Core/InternalDTO/Models/APIErrorInternalDTO.cs +++ b/Assets/Plugins/StreamChat/Core/InternalDTO/Models/APIErrorInternalDTO.cs @@ -58,15 +58,6 @@ internal partial class APIErrorInternalDTO [Newtonsoft.Json.JsonProperty("more_info", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] public string MoreInfo { get; set; } - private System.Collections.Generic.Dictionary _additionalProperties = new System.Collections.Generic.Dictionary(); - - [Newtonsoft.Json.JsonExtensionData] - public System.Collections.Generic.Dictionary AdditionalProperties - { - get { return _additionalProperties; } - set { _additionalProperties = value; } - } - } } diff --git a/Assets/Plugins/StreamChat/Core/LowLevelClient/Models/APIError.cs b/Assets/Plugins/StreamChat/Core/LowLevelClient/Models/APIError.cs index a5b95be0..09533784 100644 --- a/Assets/Plugins/StreamChat/Core/LowLevelClient/Models/APIError.cs +++ b/Assets/Plugins/StreamChat/Core/LowLevelClient/Models/APIError.cs @@ -86,7 +86,6 @@ APIError ILoadableFrom.LoadFromDto(APIErrorIntern ExceptionFields = dto.ExceptionFields; Message = dto.Message; MoreInfo = dto.MoreInfo; - AdditionalProperties = dto.AdditionalProperties; return this; } diff --git a/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs b/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs index 1e697bbd..73a060b1 100644 --- a/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs +++ b/Assets/Plugins/StreamChat/Core/LowLevelClient/StreamChatLowLevelClient.cs @@ -790,8 +790,11 @@ private void HandleNewWebsocketMessage(string msg) return; } - var time = DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss"); - EventReceived?.Invoke($"{time} - Event received: {type}"); + if (EventReceived != null) + { + var time = DateTime.Now.TimeOfDay.ToString(@"hh\:mm\:ss"); + EventReceived.Invoke($"{time} - Event received: {type}"); + } if (!_eventKeyToHandler.TryGetValue(type, out var handler)) { diff --git a/Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs b/Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs index e435a071..7044cfc4 100644 --- a/Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs +++ b/Assets/Plugins/StreamChat/Core/StatefulModels/StreamChannel.cs @@ -193,6 +193,9 @@ public async Task SendNewMessageAsync(StreamSendMessageRequest s var response = await LowLevelClient.InternalMessageApi.SendNewMessageAsync(Type, Id, sendMessageRequest.TrySaveToDto()); + + //StreamTodo: we update internal cache message without server confirmation that message got accepted. e.g. message could be rejected + //It's ok to update the cache "in good faith" to not introduce update delay but we should handle if message got rejected var streamMessage = InternalAppendOrUpdateMessage(response.Message); return streamMessage; } @@ -757,7 +760,7 @@ internal void HandleChannelTruncatedEvent(NotificationChannelTruncatedEventInter internal void InternalAddMember(StreamChannelMember member) { - if (_members.Contains(member)) + if (_members.ContainsNoAlloc(member)) { return; } @@ -769,7 +772,7 @@ internal void InternalAddMember(StreamChannelMember member) internal void InternalRemoveMember(StreamChannelMember member) { - if (!_members.Contains(member)) + if (!_members.ContainsNoAlloc(member)) { return; } @@ -781,7 +784,7 @@ internal void InternalRemoveMember(StreamChannelMember member) internal void InternalUpdateMember(StreamChannelMember member) { - if (!_members.Contains(member)) + if (!_members.ContainsNoAlloc(member)) { _members.Add(member); } @@ -822,7 +825,7 @@ private StreamMessage InternalAppendOrUpdateMessage(MessageInternalDTO dto) var streamMessage = Cache.TryCreateOrUpdate(dto, out var wasCreated); if (wasCreated) { - if (!_messages.Contains(streamMessage)) + if (!_messages.ContainsNoAlloc(streamMessage)) { _messages.Add(streamMessage); MessageReceived?.Invoke(this, streamMessage); @@ -959,7 +962,7 @@ internal void InternalHandleUserWatchingStartEvent(UserWatchingStartEventInterna AssertCid(eventDto.Cid); var user = Cache.TryCreateOrUpdate(eventDto.User, out var wasCreated); - if (wasCreated || !_watchers.Contains(user)) + if (wasCreated || !_watchers.ContainsNoAlloc(user)) { WatcherCount += 1; _watchers.Add(user); @@ -1010,7 +1013,7 @@ internal void InternalHandleTypingStarted(TypingStartEventInternalDTO eventDto) var user = Cache.TryCreateOrUpdate(eventDto.User); StreamAsserts.AssertNotNull(user, nameof(user)); - if (!_typingUsers.Contains(user)) + if (!_typingUsers.ContainsNoAlloc(user)) { _typingUsers.Add(user); UserStartedTyping?.Invoke(this, user); diff --git a/Assets/Plugins/StreamChat/Core/WSEventType.cs b/Assets/Plugins/StreamChat/Core/WSEventType.cs index 70934988..e0fec87e 100644 --- a/Assets/Plugins/StreamChat/Core/WSEventType.cs +++ b/Assets/Plugins/StreamChat/Core/WSEventType.cs @@ -41,5 +41,6 @@ internal static class WSEventType public const string NotificationRemovedFromChannel = "notification.removed_from_channel"; public const string NotificationMutesUpdated = "notification.mutes_updated"; public const string NotificationChannelMutesUpdated = "notification.channel_mutes_updated"; + //StreamTodo: implement NOTIFICATION.MARK_UNREAD } } \ No newline at end of file