From a935d1860cc2e8170b0a0164281d77e437238711 Mon Sep 17 00:00:00 2001 From: skibitsky Date: Tue, 20 Aug 2024 13:36:16 +0300 Subject: [PATCH 1/3] Handle incoming requests one by one --- .../Controllers/TypedMessageHandler.cs | 123 +++++++++++++++--- .../MessageHandler/TypedEventHandler.cs | 1 - .../Models/SessionRequestEventHandler.cs | 1 - 3 files changed, 102 insertions(+), 23 deletions(-) diff --git a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs index cf8ef1c..cfebd6e 100644 --- a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs +++ b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs @@ -1,8 +1,7 @@ -using System.Security.Cryptography; -using System.Text; +using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; using WalletConnectSharp.Common.Events; -using WalletConnectSharp.Common.Model.Errors; +using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; using WalletConnectSharp.Core.Models; @@ -15,12 +14,19 @@ namespace WalletConnectSharp.Core.Controllers { public class TypedMessageHandler : ITypedMessageHandler { - private bool _initialized = false; - private Dictionary _decodeOptionsMap = new Dictionary(); - private HashSet _typeSafeCache = new HashSet(); + private bool _initialized; + private bool _isRequestQueueProcessing; + + private readonly Dictionary _decodeOptionsMap = new(); + + private readonly HashSet _typeSafeCache = []; + + // private readonly EventHandlerMap _messageEventHandlerMap = new(); + private readonly Queue<(string method, MessageEvent messageEvent)> _requestQueue = new(); + private readonly Dictionary>> _requestCallbacksMap = new(); + private readonly Dictionary>> _responseCallbacksMap = new(); public event EventHandler RawMessage; - private EventHandlerMap messageEventHandlerMap = new(); protected bool Disposed; @@ -57,24 +63,26 @@ public Task Init() { if (!_initialized) { - this.Core.Relayer.OnMessageReceived += RelayerMessageCallback; + Core.Relayer.OnMessageReceived += RelayMessageCallback; } _initialized = true; return Task.CompletedTask; } - async void RelayerMessageCallback(object sender, MessageEvent e) + private async void RelayMessageCallback(object sender, MessageEvent e) { var topic = e.Topic; var message = e.Message; + var options = DecodeOptionForTopic(topic); var payload = await this.Core.Crypto.Decode(topic, message, options); if (payload.IsRequest) { - messageEventHandlerMap[$"request_{payload.Method}"](this, e); + _requestQueue.Enqueue((payload.Method, e)); + await ProcessRequestQueue(); } else if (payload.IsResponse) { @@ -83,6 +91,56 @@ async void RelayerMessageCallback(object sender, MessageEvent e) } } + private async Task ProcessRequestQueue() + { + if (_isRequestQueueProcessing) + { + return; + } + + _isRequestQueueProcessing = true; + + WCLogger.Log($"Processing request queue with {_requestQueue.Count} items."); + + var methods = ""; + foreach (var (method, _) in _requestQueue) + { + methods += method + ", "; + } + + WCLogger.Log($"Queue methods: [{methods}]"); + + try + { + while (_requestQueue.Count > 0) + { + var (method, messageEvent) = _requestQueue.Dequeue(); + if (!_requestCallbacksMap.TryGetValue(method, out var callbacks)) + { + continue; + } + + foreach (var callback in callbacks) + { + try + { + await callback(messageEvent); + } + catch (Exception e) + { + WCLogger.LogError(e); + } + + WCLogger.Log($"Request callback for method {method} processed"); + } + } + } + finally + { + _isRequestQueueProcessing = false; + } + } + /// /// Handle a specific request / response type and call the given callbacks for requests and responses. The /// response callback is only triggered when it originates from the request of the same type. @@ -97,7 +155,7 @@ public async Task HandleMessageType(Func(); var rpcHistory = await this.Core.History.JsonRpcHistoryOfType(); - async void RequestCallback(object sender, MessageEvent e) + async Task RequestCallback(MessageEvent e) { try { @@ -128,7 +186,7 @@ async void RequestCallback(object sender, MessageEvent e) } } - async void ResponseCallback(object sender, MessageEvent e) + async void ResponseCallback(MessageEvent e) { if (responseCallback == null || Disposed) { @@ -184,15 +242,36 @@ record = await rpcHistory.Get(topic, payload.Id); var resMethod = record.Request.Method; // Trigger the true response event, which will trigger ResponseCallback - messageEventHandlerMap[$"response_{resMethod}"](this, - new MessageEvent + + if (_responseCallbacksMap.TryGetValue(resMethod, out var callbacks)) + { + var callbacksCopy = callbacks.ToList(); + foreach (var callback in callbacksCopy) { - Topic = topic, Message = message - }); + callback(new MessageEvent + { + Topic = topic, Message = message + }); + } + } + } + + if (!_requestCallbacksMap.TryGetValue(method, out var requestCallbacks)) + { + requestCallbacks = []; + _requestCallbacksMap.Add(method, requestCallbacks); + } + + requestCallbacks.Add(RequestCallback); + + + if (!_responseCallbacksMap.TryGetValue(method, out var responseCallbacks)) + { + responseCallbacks = []; + _responseCallbacksMap.Add(method, responseCallbacks); } - messageEventHandlerMap[$"request_{method}"] += RequestCallback; - messageEventHandlerMap[$"response_{method}"] += ResponseCallback; + responseCallbacks.Add(ResponseCallback); // Handle response_raw in this context // This will allow us to examine response_raw in every typed context registered @@ -202,8 +281,10 @@ record = await rpcHistory.Get(topic, payload.Id); { this.RawMessage -= InspectResponseRaw; - messageEventHandlerMap[$"request_{method}"] -= RequestCallback; - messageEventHandlerMap[$"response_{method}"] -= ResponseCallback; + // TODO: dispose maps + + // _messageEventHandlerMap[$"request_{method}"] -= RequestCallback; + // _messageEventHandlerMap[$"response_{method}"] -= ResponseCallback; }); } @@ -429,7 +510,7 @@ protected virtual void Dispose(bool disposing) if (disposing) { - this.Core.Relayer.OnMessageReceived -= RelayerMessageCallback; + Core.Relayer.OnMessageReceived -= RelayMessageCallback; } Disposed = true; diff --git a/WalletConnectSharp.Core/Models/MessageHandler/TypedEventHandler.cs b/WalletConnectSharp.Core/Models/MessageHandler/TypedEventHandler.cs index c9da69c..3a16633 100644 --- a/WalletConnectSharp.Core/Models/MessageHandler/TypedEventHandler.cs +++ b/WalletConnectSharp.Core/Models/MessageHandler/TypedEventHandler.cs @@ -218,7 +218,6 @@ protected virtual async void Teardown() protected virtual Task ResponseCallback(string arg1, JsonRpcResponse arg2) { - WCLogger.Log($"Got generic response for type {typeof(TR)}"); var rea = new ResponseEventArgs(arg2, arg1); return ResponsePredicate != null && !ResponsePredicate(rea) ? Task.CompletedTask : _onResponse != null ? _onResponse(rea) : Task.CompletedTask; diff --git a/WalletConnectSharp.Sign/Models/SessionRequestEventHandler.cs b/WalletConnectSharp.Sign/Models/SessionRequestEventHandler.cs index 91e1ec3..841e27a 100644 --- a/WalletConnectSharp.Sign/Models/SessionRequestEventHandler.cs +++ b/WalletConnectSharp.Sign/Models/SessionRequestEventHandler.cs @@ -75,7 +75,6 @@ protected override void Setup() private Task WrappedRefOnOnResponse(ResponseEventArgs e) { - WCLogger.Log($"Got response for type {typeof(TR)}"); return base.ResponseCallback(e.Topic, e.Response); } From b595dce95ee432504a6ffe43b8bae8bec9422939 Mon Sep 17 00:00:00 2001 From: skibitsky Date: Wed, 28 Aug 2024 10:27:35 +0300 Subject: [PATCH 2/3] Cleanup --- .../Controllers/TypedMessageHandler.cs | 14 +------------- WalletConnectSharp.Sign/Internals/EngineHandler.cs | 4 ++-- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs index cfebd6e..ce428ec 100644 --- a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs +++ b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs @@ -99,17 +99,7 @@ private async Task ProcessRequestQueue() } _isRequestQueueProcessing = true; - - WCLogger.Log($"Processing request queue with {_requestQueue.Count} items."); - - var methods = ""; - foreach (var (method, _) in _requestQueue) - { - methods += method + ", "; - } - - WCLogger.Log($"Queue methods: [{methods}]"); - + try { while (_requestQueue.Count > 0) @@ -130,8 +120,6 @@ private async Task ProcessRequestQueue() { WCLogger.LogError(e); } - - WCLogger.Log($"Request callback for method {method} processed"); } } } diff --git a/WalletConnectSharp.Sign/Internals/EngineHandler.cs b/WalletConnectSharp.Sign/Internals/EngineHandler.cs index 8cd2ac9..f48d0a5 100644 --- a/WalletConnectSharp.Sign/Internals/EngineHandler.cs +++ b/WalletConnectSharp.Sign/Internals/EngineHandler.cs @@ -342,8 +342,8 @@ async Task IEnginePrivate.OnSessionEventRequest(string topic, JsonRpcRequest>, bool>(id, topic, true); From af11113e09883695a3769b68256984e5af319d67 Mon Sep 17 00:00:00 2001 From: skibitsky Date: Thu, 29 Aug 2024 14:49:46 +0300 Subject: [PATCH 3/3] Remove callbacks on dispose --- .../Controllers/TypedMessageHandler.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs index ce428ec..a32ea5f 100644 --- a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs +++ b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs @@ -1,6 +1,4 @@ -using System.Diagnostics.CodeAnalysis; -using Newtonsoft.Json; -using WalletConnectSharp.Common.Events; +using Newtonsoft.Json; using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; @@ -21,7 +19,6 @@ public class TypedMessageHandler : ITypedMessageHandler private readonly HashSet _typeSafeCache = []; - // private readonly EventHandlerMap _messageEventHandlerMap = new(); private readonly Queue<(string method, MessageEvent messageEvent)> _requestQueue = new(); private readonly Dictionary>> _requestCallbacksMap = new(); private readonly Dictionary>> _responseCallbacksMap = new(); @@ -269,10 +266,8 @@ record = await rpcHistory.Get(topic, payload.Id); { this.RawMessage -= InspectResponseRaw; - // TODO: dispose maps - - // _messageEventHandlerMap[$"request_{method}"] -= RequestCallback; - // _messageEventHandlerMap[$"response_{method}"] -= ResponseCallback; + _requestCallbacksMap[method].Remove(RequestCallback); + _responseCallbacksMap[method].Remove(ResponseCallback); }); }