diff --git a/Core Modules/WalletConnectSharp.Common/Events/EventHandlerMap.cs b/Core Modules/WalletConnectSharp.Common/Events/EventHandlerMap.cs new file mode 100644 index 0000000..7cebe55 --- /dev/null +++ b/Core Modules/WalletConnectSharp.Common/Events/EventHandlerMap.cs @@ -0,0 +1,109 @@ +namespace WalletConnectSharp.Common.Events; + +/// +/// A mapping of eventIds to EventHandler objects. This using a Dictionary as the backing datastore +/// +/// The type of EventHandler's argument to store +public class EventHandlerMap : IDisposable +{ + private Dictionary> mapping = new(); + + private readonly object _mappingLock = new(); + + private EventHandler BeforeEventExecuted; + + /// + /// Create a new EventHandlerMap with an initial EventHandler to append onto + /// + /// The initial EventHandler to use as the EventHandler. + public EventHandlerMap(EventHandler callbackBeforeExecuted = null) + { + if (callbackBeforeExecuted == null) + { + callbackBeforeExecuted = CallbackBeforeExecuted; + } + + this.BeforeEventExecuted = callbackBeforeExecuted; + } + + private void CallbackBeforeExecuted(object sender, TEventArgs e) + { + } + + /// + /// Get an EventHandler by its eventId. If the provided eventId does not exist, then the + /// initial EventHandler is returned and tracking begins + /// + /// The eventId of the EventHandler + public EventHandler this[string eventId] + { + get + { + lock (_mappingLock) + { + mapping.TryAdd(eventId, BeforeEventExecuted); + + return mapping[eventId]; + } + } + set + { + lock (_mappingLock) + { + if (mapping.ContainsKey(eventId)) + { + mapping.Remove(eventId); + } + + mapping.Add(eventId, value); + } + } + } + + public void ListenOnce(string eventId, EventHandler eventHandler) + { + EventHandler internalHandler = null; + internalHandler = (src, args) => + { + this[eventId] -= internalHandler; + eventHandler(src, args); + }; + this[eventId] += internalHandler; + } + + /// + /// Check if a given eventId has any EventHandlers registered yet. + /// + /// The eventId to check for + /// true if the eventId has any EventHandlers, false otherwise + public bool Contains(string eventId) + { + lock (_mappingLock) + { + return mapping.ContainsKey(eventId); + } + } + + /// + /// Clear an eventId from the mapping + /// + /// The eventId to clear + public void Clear(string eventId) + { + lock (_mappingLock) + { + if (mapping.ContainsKey(eventId)) + { + mapping.Remove(eventId); + } + } + } + + public void Dispose() + { + lock (_mappingLock) + { + mapping.Clear(); + } + } +} diff --git a/Core Modules/WalletConnectSharp.Common/Events/GenericEventHolder.cs b/Core Modules/WalletConnectSharp.Common/Events/GenericEventHolder.cs new file mode 100644 index 0000000..70611fb --- /dev/null +++ b/Core Modules/WalletConnectSharp.Common/Events/GenericEventHolder.cs @@ -0,0 +1,19 @@ +namespace WalletConnectSharp.Common.Events; + +public class GenericEventHolder +{ + private Dictionary dynamicTypeMapping = new(); + + public EventHandlerMap OfType() + { + Type t = typeof(T); + + if (dynamicTypeMapping.TryGetValue(t, out var value)) + return (EventHandlerMap)value; + + var mapping = new EventHandlerMap(); + dynamicTypeMapping.Add(t, mapping); + + return mapping; + } +} diff --git a/Core Modules/WalletConnectSharp.Common/Utils/Extensions.cs b/Core Modules/WalletConnectSharp.Common/Utils/Extensions.cs index e7ae344..79e30d2 100644 --- a/Core Modules/WalletConnectSharp.Common/Utils/Extensions.cs +++ b/Core Modules/WalletConnectSharp.Common/Utils/Extensions.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Threading.Tasks; using System.Web; namespace WalletConnectSharp.Common.Utils @@ -108,5 +104,31 @@ public static bool SetEquals(this IEnumerable first, IEnumerable second return new HashSet(second, comparer ?? EqualityComparer.Default) .SetEquals(first); } + + public static Action ListenOnce(this object eventSource, string eventName, EventHandler handler) { + var eventInfo = eventSource.GetType().GetEvent(eventName); + EventHandler internalHandler = null; + internalHandler = (src, args) => { + eventInfo.RemoveEventHandler(eventSource, internalHandler); + handler(src, args); + }; + void RemoveListener() + { + eventInfo.RemoveEventHandler(eventSource, internalHandler); + } + eventInfo.AddEventHandler(eventSource, internalHandler); + + return RemoveListener; + } + + public static void ListenOnce(this object eventSource, string eventName, EventHandler handler) { + var eventInfo = eventSource.GetType().GetEvent(eventName); + EventHandler internalHandler = null; + internalHandler = (src, args) => { + eventInfo.RemoveEventHandler(eventSource, internalHandler); + handler(src, args); + }; + eventInfo.AddEventHandler(eventSource, internalHandler); + } } } diff --git a/Core Modules/WalletConnectSharp.Common/Utils/RpcPayloadId.cs b/Core Modules/WalletConnectSharp.Common/Utils/RpcPayloadId.cs new file mode 100644 index 0000000..947443c --- /dev/null +++ b/Core Modules/WalletConnectSharp.Common/Utils/RpcPayloadId.cs @@ -0,0 +1,22 @@ +namespace WalletConnectSharp.Common.Utils; + +/// +/// A static class that can generate random JSONRPC ids using the current time as a source of randomness +/// +public static class RpcPayloadId +{ + private static readonly Random rng = new Random(); + private static readonly DateTime UnixEpoch = + new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// Generate a new random JSON-RPC id. The clock is used as a source of randomness + /// + /// A random JSON-RPC id + public static long Generate() + { + var date = (long)((DateTime.UtcNow - UnixEpoch).TotalMilliseconds) * (10L * 10L * 10L); + var extra = (long)Math.Floor(rng.NextDouble() * (10.0 * 10.0 * 10.0)); + return date + extra; + } +} diff --git a/Core Modules/WalletConnectSharp.Events/EventDelegator.cs b/Core Modules/WalletConnectSharp.Events/EventDelegator.cs deleted file mode 100644 index 3bef26a..0000000 --- a/Core Modules/WalletConnectSharp.Events/EventDelegator.cs +++ /dev/null @@ -1,293 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Newtonsoft.Json; -using WalletConnectSharp.Common; -using WalletConnectSharp.Common.Logging; -using WalletConnectSharp.Common.Model; -using WalletConnectSharp.Events.Model; - -namespace WalletConnectSharp.Events -{ - /// - /// A class that can delegate the process of both listening for specific events (by their event id) with a static - /// event data type and triggering events (by their event id) with any event data - /// - /// Event listeners subscribe to events by their eventId and by the event data type the event contains. This means - /// event listeners are statically typed and will never receive an event that its callback cannot cast safely - /// (this includes subclasses, interfaces and object). - /// - public class EventDelegator : IModule - { - private static readonly object _contextLock = new object(); - private static HashSet contextInstances = new HashSet(); - - private readonly object _cacheLock = new object(); - private Dictionary _typeToTriggerTypes = new Dictionary(); - - public string Name { get; private set; } - public string Context { get; private set; } - - /// - /// Create a new EventDelegator. This will create an isolated module - /// as a context for all event listeners - /// - public EventDelegator() : this(new IsolatedModule()) - { - } - - /// - /// Create a new EventDelegator, using a module's context to store - /// all event listeners - /// - /// The module to grab context from - /// If this module's context is already being used by EventDelegator - public EventDelegator(IModule parent) - { - this.Name = parent + ":event-delegator"; - this.Context = parent.Context; - - lock (_contextLock) - { - if (contextInstances.Contains(Context)) - throw new ArgumentException( - $"The module {parent.Name} with context {Context} is attempting to create a new EventDelegator that overlaps with an existing EventDelegator"); - - contextInstances.Add(Context); - } - } - - /// - /// Listen for a given event by it's eventId and trigger the parameter-less callback. This - /// callback will be triggered for all event data types emitted with the eventId given. - /// - /// The eventId of the event to listen to - /// The callback to invoke when the event is triggered - public void ListenFor(string eventId, Action callback) - { - ListenFor(eventId, (sender, @event) => - { - callback(); - }); - } - - /// - /// Listen for a given event by it's eventId and event data type T - /// - /// The eventId of the event to listen to - /// The callback to invoke when the event is triggered - /// The type of event data the callback MUST be given - public void ListenFor(string eventId, EventHandler> callback) - { - EventManager>.InstanceOf(Context).EventTriggers[eventId] += callback; - } - - /// - /// Remove a specific callback that is listening to a specific event by it's eventId and event data type T - /// - /// The eventId of the event to stop listening to - /// The callback that is unsubscribing - /// The type of event data the callback MUST be given - public void RemoveListener(string eventId, EventHandler> callback) - { - EventManager>.InstanceOf(Context).EventTriggers[eventId] -= callback; - } - - /// - /// Listen for a given event by it's eventId and event data type T. When the event is triggered, - /// stop listening for the event. This effectively ensures the callback is only invoked once. - /// - /// The eventId of the event to listen to - /// The callback to invoke when the event is triggered. The callback will only be invoked once. - /// The type of event data the callback MUST be given - public void ListenForOnce(string eventId, EventHandler> callback) - { - EventHandler> wrappedCallback = null; - - wrappedCallback = delegate(object sender, GenericEvent @event) - { - if (callback == null) - return; - RemoveListener(eventId, wrappedCallback); - callback(sender, @event); - callback = null; - }; - - EventManager>.InstanceOf(Context).EventTriggers[eventId] += wrappedCallback; - } - - /// - /// Listen for a given event by it's eventId and for a event data containing a json string. When this event - /// is triggered, the event data containing the json string is deserialized to the given type TR and the eventId - /// is retriggered with the new deserialized event data. - /// - /// The eventId of the event to listen to - /// The callback to invoked with the deserialized event data - /// The desired event data type that MUST be deserialized to - public void ListenForAndDeserialize(string eventId, EventHandler> callback) - { - ListenFor(eventId, callback); - - ListenFor(eventId, delegate(object sender, GenericEvent @event) - { - try - { - //Attempt to Deserialize - var converted = JsonConvert.DeserializeObject(@event.EventData); - - //When we convert, we trigger same eventId with required type TR - Trigger(eventId, converted); - } - catch (Exception e) - { - //Propagate any exceptions to the event callback - Trigger(eventId, e); - } - }); - } - - /// - /// Trigger an event by its eventId, providing a typed event data. This will invoke the registered callbacks - /// of the event listeners listening to this eventId and looking for the given event data type T. This will - /// also trigger event listeners looking for any sub-type of T, such as subclasses or interfaces. - /// - /// This will NOT trigger event listeners looking for any parent type of T. For example, triggering with a - /// type of IMyType will NOT trigger event listeners looking for more concrete types implementing IMyType. - /// - /// The eventId of the event to trigger - /// The event data to trigger the event with - /// Whether to raise an exception if a listener throws an exception. If false, then all exceptions are silenced - /// The type of the event data - /// true if any event listeners were triggered, otherwise false - public bool Trigger(string eventId, T eventData, bool raiseOnException = true) - { - return TriggerType(eventId, eventData, typeof(T), raiseOnException); - } - - /// - /// Trigger an event by its eventId, providing a event data and the type of the eventData. - /// This will invoke the registered callbacks of the event listeners listening to this eventId and looking for - /// the given event data type "typeToTrigger". This will also trigger event listeners looking for any - /// sub-type of the given type "typeToTrigger", such as subclasses or interfaces. - /// - /// This will NOT trigger event listeners looking for any parent type. For example, triggering with a - /// type of IMyType will NOT trigger event listeners looking for more concrete types implementing IMyType. - /// - /// The eventId of the event to trigger - /// The event data to trigger the event with - /// The type of the given event data and the event data type that will be triggered - /// Whether to raise an exception if a listener throws an exception. If false, then all exceptions are silenced - /// true if any event listeners were triggered, otherwise false - public bool TriggerType(string eventId, object eventData, Type typeToTrigger, bool raiseOnException = true) - { - Type[] allPossibleTypes; - bool wasTriggered = false; - - lock (_cacheLock) - { - if (_typeToTriggerTypes.ContainsKey(typeToTrigger)) - allPossibleTypes = _typeToTriggerTypes[typeToTrigger]; - else - { - if (typeToTrigger == typeof(object)) - { - // If the type of object was given, then only - // trigger event listeners listening to the object type explicitly - allPossibleTypes = new[] { typeof(object) }; - } - else - { - //Find all EventFactories that inherit from type T - var inheritedT = from assembly in AppDomain.CurrentDomain.GetAssemblies() - from type in assembly.GetTypes() - where type != typeof(object) && typeToTrigger.IsSubclassOf(type) - select type; - - // Create list of types that include types inherit from type T, type T, and type object - allPossibleTypes = inheritedT.Concat(typeToTrigger.GetInterfaces()).Append(typeToTrigger) - .Append(typeof(object)).Distinct().ToArray(); - } - - _typeToTriggerTypes.Add(typeToTrigger, allPossibleTypes); - } - } - - foreach (var type in allPossibleTypes) - { - var genericFactoryType = typeof(EventFactory<>).MakeGenericType(type); - - var instanceProperty = genericFactoryType.GetMethod("InstanceOf"); - if (instanceProperty == null) continue; - - var genericFactory = instanceProperty.Invoke(null, new object[] { Context }); - - var genericProviderProperty = genericFactoryType.GetProperty("Provider"); - if (genericProviderProperty == null) continue; - - var genericProvider = genericProviderProperty.GetValue(genericFactory); - if (genericProvider == null) continue; - - MethodInfo propagateEventMethod = genericProvider.GetType().GetMethod("PropagateEvent"); - if (propagateEventMethod == null) continue; - - try - { - propagateEventMethod.Invoke(genericProvider, new object[] { eventId, eventData }); - wasTriggered = true; - } - catch (Exception e) - { - WCLogger.LogError(e); - WCLogger.Log($"[EventDelegator] Error Invoking EventFactory<{type.FullName}>.Provider.PropagateEvent({eventId}, {eventData})"); - if (raiseOnException) - throw; - } - } - - return wasTriggered; - } - - public void Dispose() - { - lock (_cacheLock) - { - // loop through all cached types and remove all listeners - foreach (var eventType in _typeToTriggerTypes.Keys) - { - var allPossibleTypes = _typeToTriggerTypes[eventType]; - - // loop through all possible types of an event type, since - // event listeners can be anywhere - foreach (var type in allPossibleTypes) - { - var genericFactoryType = typeof(EventFactory<>).MakeGenericType(type); - - var instanceProperty = genericFactoryType.GetMethod("InstanceOf"); - if (instanceProperty == null) continue; - - var genericFactory = instanceProperty.Invoke(null, new object[] { Context }); - - var genericProviderProperty = genericFactoryType.GetProperty("Provider"); - if (genericProviderProperty == null) continue; - - var genericProvider = genericProviderProperty.GetValue(genericFactory); - if (genericProvider == null) continue; - - // type of IEventProvider is IDisposable - IDisposable disposable = (IDisposable)genericProvider; - - // dispose of this provider - disposable.Dispose(); - } - } - } - - lock (_contextLock) - { - if (contextInstances.Contains(Context)) - contextInstances.Remove(Context); - } - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/EventFactory.cs b/Core Modules/WalletConnectSharp.Events/EventFactory.cs deleted file mode 100644 index 36ee62f..0000000 --- a/Core Modules/WalletConnectSharp.Events/EventFactory.cs +++ /dev/null @@ -1,69 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace WalletConnectSharp.Events -{ - /// - /// A class that simply holds the IEventProvider for a given event data type T. This is needed to keep the - /// different event listeners (same eventId but different event data types) separate at runtime. - /// - /// Event Factories are seperated by context, and a context string must be provided before - /// getting access to an EventFactory. This means events ARE NOT fired between contexts - /// - /// - public class EventFactory - { - private static Dictionary> _eventFactories = new Dictionary>(); - private static readonly object _factoryLock = new object(); - private IEventProvider _eventProvider; - - /// - /// The current context of this EventFactory - /// - public string Context { get; private set; } - - /// - /// Create a new event factory with the given context string - /// - /// The context string to create this factory with - private EventFactory(string context) - { - this.Context = context; - } - - /// - /// Get the EventFactory for the event data type T - /// The context string to use - /// The EventFactory that is isolated in the given context string - /// - public static EventFactory InstanceOf(string context) - { - lock (_factoryLock) - { - if (!_eventFactories.ContainsKey(context)) - _eventFactories.Add(context, new EventFactory(context)); - - return _eventFactories[context]; - } - } - - /// - /// Get the current EventProvider for the event data type T - /// - /// Internally only. When this value is set more than once - public IEventProvider Provider - { - get - { - return _eventProvider; - } - internal set - { - if (_eventProvider != null) - throw new Exception("Provider for type " + typeof(T) + " already set"); - - _eventProvider = value; - } - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/EventHandlerMap.cs b/Core Modules/WalletConnectSharp.Events/EventHandlerMap.cs deleted file mode 100644 index 63fe313..0000000 --- a/Core Modules/WalletConnectSharp.Events/EventHandlerMap.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace WalletConnectSharp.Events -{ - /// - /// A mapping of eventIds to EventHandler objects. This using a Dictionary as the backing datastore - /// - /// The type of EventHandler's argument to store - public class EventHandlerMap : IDisposable - { - private Dictionary> mapping = - new Dictionary>(); - - private readonly object _mappingLock = new object(); - - private EventHandler BeforeEventExecuted; - - /// - /// Create a new EventHandlerMap with an initial EventHandler to append onto - /// - /// The initial EventHandler to use as the EventHandler. - public EventHandlerMap(EventHandler callbackBeforeExecuted) - { - if (callbackBeforeExecuted == null) - { - callbackBeforeExecuted = CallbackBeforeExecuted; - } - - this.BeforeEventExecuted = callbackBeforeExecuted; - } - - private void CallbackBeforeExecuted(object sender, TEventArgs e) - { - } - - /// - /// Get an EventHandler by its eventId. If the provided eventId does not exist, then the - /// initial EventHandler is returned and tracking begins - /// - /// The eventId of the EventHandler - public EventHandler this[string eventId] - { - get - { - lock (_mappingLock) - { - if (!mapping.ContainsKey(eventId)) - { - mapping.Add(eventId, BeforeEventExecuted); - } - - return mapping[eventId]; - } - } - set - { - lock (_mappingLock) - { - if (mapping.ContainsKey(eventId)) - { - mapping.Remove(eventId); - } - - mapping.Add(eventId, value); - } - } - } - - /// - /// Check if a given eventId has any EventHandlers registered yet. - /// - /// The eventId to check for - /// true if the eventId has any EventHandlers, false otherwise - public bool Contains(string eventId) - { - lock (_mappingLock) - { - return mapping.ContainsKey(eventId); - } - } - - /// - /// Clear an eventId from the mapping - /// - /// The eventId to clear - public void Clear(string eventId) - { - lock (_mappingLock) - { - if (mapping.ContainsKey(eventId)) - { - mapping.Remove(eventId); - } - } - } - - public void Dispose() - { - lock (_mappingLock) - { - mapping.Clear(); - } - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/EventManager.cs b/Core Modules/WalletConnectSharp.Events/EventManager.cs deleted file mode 100644 index f867daa..0000000 --- a/Core Modules/WalletConnectSharp.Events/EventManager.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace WalletConnectSharp.Events -{ - /// - /// An EventProvider that triggers any events by their eventId using C# EventHandlers and the EventHandlerMap. - /// Each EventManager is denoted by the event data type T that it handles and the EventHandlers event args type - /// TEventArgs that is triggered. - /// - /// Each EventManager is also isolated inside of their own Context. This means two EventManager that share the same - /// type T and same eventId will NOT share invocations. This means the context string must be given to obtain an - /// EventManager - /// - /// The type of the event data that this EventManager handles - /// The type of the EventHandler's args this EventManager triggers. Must be a type of IEvent - public class EventManager : IEventProvider where TEventArgs : IEvent, new() - { - private static Dictionary> _instances = - new Dictionary>(); - - private static readonly object _managerLock = new object(); - - /// - /// The current EventTriggers this EventManager has - /// - public EventHandlerMap EventTriggers { get; private set; } - - /// - /// The current context of this EventManager - /// - public string Context { get; private set; } - - /// - /// Create a new EventManager with the given context string - /// - /// The context string to give this EventManager - private EventManager(string context) - { - this.Context = context; - - EventTriggers = new EventHandlerMap(CallbackBeforeExecuted); - - EventFactory.InstanceOf(context).Provider = this; - } - - /// - /// Get the current instance of the EventManager for the given type T and TEventArgs. - /// The context to use for the EventManager - /// An EventManager that matches the given type T, TEventArgs and context string - /// - public static EventManager InstanceOf(string context) - { - lock (_managerLock) - { - if (!_instances.ContainsKey(context)) - _instances.Add(context, new EventManager(context)); - - return _instances[context]; - } - } - - private void CallbackBeforeExecuted(object sender, TEventArgs e) - { - } - - /// - /// Trigger an event by its eventId providing event data of a specific type - /// - /// The eventId of the event to trigger - /// The event data to trigger with this event - public void PropagateEvent(string eventId, T eventData) - { - if (EventTriggers.Contains(eventId)) - { - var eventTrigger = EventTriggers[eventId]; - - if (eventTrigger != null) - { - //var response = JsonConvert.DeserializeObject(responseJson); - var eventArgs = new TEventArgs(); - eventArgs.SetData(eventData); - eventTrigger(this, eventArgs); - } - } - } - - public void Dispose() - { - EventTriggers.Dispose(); - lock (_managerLock) - { - if (_instances.ContainsKey(Context)) - _instances.Remove(Context); - } - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/EventsExtensions.cs b/Core Modules/WalletConnectSharp.Events/EventsExtensions.cs deleted file mode 100644 index dcdbe15..0000000 --- a/Core Modules/WalletConnectSharp.Events/EventsExtensions.cs +++ /dev/null @@ -1,87 +0,0 @@ -using WalletConnectSharp.Events.Interfaces; -using WalletConnectSharp.Events.Model; - -namespace WalletConnectSharp.Events -{ - /// - /// Extension methods for any class that implements IEvents. - /// - public static class EventsExtensions - { - /// - /// Listen for an eventId and invoke the given Action. This will trigger for - /// any event data type. - /// - /// The event emitter to use - /// The event id to listen to - /// The callback Action to invoke when the event id (of any type) is triggered - public static IEvents On(this IEvents eventEmitter, string eventId, Action callback) - { - eventEmitter.On(eventId, (sender, @event) => - { - callback(); - }); - - return eventEmitter; - } - - /// - /// Listen for an eventId and invoke the given Action. This will trigger for - /// the given event data type T only. - /// - /// The event emitter to use - /// The event id to listen to - /// The callback Action to invoke when the event id is triggered - /// The type of event data to listen for - public static IEvents On(this IEvents eventEmitter, string eventId, EventHandler> callback) - { - eventEmitter.Events.ListenFor(eventId, callback); - - return eventEmitter; - } - - /// - /// Listen for an eventId and invoke the given Action once. This will trigger for - /// the given event data type T only. - /// - /// The event emitter to use - /// The event id to listen to - /// The callback Action to invoke when the event id is triggered - /// The type of event data to listen for - public static IEvents Once(this IEvents eventEmitter, string eventId, EventHandler> callback) - { - eventEmitter.Events.ListenForOnce(eventId, callback); - - return eventEmitter; - } - - /// - /// Stop listening for an eventId with the given Action. - /// - /// The event emitter to use - /// The event id to stop listening to - /// The callback Action to stop invoking when the event id is triggered - /// The type of event data to stop listening for - public static IEvents Off(this IEvents eventEmitter, string eventId, EventHandler> callback) - { - eventEmitter.Events.RemoveListener(eventId, callback); - - return eventEmitter; - } - - /// - /// Stop listening for an eventId with the given Action. - /// - /// The event emitter to use - /// The event id to stop listening to - /// The callback Action to stop invoking when the event id is triggered - /// The type of event data to stop listening for - public static IEvents RemoveListener(this IEvents eventEmitter, string eventId, - EventHandler> callback) - { - eventEmitter.Events.RemoveListener(eventId, callback); - - return eventEmitter; - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/Interfaces/IEvent.cs b/Core Modules/WalletConnectSharp.Events/Interfaces/IEvent.cs deleted file mode 100644 index 8d14119..0000000 --- a/Core Modules/WalletConnectSharp.Events/Interfaces/IEvent.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace WalletConnectSharp.Events -{ - /// - /// An interface that represents a class that can take in an event's data and store it. The event data - /// is generic and may be anything - /// - /// The type of the event data - public interface IEvent - { - /// - /// Set the data for this event. This is invoked when the event is triggered with the provided - /// data - /// - /// The data the event was triggered with - void SetData(T data); - } -} \ No newline at end of file diff --git a/Core Modules/WalletConnectSharp.Events/Interfaces/IEventProvider.cs b/Core Modules/WalletConnectSharp.Events/Interfaces/IEventProvider.cs deleted file mode 100644 index 7c13d54..0000000 --- a/Core Modules/WalletConnectSharp.Events/Interfaces/IEventProvider.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace WalletConnectSharp.Events -{ - /// - /// An interface that represents a class that can trigger event listeners for a given data type. This - /// provider can trigger any event for a given event data type. - /// - /// The event data type this class triggers events with - public interface IEventProvider : IDisposable - { - /// - /// Trigger the given event (using the event id) with the given event data. - /// - /// The event id to trigger - /// The event data to trigger the event with - void PropagateEvent(string eventId, T eventData); - } -} diff --git a/Core Modules/WalletConnectSharp.Events/Interfaces/IEvents.cs b/Core Modules/WalletConnectSharp.Events/Interfaces/IEvents.cs deleted file mode 100644 index 80b1c8f..0000000 --- a/Core Modules/WalletConnectSharp.Events/Interfaces/IEvents.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using WalletConnectSharp.Events.Model; - -namespace WalletConnectSharp.Events.Interfaces -{ - /// - /// An interface that represents a class that triggers events that can be listened to. - /// - public interface IEvents - { - /// - /// The EventDelegator that should be used to listen to (or trigger) events - /// - EventDelegator Events { get; } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/Model/GenericEvent.cs b/Core Modules/WalletConnectSharp.Events/Model/GenericEvent.cs deleted file mode 100644 index 6fcdb3b..0000000 --- a/Core Modules/WalletConnectSharp.Events/Model/GenericEvent.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; - -namespace WalletConnectSharp.Events.Model -{ - /// - /// A generic implementation of the IEvent interface. Given a event data type T, store the data in-memory - /// in the EventData property - /// - /// The event data type to store - public class GenericEvent : IEvent - { - /// - /// The event data - /// - public T EventData { get; private set; } - - /// - /// Store the event data, this function may only be invoked once - /// - /// The event data to store - /// This instance already is storing event data - public void SetData(T response) - { - if (EventData != null && !EventData.Equals(default(T))) - { - throw new ArgumentException("Event Data was already set"); - } - - EventData = response; - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/Utils/RpcPayloadId.cs b/Core Modules/WalletConnectSharp.Events/Utils/RpcPayloadId.cs deleted file mode 100644 index f3788da..0000000 --- a/Core Modules/WalletConnectSharp.Events/Utils/RpcPayloadId.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace WalletConnectSharp.Events.Utils -{ - /// - /// A static class that can generate random JSONRPC ids using the current time as a source of randomness - /// - public static class RpcPayloadId - { - private static readonly Random rng = new Random(); - private static readonly DateTime UnixEpoch = - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - /// - /// Generate a new random JSON-RPC id. The clock is used as a source of randomness - /// - /// A random JSON-RPC id - public static long Generate() - { - var date = (long)((DateTime.UtcNow - UnixEpoch).TotalMilliseconds) * (10L * 10L * 10L); - var extra = (long)Math.Floor(rng.NextDouble() * (10.0 * 10.0 * 10.0)); - return date + extra; - } - } -} diff --git a/Core Modules/WalletConnectSharp.Events/WalletConnectSharp.Events.csproj b/Core Modules/WalletConnectSharp.Events/WalletConnectSharp.Events.csproj deleted file mode 100644 index f877fe9..0000000 --- a/Core Modules/WalletConnectSharp.Events/WalletConnectSharp.Events.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - $(DefaultTargetFrameworks) - $(DefaultVersion) - $(DefaultVersion) - $(DefaultVersion) - WalletConnect.Events - WalletConnectSharp.Events - pedrouid, gigajuwels, edkek - A port of the TypeScript SDK to C#. A complete implementation of the WalletConnect v2 protocol that can be used to connect to external wallets or connect a wallet to an external Dapp - Copyright (c) WalletConnect 2023 - https://walletconnect.org/ - icon.png - https://github.com/WalletConnect/WalletConnectSharp - git - walletconnect wallet web3 ether ethereum blockchain evm - true - Apache-2.0 - - - - - - - - - - - diff --git a/Core Modules/WalletConnectSharp.Network.Websocket/WalletConnectSharp.Network.Websocket.csproj b/Core Modules/WalletConnectSharp.Network.Websocket/WalletConnectSharp.Network.Websocket.csproj index 6070f63..cf9d841 100644 --- a/Core Modules/WalletConnectSharp.Network.Websocket/WalletConnectSharp.Network.Websocket.csproj +++ b/Core Modules/WalletConnectSharp.Network.Websocket/WalletConnectSharp.Network.Websocket.csproj @@ -30,6 +30,7 @@ WC_DEF_WEBSOCKET + diff --git a/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs b/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs index 67c3311..74fc224 100644 --- a/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs +++ b/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs @@ -2,8 +2,6 @@ using Newtonsoft.Json; using WalletConnectSharp.Common; using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; using Websocket.Client; @@ -14,7 +12,6 @@ namespace WalletConnectSharp.Network.Websocket /// public class WebsocketConnection : IJsonRpcConnection, IModule { - private EventDelegator _delegator; private WebsocketClient _socket; private string _url; private bool _registering; @@ -64,17 +61,12 @@ public string Context } } - /// - /// The EventDelegator this Websocket connection module is using - /// - public EventDelegator Events - { - get - { - return _delegator; - } - } - + public event EventHandler PayloadReceived; + public event EventHandler Closed; + public event EventHandler ErrorReceived; + public event EventHandler Opened; + public event EventHandler RegisterErrored; + /// /// Whether this websocket connection is connected /// @@ -109,7 +101,6 @@ public WebsocketConnection(string url) _context = Guid.NewGuid(); this._url = url; - _delegator = new EventDelegator(this); } /// @@ -146,18 +137,16 @@ private async Task Register(string url) { TaskCompletionSource registeringTask = new TaskCompletionSource(TaskCreationOptions.None); - - Events.ListenForOnce("register_error", - delegate(object sender, GenericEvent @event) - { - registeringTask.SetException(@event.EventData); - }); - - Events.ListenForOnce("open", - delegate(object sender, GenericEvent @event) - { - registeringTask.SetResult(@event.EventData); - }); + + this.ListenOnce(nameof(RegisterErrored), (sender, args) => + { + registeringTask.SetException(args); + }); + + this.ListenOnce(nameof(Opened), (sender, args) => + { + registeringTask.SetResult(args); + }); await registeringTask.Task; @@ -178,7 +167,7 @@ private async Task Register(string url) } catch (Exception e) { - Events.Trigger(WebsocketConnectionEvents.RegisterError, e); + this.RegisterErrored?.Invoke(this, e); OnClose(new DisconnectionInfo(DisconnectionType.Error, WebSocketCloseStatus.Empty, e.Message, null, e)); throw; @@ -195,13 +184,13 @@ private void OnOpen(WebsocketClient socket) this._socket = socket; this._registering = false; - Events.Trigger(WebsocketConnectionEvents.Open, _socket); + this.Opened?.Invoke(this, _socket); } private void OnDisconnect(DisconnectionInfo obj) { if (obj.Exception != null) - Events.Trigger(WebsocketConnectionEvents.Error, obj.Exception); + this.ErrorReceived?.Invoke(this, obj.Exception); OnClose(obj); } @@ -214,7 +203,7 @@ private void OnClose(DisconnectionInfo obj) //_socket.Dispose(); this._socket = null; this._registering = false; - Events.Trigger(WebsocketConnectionEvents.Close, obj); + this.Closed?.Invoke(this, EventArgs.Empty); } private void OnPayload(ResponseMessage obj) @@ -235,7 +224,7 @@ private void OnPayload(ResponseMessage obj) //Console.WriteLine($"[{Name}] Got payload {json}"); - Events.Trigger(WebsocketConnectionEvents.Payload, json); + this.PayloadReceived?.Invoke(this, json); } /// @@ -342,7 +331,7 @@ private void OnError(IJsonRpcPayload ogPayload, Exception e) }, default(T)); //Trigger the payload event, converting the new JsonRpcResponse object to JSON string - Events.Trigger(WebsocketConnectionEvents.Payload, JsonConvert.SerializeObject(payload)); + this.PayloadReceived?.Invoke(this, JsonConvert.SerializeObject(payload)); } } } diff --git a/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnectionEvents.cs b/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnectionEvents.cs deleted file mode 100644 index c01d2fe..0000000 --- a/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnectionEvents.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace WalletConnectSharp.Network.Websocket -{ - /// - /// Constants defining WebsocketConnection eventIds - /// - public static class WebsocketConnectionEvents - { - /// - /// The eventId for the Payload event - /// - public const string Payload = "payload"; - - /// - /// The eventId for the Close event - /// - public const string Close = "close"; - - /// - /// The eventId of the RegisterError event - /// - public const string RegisterError = "register_error"; - - /// - /// The eventId of the Open event - /// - public const string Open = "open"; - - /// - /// The eventId of the Error event - /// - public const string Error = "error"; - } -} diff --git a/Core Modules/WalletConnectSharp.Network/Interfaces/IBaseJsonRpcProvider.cs b/Core Modules/WalletConnectSharp.Network/Interfaces/IBaseJsonRpcProvider.cs index 14eabbd..3babbd3 100644 --- a/Core Modules/WalletConnectSharp.Network/Interfaces/IBaseJsonRpcProvider.cs +++ b/Core Modules/WalletConnectSharp.Network/Interfaces/IBaseJsonRpcProvider.cs @@ -1,12 +1,10 @@ -using System.Threading.Tasks; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Network { /// /// Represents a base interface for JsonRpcProvider /// - public interface IBaseJsonRpcProvider : IEvents + public interface IBaseJsonRpcProvider { /// /// Gets the current IJsonRpcConnection this provider is using diff --git a/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcConnection.cs b/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcConnection.cs index 33d72a5..33af982 100644 --- a/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcConnection.cs +++ b/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcConnection.cs @@ -1,14 +1,22 @@ -using System; -using System.Threading.Tasks; -using WalletConnectSharp.Events.Interfaces; + namespace WalletConnectSharp.Network { /// /// An interface describing a connection to a JSON RPC node /// - public interface IJsonRpcConnection : IEvents, IDisposable + public interface IJsonRpcConnection : IDisposable { + event EventHandler PayloadReceived; + + event EventHandler Closed; + + event EventHandler ErrorReceived; + + event EventHandler Opened; + + event EventHandler RegisterErrored; + /// /// Whether this connection is active and connected /// diff --git a/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcProvider.cs b/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcProvider.cs index 1c02fde..11aa025 100644 --- a/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcProvider.cs +++ b/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcProvider.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Network { @@ -8,6 +9,16 @@ namespace WalletConnectSharp.Network /// public interface IJsonRpcProvider : IBaseJsonRpcProvider { + event EventHandler PayloadReceived; + + event EventHandler Connected; + + event EventHandler Disconnected; + + event EventHandler ErrorReceived; + + event EventHandler RawMessageReceived; + /// /// Connect this provider to the given URL /// diff --git a/Core Modules/WalletConnectSharp.Network/JsonRpcProvider.cs b/Core Modules/WalletConnectSharp.Network/JsonRpcProvider.cs index 1a56c99..0a47993 100644 --- a/Core Modules/WalletConnectSharp.Network/JsonRpcProvider.cs +++ b/Core Modules/WalletConnectSharp.Network/JsonRpcProvider.cs @@ -1,9 +1,8 @@ using Newtonsoft.Json; using WalletConnectSharp.Common; +using WalletConnectSharp.Common.Events; using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Common.Model.Errors; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Network @@ -14,13 +13,24 @@ namespace WalletConnectSharp.Network public class JsonRpcProvider : IJsonRpcProvider, IModule { private IJsonRpcConnection _connection; - private EventDelegator _delegator; private bool _hasRegisteredEventListeners; private Guid _context; private bool _connectingStarted; private TaskCompletionSource Connecting = new TaskCompletionSource(); private long _lastId; + public event EventHandler PayloadReceived; + + public event EventHandler Connected; + + public event EventHandler Disconnected; + + public event EventHandler ErrorReceived; + + public event EventHandler RawMessageReceived; + + private GenericEventHolder jsonResponseEventHolder = new(); + /// /// Whether the provider is currently connecting or not /// @@ -66,17 +76,6 @@ public string Context } } - /// - /// The EventDelegator this provider is using for events - /// - public EventDelegator Events - { - get - { - return _delegator; - } - } - /// /// Create a new JsonRpcProvider with the given connection /// @@ -84,7 +83,6 @@ public EventDelegator Events public JsonRpcProvider(IJsonRpcConnection connection) { _context = Guid.NewGuid(); - this._delegator = new EventDelegator(this); this._connection = connection; if (this._connection.Connected) { @@ -141,7 +139,7 @@ private void FinalizeConnection(IJsonRpcConnection connection) WCLogger.Log("[JsonRpcProvider] Finalizing Connection, registering event listeners"); this._connection = connection; RegisterEventListeners(); - Events.Trigger(ProviderEvents.Connect, connection); + this.Connected?.Invoke(this, connection); Connecting.SetResult(true); _connectingStarted = false; } @@ -199,39 +197,35 @@ public async Task Request(IRequestArguments requestArgs, object co var request = new JsonRpcRequest(requestArgs.Method, requestArgs.Params, id); TaskCompletionSource requestTask = new TaskCompletionSource(TaskCreationOptions.None); - - Events.ListenForAndDeserialize>(request.Id.ToString(), - delegate(object sender, GenericEvent> @event) - { - if (requestTask.Task.IsCompleted) - return; - - var result = @event.EventData; - - //Console.WriteLine($"[{Name}] Got response {JsonConvert.SerializeObject(result)}"); + + jsonResponseEventHolder.OfType()[request.Id.ToString()] += (sender, responseJson) => + { + if (requestTask.Task.IsCompleted) + return; + + var result = JsonConvert.DeserializeObject>(responseJson); - if (result.Error != null) - { - requestTask.SetException(new IOException(result.Error.Message)); - } - else - { - requestTask.SetResult(result.Result); - } - }); - - Events.ListenFor(request.Id.ToString(), delegate(object sender, GenericEvent @event) + if (result.Error != null) + { + requestTask.SetException(new IOException(result.Error.Message)); + } + else + { + requestTask.SetResult(result.Result); + } + }; + + jsonResponseEventHolder.OfType()[request.Id.ToString()] += (sender, exception) => { if (requestTask.Task.IsCompleted) return; - var exception = @event.EventData; //Console.WriteLine($"[{Name}] Got Response Error {exception}"); if (exception != null) { requestTask.SetException(exception); } - }); + }; _lastId = request.Id; @@ -249,27 +243,29 @@ protected void RegisterEventListeners() { if (_hasRegisteredEventListeners) return; - WCLogger.Log($"[JsonRpcProvider] Registering event listeners on connection object with context {_connection.Events.Context}"); - _connection.On("payload", OnPayload); + WCLogger.Log($"[JsonRpcProvider] Registering event listeners on connection object with context {_connection.ToString()}"); + _connection.PayloadReceived += OnPayload; + _connection.Closed += OnConnectionDisconnected; + _connection.ErrorReceived += OnConnectionError; + + /*_connection.On("payload", OnPayload); _connection.On("close", OnConnectionDisconnected); - _connection.On("error", OnConnectionError); + _connection.On("error", OnConnectionError);*/ _hasRegisteredEventListeners = true; } - private void OnConnectionError(object sender, GenericEvent e) + private void OnConnectionError(object sender, Exception e) { - Events.Trigger(ProviderEvents.Error, e.EventData); + this.ErrorReceived?.Invoke(this, e); } - private void OnConnectionDisconnected(object sender, GenericEvent e) + private void OnConnectionDisconnected(object sender, EventArgs e) { - Events.TriggerType(ProviderEvents.Disconnect, e.EventData, e.EventData.GetType()); + this.Disconnected?.Invoke(this, e); } - private void OnPayload(object sender, GenericEvent e) + private void OnPayload(object sender, string json) { - var json = e.EventData; - WCLogger.Log($"[JsonRpcProvider] Got payload {json}"); var payload = JsonConvert.DeserializeObject(json); @@ -284,23 +280,24 @@ private void OnPayload(object sender, GenericEvent e) WCLogger.Log($"[JsonRpcProvider] Payload has ID {payload.Id}"); - Events.Trigger(ProviderEvents.Payload, payload); + this.PayloadReceived?.Invoke(this, payload); if (payload.IsRequest) { - Events.Trigger(ProviderEvents.RawRequestMessage, json); + this.RawMessageReceived?.Invoke(this, json); } else { if (payload.IsError) { var errorPayload = JsonConvert.DeserializeObject(json); - Events.Trigger(payload.Id.ToString(), errorPayload.Error.ToException()); + jsonResponseEventHolder.OfType()[payload.Id.ToString()](this, + errorPayload.Error.ToException()); } else { WCLogger.Log($"Triggering event for ID {payload.Id.ToString()}"); - Events.Trigger(payload.Id.ToString(), json); + jsonResponseEventHolder.OfType()[payload.Id.ToString()](this, json); } } } @@ -308,7 +305,6 @@ private void OnPayload(object sender, GenericEvent e) public void Dispose() { _connection?.Dispose(); - _delegator?.Dispose(); } } } diff --git a/Core Modules/WalletConnectSharp.Network/Models/JsonRpcRequest.cs b/Core Modules/WalletConnectSharp.Network/Models/JsonRpcRequest.cs index 3946884..45e29cb 100644 --- a/Core Modules/WalletConnectSharp.Network/Models/JsonRpcRequest.cs +++ b/Core Modules/WalletConnectSharp.Network/Models/JsonRpcRequest.cs @@ -1,5 +1,5 @@ using Newtonsoft.Json; -using WalletConnectSharp.Events.Utils; +using WalletConnectSharp.Common.Utils; namespace WalletConnectSharp.Network.Models { diff --git a/Core Modules/WalletConnectSharp.Network/Models/ProviderEvents.cs b/Core Modules/WalletConnectSharp.Network/Models/ProviderEvents.cs deleted file mode 100644 index e3d3781..0000000 --- a/Core Modules/WalletConnectSharp.Network/Models/ProviderEvents.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace WalletConnectSharp.Network.Models -{ - /// - /// Event id constants for JsonRpcProvider - /// - public static class ProviderEvents - { - /// - /// The event id for the Payload event - /// - public static readonly string Payload = "payload"; - - /// - /// The event id of the Connect event - /// - public static readonly string Connect = "connect"; - - /// - /// The event id of the Disconnect event - /// - public static readonly string Disconnect = "disconnect"; - - /// - /// The event id of the Error event - /// - public static readonly string Error = "error"; - - /// - /// The event id of the RawRequestMessage event - /// - public static readonly string RawRequestMessage = "message"; - } -} diff --git a/Core Modules/WalletConnectSharp.Network/WalletConnectSharp.Network.csproj b/Core Modules/WalletConnectSharp.Network/WalletConnectSharp.Network.csproj index 17b905d..903992c 100644 --- a/Core Modules/WalletConnectSharp.Network/WalletConnectSharp.Network.csproj +++ b/Core Modules/WalletConnectSharp.Network/WalletConnectSharp.Network.csproj @@ -20,11 +20,11 @@ - + - + diff --git a/Tests/WalletConnectSharp.Auth.Tests/AuthClientTest.cs b/Tests/WalletConnectSharp.Auth.Tests/AuthClientTest.cs index db6a92f..504ff77 100644 --- a/Tests/WalletConnectSharp.Auth.Tests/AuthClientTest.cs +++ b/Tests/WalletConnectSharp.Auth.Tests/AuthClientTest.cs @@ -3,12 +3,11 @@ using WalletConnectSharp.Auth.Interfaces; using WalletConnectSharp.Auth.Internals; using WalletConnectSharp.Auth.Models; +using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core; using WalletConnectSharp.Core.Models.Pairing; using WalletConnectSharp.Core.Models.Publisher; -using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Core.Models.Verify; -using WalletConnectSharp.Events; using WalletConnectSharp.Storage; using WalletConnectSharp.Tests.Common; using Xunit; @@ -67,13 +66,11 @@ public async void TestInit() Assert.NotNull(PeerB); Assert.NotNull(PeerA.Core); - Assert.NotNull(PeerA.Events); Assert.NotNull(PeerA.Core.Expirer); Assert.NotNull(PeerA.Core.History); Assert.NotNull(PeerA.Core.Pairing); Assert.NotNull(PeerB.Core); - Assert.NotNull(PeerB.Events); Assert.NotNull(PeerB.Core.Expirer); Assert.NotNull(PeerB.Core.History); Assert.NotNull(PeerB.Core.Pairing); @@ -304,13 +301,12 @@ public async void TestCustomRequestExpiry() var expiry = 1000; TaskCompletionSource resolve1 = new TaskCompletionSource(); - - PeerA.Core.Relayer.Once(RelayerEvents.Publish, (sender, @event) => + + PeerA.Core.Relayer.Publisher.ListenOnce(nameof(PeerA.Core.Relayer.Publisher.OnPublishedMessage), (sender, args) => { - Assert.Equal(expiry, @event.EventData.Options?.TTL); + Assert.Equal(expiry, args.Options.TTL); resolve1.SetResult(true); }); - await Task.WhenAll(resolve1.Task, Task.Run(async () => { @@ -401,12 +397,12 @@ public async void TestPing() PeerB.AuthRequested += OnPeerBOnAuthRequested; - PeerB.Core.Pairing.Once(PairingEvents.PairingPing, (sender, @event) => + PeerB.Core.Pairing.ListenOnce(nameof(PeerB.Core.Pairing.PairingPinged), (sender, @event) => { receivedPeerPing.SetResult(true); }); - PeerA.Core.Pairing.Once(PairingEvents.PairingPing, (sender, @event) => + PeerA.Core.Pairing.ListenOnce(nameof(PeerA.Core.Pairing.PairingPinged), (sender, args) => { receivedClientPing.SetResult(true); }); @@ -442,7 +438,7 @@ public async void TestDisconnectedPairing() PeerB.AuthRequested += OnPeerBOnAuthRequested; - PeerB.Core.Pairing.Once(PairingEvents.PairingDelete, (sender, @event) => + PeerB.Core.Pairing.ListenOnce(nameof(PeerB.Core.Pairing.PairingDeleted), (sender, args) => { peerDeletedPairing.SetResult(true); }); diff --git a/Tests/WalletConnectSharp.Events.Tests/EventTests.cs b/Tests/WalletConnectSharp.Events.Tests/EventTests.cs deleted file mode 100644 index 004f235..0000000 --- a/Tests/WalletConnectSharp.Events.Tests/EventTests.cs +++ /dev/null @@ -1,262 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using Newtonsoft.Json; -using WalletConnectSharp.Common; -using WalletConnectSharp.Common.Model; -using WalletConnectSharp.Events.Model; -using Xunit; - -namespace WalletConnectSharp.Events.Tests -{ - public class EventDelegatorTests - { - interface ITest - { - public int test1 { get; } - } - - public class TestEventData : ITest - { - public int test1 { get; set; } - public string test2; - } - - public class TestGenericData - { - public T data; - } - - [Fact, Trait("Category", "unit")] - public async void AsyncEventsPropagate() - { - var events = new EventDelegator(); - - TaskCompletionSource eventCallbackTask = new TaskCompletionSource(); - - string eventId = Guid.NewGuid().ToString(); - - events.ListenFor(eventId, delegate(object sender, GenericEvent @event) - { - eventCallbackTask.SetResult(@event.EventData); - }); - var eventData = Guid.NewGuid().ToString(); - - await Task.Run(delegate - { - Thread.Sleep(500); - events.Trigger(eventId, eventData); - }); - - Assert.Equal(eventData, (await eventCallbackTask.Task)); - } - - [Fact, Trait("Category", "unit")] - public void ListenForOnce() - { - EventDelegator events = new EventDelegator(); - - TestEventData result1 = null; - - events.ListenForOnce("abc", delegate(object sender, GenericEvent @event) - { - result1 = @event.EventData; - }); - - var testData1 = new TestEventData() - { - test1 = 11, - test2 = "abccc" - }; - - events.Trigger("abc", testData1); - - Assert.StrictEqual(testData1, result1); - - result1 = null; - - events.Trigger("abc", testData1); - - Assert.Null(result1); - } - - [Fact, Trait("Category", "unit")] - public void RemoveListener() - { - EventDelegator events = new EventDelegator(); - - events.ListenFor("abc", Callback); - - events.RemoveListener("abc", Callback); - - events.Trigger("abc", new TestEventData()); - } - - private void Callback(object sender, GenericEvent e) - { - throw new NotImplementedException(); - } - - [Fact, Trait("Category", "unit")] - public void InheritanceEventsPropagate() - { - EventDelegator events = new EventDelegator(); - - TestEventData result1 = null; - ITest result2 = null; - TestGenericData result3 = null; - ITest result4 = null; - - events.ListenFor("abc", delegate(object sender, GenericEvent @event) - { - result1 = @event.EventData; - }); - - events.ListenFor("abc", delegate(object sender, GenericEvent @event) - { - result2 = @event.EventData; - }); - - - events.ListenFor>("xyz", - delegate(object sender, GenericEvent> @event) - { - result3 = @event.EventData; - }); - - events.ListenFor("xyz", delegate(object sender, GenericEvent @event) - { - result4 = @event.EventData; - }); - - var testData1 = new TestEventData() - { - test1 = 11, - test2 = "abccc" - }; - - var testData2 = new TestGenericData() - { - data = testData1 - }; - - events.Trigger("abc", testData1); - events.Trigger("xyz", testData2); - - Assert.StrictEqual(testData1, result1); - Assert.StrictEqual(testData1, result2); - Assert.StrictEqual(testData2, result3); - Assert.Null(result4); - } - - [Fact, Trait("Category", "unit")] - public void ListenAndDeserializeJson() - { - EventDelegator events = new EventDelegator(); - - TestEventData result1 = null; - - events.ListenForAndDeserialize("abc", delegate(object sender, GenericEvent @event) - { - result1 = @event.EventData; - }); - - var testData1 = new TestEventData() - { - test1 = 11, - test2 = "abccc" - }; - - var json = JsonConvert.SerializeObject(testData1); - - events.Trigger("abc", json); - - Assert.Equal(result1.test1, testData1.test1); - Assert.Equal(result1.test2, testData1.test2); - } - - public class TestModule : IModule - { - public void Dispose() - { - // TODO release managed resources here - } - - public string Name - { - get - { - return "test"; - } - } - - public string Context - { - get - { - return $"{Name}-context"; - } - } - } - - [Fact, Trait("Category", "unit")] - public void TestContextSharingWithoutDisposingFails() - { - var module = new TestModule(); - var events = new EventDelegator(module); - - Assert.Equal(module.Context, events.Context); - - Assert.Throws(() => new EventDelegator(module)); - - events.Dispose(); - - events = new EventDelegator(module); - - Assert.Equal(module.Context, events.Context); - - events.Dispose(); - } - - [Fact, Trait("Category", "unit")] - public void TestEventsDontLeakWhenDisposed() - { - var module = new TestModule(); - var events = new EventDelegator(module); - - Assert.Equal(module.Context, events.Context); - - Assert.Throws(() => new EventDelegator(module)); - - TestEventData result1 = null; - - events.ListenForAndDeserialize("abc", delegate(object sender, GenericEvent @event) - { - result1 = @event.EventData; - }); - - var testData1 = new TestEventData() - { - test1 = 11, - test2 = "abccc" - }; - - var json = JsonConvert.SerializeObject(testData1); - - events.Trigger("abc", json); - - Assert.Equal(result1.test1, testData1.test1); - Assert.Equal(result1.test2, testData1.test2); - - events.Dispose(); - result1 = null; - - events = new EventDelegator(module); - events.Trigger("abc", json); - - Assert.Null(result1); - - events.Dispose(); - } - } -} diff --git a/Tests/WalletConnectSharp.Events.Tests/WalletConnectSharp.Events.Tests.csproj b/Tests/WalletConnectSharp.Events.Tests/WalletConnectSharp.Events.Tests.csproj deleted file mode 100644 index 1bf47b3..0000000 --- a/Tests/WalletConnectSharp.Events.Tests/WalletConnectSharp.Events.Tests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net6.0;netcoreapp3.1 - 2.0.0 - 2.0.0 - 2.0.0 - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - - diff --git a/Tests/WalletConnectSharp.Network.Tests/RelayTests.cs b/Tests/WalletConnectSharp.Network.Tests/RelayTests.cs index 355519b..2d47e0d 100644 --- a/Tests/WalletConnectSharp.Network.Tests/RelayTests.cs +++ b/Tests/WalletConnectSharp.Network.Tests/RelayTests.cs @@ -1,11 +1,9 @@ using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Model.Relay; -using WalletConnectSharp.Events; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Network.Tests.Models; using WalletConnectSharp.Network.Websocket; using WalletConnectSharp.Tests.Common; -using Websocket.Client; using Xunit; namespace WalletConnectSharp.Network.Tests @@ -118,7 +116,7 @@ public async void DoesNotDoubleRegisterListeners() var expectedDisconnectCount = 3; var disconnectCount = 0; - provider.On("disconnect", (_, __) => disconnectCount++); + provider.Disconnected += (_, _) => disconnectCount++; await provider.Connect(); await provider.Disconnect(); diff --git a/Tests/WalletConnectSharp.Network.Tests/WalletConnectSharp.Network.Tests.csproj b/Tests/WalletConnectSharp.Network.Tests/WalletConnectSharp.Network.Tests.csproj index 708f371..82acc30 100644 --- a/Tests/WalletConnectSharp.Network.Tests/WalletConnectSharp.Network.Tests.csproj +++ b/Tests/WalletConnectSharp.Network.Tests/WalletConnectSharp.Network.Tests.csproj @@ -22,7 +22,6 @@ - diff --git a/Tests/WalletConnectSharp.Sign.Test/SignClientConcurrency.cs b/Tests/WalletConnectSharp.Sign.Test/SignClientConcurrency.cs index 5337c88..cba4c0a 100644 --- a/Tests/WalletConnectSharp.Sign.Test/SignClientConcurrency.cs +++ b/Tests/WalletConnectSharp.Sign.Test/SignClientConcurrency.cs @@ -1,8 +1,6 @@ using Newtonsoft.Json; using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Utils; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign.Interfaces; using WalletConnectSharp.Sign.Models; @@ -93,7 +91,7 @@ private async Task _TestConcurrentClients() List pairings = new List(); object messageLock = new object(); - List> messagesReceived = new List>(); + List> messagesReceived = new List>(); CancellationTokenSource heartbeatToken = new CancellationTokenSource(); @@ -129,7 +127,7 @@ Task ProcessMessages(TestPairings data, int clientIndex) lock (messageLock) { - messagesReceived.Insert(clientIndex, new List()); + messagesReceived.Insert(clientIndex, new List()); } TaskCompletionSource task = new TaskCompletionSource(); @@ -166,38 +164,39 @@ void CheckAllMessagesProcessed() foreach (var client in clientsArr) { - client.On(EngineEvents.SessionPing, (sender, @event) => + client.SessionPinged += (sender, @event) => { - Assert.Equal(sessionA.Topic, @event.EventData.Topic); + Assert.Equal(sessionA.Topic, @event.Topic); lock (messageLock) { - messagesReceived[clientIndex].Add(@event.EventData); + messagesReceived[clientIndex].Add(@event); } CheckAllMessagesProcessed(); - }); + }; - client.On>(EngineEvents.SessionEvent, (sender, @event) => + client.HandleEventMessageType(async (s, args) => { - Assert.Equal(testEventParams.Data, @event.EventData.Params.Event.Data); - Assert.Equal(eventPayload.Topic, @event.EventData.Topic); + Assert.Equal(testEventParams.Data, args.Params.Event.Data); + Assert.Equal(eventPayload.Topic, args.Params.Topic); lock (messageLock) { - messagesReceived[clientIndex].Add(@event.EventData); + messagesReceived[clientIndex].Add(args.Params); } CheckAllMessagesProcessed(); - }); + }, null); - client.On(EngineEvents.SessionUpdate, (sender, @event) => + client.SessionUpdateRequest += (sender, @event) => { Assert.Equal(client.Session.Get(sessionA.Topic).Namespaces, namespacesAfter); lock (messageLock) { - messagesReceived[clientIndex].Add(@event.EventData); + messagesReceived[clientIndex].Add(@event); } + CheckAllMessagesProcessed(); - }); + }; } async void SendMessages() @@ -291,11 +290,11 @@ async Task ConnectClient() var sessionA = data.sessionA; TaskCompletionSource clientBDisconnected = new TaskCompletionSource(); - clients.ClientB.On(EngineEvents.SessionDelete, (sender, @event) => + clients.ClientB.SessionDeleted += (sender, @event) => { - Assert.Equal(sessionA.Topic, @event.EventData.Topic); + Assert.Equal(sessionA.Topic, @event.Topic); clientBDisconnected.TrySetResult(true); - }); + }; await Task.WhenAll( clientBDisconnected.Task, diff --git a/Tests/WalletConnectSharp.Web3Wallet.Tests/SignTests.cs b/Tests/WalletConnectSharp.Web3Wallet.Tests/SignTests.cs index 4ffa579..208ea19 100644 --- a/Tests/WalletConnectSharp.Web3Wallet.Tests/SignTests.cs +++ b/Tests/WalletConnectSharp.Web3Wallet.Tests/SignTests.cs @@ -9,7 +9,6 @@ using WalletConnectSharp.Core; using WalletConnectSharp.Core.Models; using WalletConnectSharp.Core.Models.Verify; -using WalletConnectSharp.Events; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign; using WalletConnectSharp.Sign.Models; @@ -187,18 +186,18 @@ public async Task DisposeAsync() public async void TestShouldApproveSessionProposal() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; - + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; + Assert.Equal(Validation.Unknown, verifyContext.Validation); session = await _wallet.ApproveSession(id, TestNamespaces); - + Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -213,16 +212,16 @@ public async void TestShouldRejectSessionProposal() var rejectionError = Error.FromErrorType(ErrorType.USER_DISCONNECTED); TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var proposal = @event.EventData.Proposal; + var proposal = @event.Proposal; - var id = @event.EventData.Id; + var id = @event.Id; Assert.Equal(TestRequiredNamespaces, proposal.RequiredNamespaces); await _wallet.RejectSession(id, rejectionError); task1.TrySetResult(true); - }); + }; async Task CheckSessionReject() { @@ -250,18 +249,18 @@ await Task.WhenAll( public async void TestUpdateSession() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; - + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; + Assert.Equal(Validation.Unknown, verifyContext.Validation); session = await _wallet.ApproveSession(id, TestNamespaces); - + Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -272,12 +271,12 @@ await Task.WhenAll( Assert.NotEqual(TestNamespaces, TestUpdatedNamespaces); TaskCompletionSource task2 = new TaskCompletionSource(); - _dapp.On(EngineEvents.SessionUpdate, (sender, @event) => + _dapp.SessionUpdateRequest += (sender, @event) => { - var param = @event.EventData.Params; + var param = @event.Params; Assert.Equal(TestUpdatedNamespaces, param.Namespaces); task2.TrySetResult(true); - }); + }; await Task.WhenAll( task2.Task, @@ -289,18 +288,18 @@ await Task.WhenAll( public async void TestExtendSession() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; - + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; + Assert.Equal(Validation.Unknown, verifyContext.Validation); session = await _wallet.ApproveSession(id, TestNamespaces); - + Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -325,11 +324,11 @@ await Task.WhenAll( public async void TestRespondToSessionRequest() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; session = await _wallet.ApproveSession(id, new Namespaces() { @@ -345,7 +344,7 @@ public async void TestRespondToSessionRequest() Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -403,11 +402,11 @@ await Task.WhenAll( public async void TestWalletDisconnectFromSession() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; session = await _wallet.ApproveSession(id, new Namespaces() { @@ -423,7 +422,7 @@ public async void TestWalletDisconnectFromSession() Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -432,13 +431,13 @@ await Task.WhenAll( ); var reason = Error.FromErrorType(ErrorType.USER_DISCONNECTED); - + TaskCompletionSource task2 = new TaskCompletionSource(); - _dapp.On(EngineEvents.SessionDelete, (sender, @event) => + _dapp.SessionDeleted += (sender, @event) => { - Assert.Equal(session.Topic, @event.EventData.Topic); + Assert.Equal(session.Topic, @event.Topic); task2.TrySetResult(true); - }); + }; await Task.WhenAll( task2.Task, @@ -450,11 +449,11 @@ await Task.WhenAll( public async void TestDappDisconnectFromSession() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; session = await _wallet.ApproveSession(id, new Namespaces() { @@ -470,7 +469,7 @@ public async void TestDappDisconnectFromSession() Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -481,11 +480,11 @@ await Task.WhenAll( var reason = Error.FromErrorType(ErrorType.USER_DISCONNECTED); TaskCompletionSource task2 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionDelete, (sender, @event) => + _wallet.SessionDeleted += (sender, @event) => { - Assert.Equal(session.Topic, @event.EventData.Topic); + Assert.Equal(session.Topic, @event.Topic); task2.TrySetResult(true); - }); + }; await Task.WhenAll( task2.Task, @@ -497,11 +496,11 @@ await Task.WhenAll( public async void TestEmitSessionEvent() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; session = await _wallet.ApproveSession(id, new Namespaces() { @@ -517,7 +516,7 @@ public async void TestEmitSessionEvent() Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -555,27 +554,29 @@ await Task.WhenAll( public async void TestGetActiveSessions() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; - - session = await _wallet.ApproveSession(id, new Namespaces() - { - { - "eip155", new Namespace() + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; + + session = await _wallet.ApproveSession(id, + new Namespaces() + { { - Methods = TestNamespace.Methods, - Events = TestNamespace.Events, - Accounts = new []{ $"{TestEthereumChain}:{WalletAddress}" } + "eip155", + new Namespace() + { + Methods = TestNamespace.Methods, + Events = TestNamespace.Events, + Accounts = new[] { $"{TestEthereumChain}:{WalletAddress}" } + } } - } - }); + }); Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -593,14 +594,14 @@ await Task.WhenAll( public async void TestGetPendingSessionProposals() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += (sender, @event) => { var proposals = _wallet.PendingSessionProposals; Assert.NotNull(proposals); Assert.Single(proposals); Assert.Equal(TestRequiredNamespaces, proposals.Values.ToArray()[0].RequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, @@ -612,27 +613,29 @@ await Task.WhenAll( public async void TestGetPendingSessionRequests() { TaskCompletionSource task1 = new TaskCompletionSource(); - _wallet.On(EngineEvents.SessionProposal, async (sender, @event) => + _wallet.SessionProposed += async (sender, @event) => { - var id = @event.EventData.Id; - var proposal = @event.EventData.Proposal; - var verifyContext = @event.EventData.VerifiedContext; - - session = await _wallet.ApproveSession(id, new Namespaces() - { - { - "eip155", new Namespace() + var id = @event.Id; + var proposal = @event.Proposal; + var verifyContext = @event.VerifiedContext; + + session = await _wallet.ApproveSession(id, + new Namespaces() + { { - Methods = TestNamespace.Methods, - Events = TestNamespace.Events, - Accounts = new []{ $"{TestEthereumChain}:{WalletAddress}" } + "eip155", + new Namespace() + { + Methods = TestNamespace.Methods, + Events = TestNamespace.Events, + Accounts = new[] { $"{TestEthereumChain}:{WalletAddress}" } + } } - } - }); + }); Assert.Equal(proposal.RequiredNamespaces, TestRequiredNamespaces); task1.TrySetResult(true); - }); + }; await Task.WhenAll( task1.Task, diff --git a/WalletConnectSharp.Auth/Controllers/AuthEngine.cs b/WalletConnectSharp.Auth/Controllers/AuthEngine.cs index 3e2e69f..e7ac368 100644 --- a/WalletConnectSharp.Auth/Controllers/AuthEngine.cs +++ b/WalletConnectSharp.Auth/Controllers/AuthEngine.cs @@ -5,11 +5,8 @@ using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core; -using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Core.Models.Verify; using WalletConnectSharp.Crypto.Models; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; using ErrorResponse = WalletConnectSharp.Auth.Models.ErrorResponse; diff --git a/WalletConnectSharp.Auth/Interfaces/IAuthClient.cs b/WalletConnectSharp.Auth/Interfaces/IAuthClient.cs index 205c697..011ea14 100644 --- a/WalletConnectSharp.Auth/Interfaces/IAuthClient.cs +++ b/WalletConnectSharp.Auth/Interfaces/IAuthClient.cs @@ -2,11 +2,10 @@ using WalletConnectSharp.Common; using WalletConnectSharp.Core; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Auth.Interfaces; -public interface IAuthClient : IModule, IEvents, IAuthClientEvents +public interface IAuthClient : IModule, IAuthClientEvents { string Protocol { get; } int Version { get; } diff --git a/WalletConnectSharp.Auth/WalletConnectAuthClient.cs b/WalletConnectSharp.Auth/WalletConnectAuthClient.cs index 6de2564..eda24b9 100644 --- a/WalletConnectSharp.Auth/WalletConnectAuthClient.cs +++ b/WalletConnectSharp.Auth/WalletConnectAuthClient.cs @@ -4,7 +4,6 @@ using WalletConnectSharp.Core; using WalletConnectSharp.Core.Controllers; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Events; namespace WalletConnectSharp.Auth; @@ -31,8 +30,6 @@ public string Context } } - public EventDelegator Events { get; } - public string Protocol { get @@ -107,7 +104,6 @@ private WalletConnectAuthClient(AuthOptions options) Requests = new Store(Core, "requests", AUTH_CLIENT_STORAGE_PREFIX); Engine = new AuthEngine(this); - Events = new EventDelegator(this); } public Task Request(RequestParams @params, string topic = null) @@ -165,7 +161,6 @@ bool IAuthClient.OnAuthResponse(AuthResponse response) public void Dispose() { - Events?.Dispose(); Core?.Dispose(); AuthKeys?.Dispose(); PairingTopics?.Dispose(); diff --git a/WalletConnectSharp.Core/Controllers/Expirer.cs b/WalletConnectSharp.Core/Controllers/Expirer.cs index 766dc64..e262c51 100644 --- a/WalletConnectSharp.Core/Controllers/Expirer.cs +++ b/WalletConnectSharp.Core/Controllers/Expirer.cs @@ -2,8 +2,6 @@ using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; using WalletConnectSharp.Core.Models.Expirer; -using WalletConnectSharp.Core.Models.Heartbeat; -using WalletConnectSharp.Events; namespace WalletConnectSharp.Core.Controllers { @@ -45,11 +43,6 @@ public string Context } } - /// - /// The this module uses to emit events - /// - public EventDelegator Events { get; } - /// /// The string key value this module will use when storing data in the module /// module @@ -62,6 +55,11 @@ public string StorageKey } } + public event EventHandler Created; + public event EventHandler Deleted; + public event EventHandler Expired; + public event EventHandler Sync; + /// /// The number of expirations this module is tracking /// @@ -102,7 +100,6 @@ public Expiration[] Values public Expirer(ICore core) { this._core = core; - Events = new EventDelegator(this); } /// @@ -199,7 +196,7 @@ private void SetWithTarget(string targetType, object key, long expiry) _expirations.Add(target, expiration); CheckExpiry(target, expiration); - Events.Trigger(ExpirerEvents.Created, new ExpirerEventArgs() + this.Created?.Invoke(this, new ExpirerEventArgs() { Expiration = expiration, Target = target @@ -266,7 +263,7 @@ private void DeleteWithTarget(string targetType, object key) { var expiration = GetExpiration(target); _expirations.Remove(target); - Events.Trigger(ExpirerEvents.Deleted, new ExpirerEventArgs() + this.Deleted?.Invoke(this, new ExpirerEventArgs() { Target = target, Expiration = expiration @@ -286,10 +283,10 @@ private async Task GetExpirations() return await _core.Storage.GetItem(StorageKey); } - private async void Persist() + private async void Persist(object sender, ExpirerEventArgs args) { await SetExpiration(Values); - Events.Trigger(ExpirerEvents.Sync, this); + this.Sync?.Invoke(this, EventArgs.Empty); } private async Task Restore() @@ -323,14 +320,14 @@ private void CheckExpiry(string target, Expiration expiration) private void Expire(string target, Expiration expiration) { _expirations.Remove(target); - Events.Trigger(ExpirerEvents.Expired, new ExpirerEventArgs() + this.Expired?.Invoke(this, new ExpirerEventArgs() { Target = target, Expiration = expiration }); } - private void CheckExpirations() + private void CheckExpirations(object sender, EventArgs args) { var clonedArray = _expirations.Keys.ToArray(); foreach (var target in clonedArray) @@ -342,11 +339,12 @@ private void CheckExpirations() private void RegisterEventListeners() { - _core.HeartBeat.On(HeartbeatEvents.Pulse, CheckExpirations); - - this.On(ExpirerEvents.Created, Persist); - this.On(ExpirerEvents.Expired, Persist); - this.On(ExpirerEvents.Deleted, Persist); + _core.HeartBeat.OnPulse += CheckExpirations; + //_core.HeartBeat.On(HeartbeatEvents.Pulse, CheckExpirations); + + this.Created += Persist; + this.Expired += Persist; + this.Deleted += Persist; } private void IsInitialized() @@ -380,7 +378,6 @@ private string FormatTarget(string targetType, object key) public void Dispose() { - Events?.Dispose(); } } } diff --git a/WalletConnectSharp.Core/Controllers/HeartBeat.cs b/WalletConnectSharp.Core/Controllers/HeartBeat.cs index d8c5346..2832126 100644 --- a/WalletConnectSharp.Core/Controllers/HeartBeat.cs +++ b/WalletConnectSharp.Core/Controllers/HeartBeat.cs @@ -1,6 +1,4 @@ using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Core.Models.Heartbeat; -using WalletConnectSharp.Events; namespace WalletConnectSharp.Core.Controllers { @@ -10,21 +8,13 @@ namespace WalletConnectSharp.Core.Controllers /// public class HeartBeat : IHeartBeat { - /// - /// The event data object used in the Pulse event - /// - public static readonly object PULSE_OBJECT = new object(); - - /// - /// The EventDelegator this module is using - /// - public EventDelegator Events { get; } - /// /// The CancellationToken that stops the Heartbeat module /// public CancellationToken HeartBeatCancellationToken { get; private set; } - + + public event EventHandler OnPulse; + /// /// The interval (in milliseconds) the Pulse event gets emitted/triggered /// @@ -60,11 +50,9 @@ public string Context /// /// Create a new Heartbeat module, optionally specifying options /// - /// The interval to emit the event at + /// The interval to emit the event at public HeartBeat(int interval = 5000) { - Events = new EventDelegator(this); - Interval = interval; } @@ -93,12 +81,11 @@ public Task Init() private void Pulse() { - Events.Trigger(HeartbeatEvents.Pulse, PULSE_OBJECT); + this.OnPulse?.Invoke(this, EventArgs.Empty); } public void Dispose() { - Events?.Dispose(); } } } diff --git a/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs b/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs index 1b637b7..608f6a3 100644 --- a/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs +++ b/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs @@ -1,8 +1,6 @@ using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Core.Interfaces; using WalletConnectSharp.Core.Models.History; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network; namespace WalletConnectSharp.Core.Controllers @@ -20,11 +18,6 @@ public class JsonRpcHistory : IJsonRpcHistory /// public static readonly string Version = "0.3"; - /// - /// The this module is using to emit events - /// - public EventDelegator Events { get; } - /// /// The name of this module instance /// @@ -63,6 +56,11 @@ public string StorageKey private bool initialized = false; private ICore _core; + public event EventHandler> Created; + public event EventHandler> Updated; + public event EventHandler> Deleted; + public event EventHandler Sync; + /// /// A mapping of Json RPC Records to their corresponding Json RPC id /// @@ -123,7 +121,6 @@ public RequestEvent[] Pending public JsonRpcHistory(ICore core) { _core = core; - Events = new EventDelegator(this); } /// @@ -165,7 +162,7 @@ public void Set(string topic, IJsonRpcRequest request, string chainId) ChainId = chainId, }; _records.Add(record.Id, record); - Events.Trigger(HistoryEvents.Created, record); + this.Created?.Invoke(this, record); } /// @@ -205,7 +202,7 @@ public Task Resolve(IJsonRpcResult response) if (record.Response != null) return Task.CompletedTask; record.Response = response; - Events.Trigger(HistoryEvents.Updated, record); + this.Updated?.Invoke(this, record); return Task.CompletedTask; } @@ -224,7 +221,7 @@ public void Delete(string topic, long? id) { if (id != null && record.Id != id) continue; _records.Remove(record.Id); - Events.Trigger(HistoryEvents.Deleted, record); + this.Deleted?.Invoke(this, record); } } } @@ -284,7 +281,7 @@ private JsonRpcRecord GetRecord(long id) private async Task Persist() { await SetJsonRpcRecords(Values); - Events.Trigger(HistoryEvents.Sync, new object()); + this.Sync?.Invoke(this, EventArgs.Empty); } private async Task Restore() @@ -304,14 +301,12 @@ private async Task Restore() private void RegisterEventListeners() { - this.On>(HistoryEvents.Created, SaveRecordCallback); - - this.On>(HistoryEvents.Updated, SaveRecordCallback); - - this.On>(HistoryEvents.Deleted, SaveRecordCallback); + this.Created += SaveRecordCallback; + this.Updated += SaveRecordCallback; + this.Deleted += SaveRecordCallback; } - private async void SaveRecordCallback(object sender, GenericEvent> @event) + private async void SaveRecordCallback(object sender, JsonRpcRecord @event) { await Persist(); } @@ -327,7 +322,6 @@ private void IsInitialized() public void Dispose() { _core?.Dispose(); - Events?.Dispose(); } } } diff --git a/WalletConnectSharp.Core/Controllers/Pairing.cs b/WalletConnectSharp.Core/Controllers/Pairing.cs index b4fe387..cce3042 100644 --- a/WalletConnectSharp.Core/Controllers/Pairing.cs +++ b/WalletConnectSharp.Core/Controllers/Pairing.cs @@ -1,5 +1,6 @@ using System.Security.Cryptography; using System.Text.RegularExpressions; +using WalletConnectSharp.Common.Events; using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Model.Relay; using WalletConnectSharp.Common.Utils; @@ -8,8 +9,6 @@ using WalletConnectSharp.Core.Models.Pairing; using WalletConnectSharp.Core.Models.Pairing.Methods; using WalletConnectSharp.Core.Models.Relay; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Core.Controllers @@ -22,7 +21,7 @@ public class Pairing : IPairing private const int KeyLength = 32; private bool _initialized; private HashSet _registeredMethods = new HashSet(); - + /// /// The name for this module instance /// @@ -45,11 +44,12 @@ public string Context } } - /// - /// The EventDelegator this module is using for events - /// - public EventDelegator Events { get; } - + public event EventHandler PairingExpired; + public event EventHandler PairingPinged; + public event EventHandler PairingDeleted; + + private EventHandlerMap> PairingPingResponseEvents = new(); + /// /// Get the module that is handling the storage of /// @@ -79,7 +79,6 @@ public PairingStruct[] Pairings public Pairing(ICore core) { this.Core = core; - this.Events = new EventDelegator(this); this.Store = new PairingStore(core); } @@ -101,7 +100,7 @@ public async Task Init() private void RegisterExpirerEvents() { - this.Core.Expirer.On(ExpirerEvents.Expired, ExpiredCallback); + this.Core.Expirer.Expired += ExpiredCallback; } private void RegisterTypedMessages() @@ -302,13 +301,15 @@ public async Task Ping(string topic) { var id = await Core.MessageHandler.SendRequest(topic, new PairingPing()); var done = new TaskCompletionSource(); - this.Events.ListenForOnce>($"pairing_ping{id}", (sender, e) => + + PairingPingResponseEvents.ListenOnce($"pairing_ping{id}", (sender, args) => { - if (e.EventData.IsError) - done.SetException(e.EventData.Error.ToException()); + if (args.IsError) + done.SetException(args.Error.ToException()); else - done.SetResult(e.EventData.Result); + done.SetResult(args.Result); }); + await done.Task; } } @@ -422,7 +423,7 @@ private async Task OnPairingPingRequest(string topic, JsonRpcRequest(id, topic, true); - this.Events.Trigger(PairingEvents.PairingPing, new PairingEvent() + this.PairingPinged?.Invoke(this, new PairingEvent() { Topic = topic, Id = id @@ -442,7 +443,13 @@ private async Task OnPairingPingResponse(string topic, JsonRpcResponse pay // where session_ping listener is not yet initialized await Task.Delay(500); - this.Events.Trigger($"pairing_ping{id}", payload); + this.PairingPinged?.Invoke(this, new PairingEvent() + { + Id = id, + Topic = topic + }); + + PairingPingResponseEvents[$"pairing_ping{id}"](this, payload); } private async Task OnPairingDeleteRequest(string topic, JsonRpcRequest payload) @@ -454,7 +461,7 @@ private async Task OnPairingDeleteRequest(string topic, JsonRpcRequest(id, topic, true); await DeletePairing(topic); - this.Events.Trigger(PairingEvents.PairingDelete, new PairingEvent() + this.PairingDeleted?.Invoke(this, new PairingEvent() { Topic = topic, Id = id @@ -476,9 +483,9 @@ private async Task IsValidDisconnect(string topic, Error reason) await IsValidPairingTopic(topic); } - private async void ExpiredCallback(object sender, GenericEvent e) + private async void ExpiredCallback(object sender, ExpirerEventArgs e) { - var target = new ExpirerTarget(e.EventData.Target); + var target = new ExpirerTarget(e.Target); if (string.IsNullOrWhiteSpace(target.Topic)) return; @@ -486,7 +493,7 @@ private async void ExpiredCallback(object sender, GenericEvent e) if (this.Store.Keys.Contains(topic)) { await DeletePairing(topic); - this.Events.Trigger(PairingEvents.PairingExpire, new PairingEvent() + this.PairingExpired?.Invoke(this, new PairingEvent() { Topic = topic, }); @@ -495,7 +502,6 @@ private async void ExpiredCallback(object sender, GenericEvent e) public void Dispose() { - Events?.Dispose(); Store?.Dispose(); } } diff --git a/WalletConnectSharp.Core/Controllers/Publisher.cs b/WalletConnectSharp.Core/Controllers/Publisher.cs index 904fb82..ac99f25 100644 --- a/WalletConnectSharp.Core/Controllers/Publisher.cs +++ b/WalletConnectSharp.Core/Controllers/Publisher.cs @@ -1,10 +1,8 @@ using WalletConnectSharp.Common.Model.Relay; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Core.Models.Heartbeat; using WalletConnectSharp.Core.Models.Publisher; using WalletConnectSharp.Core.Models.Relay; -using WalletConnectSharp.Events; using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Core.Controllers @@ -14,11 +12,8 @@ namespace WalletConnectSharp.Core.Controllers /// public class Publisher : IPublisher { - /// - /// The EventDelegator this publisher module is using - /// - public EventDelegator Events { get; } - + public event EventHandler OnPublishedMessage; + /// /// The Relayer this publisher module uses to publish messages /// @@ -56,14 +51,13 @@ public string Context public Publisher(IRelayer relayer) { Relayer = relayer; - Events = new EventDelegator(this); RegisterEventListeners(); } private void RegisterEventListeners() { - Relayer.Core.HeartBeat.On(HeartbeatEvents.Pulse, (_, __) => CheckQueue()); + Relayer.Core.HeartBeat.OnPulse += (_, _) => CheckQueue(); } private async void CheckQueue() @@ -98,6 +92,7 @@ private async void CheckQueue() var hash = HashUtils.HashMessage(@params.Message); await RpcPublish(@params.Topic, @params.Message, @params.Options.TTL, @params.Options.Tag, @params.Options.Relay); + this.OnPublishedMessage?.Invoke(this, @params); OnPublish(hash); } } @@ -178,19 +173,18 @@ public async Task Publish(string topic, string message, PublishOptions opts = nu { await RpcPublish(topic, message, @params.Options.TTL, @params.Options.Tag, @params.Options.Relay) .WithTimeout(TimeSpan.FromSeconds(45)); - this.Relayer.Events.Trigger(RelayerEvents.Publish, @params); + this.OnPublishedMessage?.Invoke(this, @params); OnPublish(hash); } catch (Exception e) { - this.Relayer.Events.Trigger(RelayerEvents.ConnectionStalled, new object()); + this.Relayer.TriggerConnectionStalled(); return; } } public void Dispose() { - Events?.Dispose(); } } } diff --git a/WalletConnectSharp.Core/Controllers/Relayer.cs b/WalletConnectSharp.Core/Controllers/Relayer.cs index 3a162a3..90dca2f 100644 --- a/WalletConnectSharp.Core/Controllers/Relayer.cs +++ b/WalletConnectSharp.Core/Controllers/Relayer.cs @@ -5,8 +5,6 @@ using WalletConnectSharp.Core.Interfaces; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Core.Models.Subscriber; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network; using WalletConnectSharp.Network.Models; @@ -25,11 +23,6 @@ public class Relayer : IRelayer /// public static readonly string DEFAULT_RELAY_URL = "wss://relay.walletconnect.com"; - /// - /// The EventDelegaor this Relayer module is using - /// - public EventDelegator Events { get; } - /// /// The Name of this Relayer module /// @@ -52,6 +45,13 @@ public string Context } } + public event EventHandler OnConnected; + public event EventHandler OnDisconnected; + public event EventHandler OnErrored; + public event EventHandler OnMessageReceived; + public event EventHandler OnTransportClosed; + public event EventHandler OnConnectionStalled; + /// /// The ICore module that is using this Relayer module /// @@ -131,7 +131,6 @@ public bool TransportExplicitlyClosed public Relayer(RelayerOptions opts) { Core = opts.Core; - Events = new EventDelegator(this); Messages = new MessageTracker(Core); Subscriber = new Subscriber(this); Publisher = new Publisher(this); @@ -199,19 +198,19 @@ protected virtual Task BuildConnection(string url) protected virtual void RegisterProviderEventListeners() { - Provider.On(ProviderEvents.RawRequestMessage, (sender, @event) => + Provider.RawMessageReceived += (sender, s) => { - OnProviderPayload(@event.EventData); - }); + OnProviderPayload(s); + }; - Provider.On(ProviderEvents.Connect, () => + Provider.Connected += (sender, connection) => { - Events.Trigger(RelayerEvents.Connect, new object()); - }); + this.OnConnected?.Invoke(this, EventArgs.Empty); + }; - Provider.On(ProviderEvents.Disconnect, async () => + Provider.Disconnected += async (sender, args) => { - Events.Trigger(RelayerEvents.Disconnect, new object()); + this.OnDisconnected?.Invoke(this, EventArgs.Empty); if (this._transportExplicitlyClosed) return; @@ -220,23 +219,23 @@ protected virtual void RegisterProviderEventListeners() await Task.Delay(1000); await RestartTransport(); - }); + }; - Provider.On(ProviderEvents.Error, (sender, @event) => + Provider.ErrorReceived += (sender, args) => { - Events.Trigger(RelayerEvents.Error, @event.EventData); - }); + this.OnErrored?.Invoke(this, args); + }; } protected virtual void RegisterEventListeners() { - this.Events.ListenFor(RelayerEvents.ConnectionStalled, async (sender, @event) => + this.OnConnectionStalled += async (sender, args) => { if (this.Provider.Connection.IsPaused) return; await this.RestartTransport(); - }); + }; } protected virtual async void OnProviderPayload(string payloadJson) @@ -274,7 +273,7 @@ protected virtual async Task OnMessageEvent(MessageEvent messageEvent) { if (await ShouldIgnoreMessageEvent(messageEvent)) return; - Events.Trigger(RelayerEvents.Message, messageEvent); + this.OnMessageReceived?.Invoke(this, messageEvent); await RecordMessageEvent(messageEvent); } @@ -314,12 +313,11 @@ public async Task Subscribe(string topic, SubscribeOptions opts = null) } TaskCompletionSource task1 = new TaskCompletionSource(); - this.Subscriber.Once(Controllers.Subscriber.SubscriberEvents.Created, - (sender, @event) => - { - if (@event.EventData.Topic == topic) - task1.TrySetResult(""); - }); + this.Subscriber.ListenOnce(nameof(this.Subscriber.Created), (sender, subscription) => + { + if (subscription.Topic == topic) + task1.TrySetResult(""); + }); return (await Task.WhenAll( task1.Task, @@ -345,7 +343,9 @@ public async Task Request(IRequestArguments request, object contex await this.ToEstablishConnection(); WCLogger.Log("[Relayer] Sending request through provider"); - return await this.Provider.Request(request, context); + var result = await this.Provider.Request(request, context); + + return result; } public async Task TransportClose() @@ -354,7 +354,7 @@ public async Task TransportClose() if (Connected) { await this.Provider.Disconnect(); - this.Events.Trigger(RelayerEvents.TransportClosed, new object()); + this.OnTransportClosed?.Invoke(this, EventArgs.Empty); } } @@ -373,23 +373,22 @@ public async Task TransportOpen(string relayUrl = null) } else { - this.Subscriber.Once(Controllers.Subscriber.SubscriberEvents.Resubscribed, - (sender, @event) => - { - task1.SetResult(true); - }); + this.Subscriber.ListenOnce(nameof(this.Subscriber.Resubscribed), (sender, args) => + { + task1.TrySetResult(true); + }); } TaskCompletionSource task2 = new TaskCompletionSource(); - void RejectTransportOpen(object sender, GenericEvent @event) + void RejectTransportOpen(object sender, EventArgs @event) { task2.TrySetException(new Exception("closeTransport called before connection was established")); } async void Task2() { - this.Events.ListenForOnce(RelayerEvents.TransportClosed, RejectTransportOpen); + var cleanupEvent = this.ListenOnce(nameof(OnTransportClosed), RejectTransportOpen); try { var connectionTask = this.Provider.Connect(); @@ -401,7 +400,7 @@ async void Task2() } finally { - this.Events.RemoveListener(RelayerEvents.TransportClosed, RejectTransportOpen); + cleanupEvent(); } } @@ -415,7 +414,7 @@ async void Task2() if (e.Message != "socket stalled") throw; - this.Events.Trigger(RelayerEvents.TransportClosed, new object()); + this.OnTransportClosed?.Invoke(this, EventArgs.Empty); } finally { @@ -430,9 +429,9 @@ public async Task RestartTransport(string relayUrl = null) if (this.Connected) { TaskCompletionSource task1 = new TaskCompletionSource(); - this.Provider.Once(ProviderEvents.Disconnect, (sender, @event) => + this.Provider.ListenOnce(nameof(this.Provider.Disconnected), (sender, args) => { - task1.SetResult(true); + task1.TrySetResult(true); }); await Task.WhenAll(task1.Task, this.TransportClose()); @@ -442,6 +441,11 @@ public async Task RestartTransport(string relayUrl = null) await TransportOpen(); } + void IRelayer.TriggerConnectionStalled() + { + this.OnConnectionStalled?.Invoke(this, EventArgs.Empty); + } + protected virtual void IsInitialized() { if (!initialized) @@ -484,8 +488,6 @@ private async Task ToEstablishConnection() public void Dispose() { - Events?.Dispose(); - // Core?.Dispose(); Subscriber?.Dispose(); Publisher?.Dispose(); Messages?.Dispose(); diff --git a/WalletConnectSharp.Core/Controllers/Subscriber.cs b/WalletConnectSharp.Core/Controllers/Subscriber.cs index effb82f..2b8e944 100644 --- a/WalletConnectSharp.Core/Controllers/Subscriber.cs +++ b/WalletConnectSharp.Core/Controllers/Subscriber.cs @@ -3,11 +3,8 @@ using WalletConnectSharp.Common.Model.Relay; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Core.Models.Heartbeat; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Core.Models.Subscriber; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Core.Controllers @@ -19,23 +16,10 @@ namespace WalletConnectSharp.Core.Controllers /// public class Subscriber : ISubscriber { - /// - /// Constants that define eventIds for the Subscriber events - /// - public static class SubscriberEvents - { - public static readonly string Created = "subscription_created"; - public static readonly string Deleted = "subscription_deleted"; - public static readonly string Expired = "subscription_expired"; - public static readonly string Disabled = "subscription_disabled"; - public static readonly string Sync = "subscription_sync"; - public static readonly string Resubscribed = "subscription_resubscribed"; - } - - /// - /// The EventDelegator this module is using - /// - public EventDelegator Events { get; } + public event EventHandler Sync; + public event EventHandler Resubscribed; + public event EventHandler Created; + public event EventHandler Deleted; /// /// The name of this Subscriber @@ -176,12 +160,10 @@ public string StorageKey public Subscriber(IRelayer relayer) { _relayer = relayer; - - Events = new EventDelegator(this); _logger = WCLogger.WithContext(Context); } - + /// /// Initialize this Subscriber, which will restore + resubscribe to all active subscriptions found /// in storage @@ -190,10 +172,11 @@ public async Task Init() { if (!_initialized) { + this._clientId = await this._relayer.Core.Crypto.GetClientId(); + await Restart(); RegisterEventListeners(); OnEnabled(); - this._clientId = await this._relayer.Core.Crypto.GetClientId(); } } @@ -207,36 +190,35 @@ private async Task Restart() protected virtual void RegisterEventListeners() { - _relayer.Core.HeartBeat.On(HeartbeatEvents.Pulse, (sender, @event) => + _relayer.Core.HeartBeat.OnPulse += (sender, @event) => { CheckPending(); - }); - - _relayer.On(RelayerEvents.Connect, (sender, @event) => + }; + + _relayer.Provider.Connected += (sender, connection) => { OnConnect(); - }); - - _relayer.On(RelayerEvents.Disconnect, (sender, @event) => + }; + + _relayer.Provider.Disconnected += (sender, args) => { OnDisconnect(); - }); - - this.On(SubscriberEvents.Created, AsyncPersist); + }; + + this.Created += AsyncPersist; - this.On(SubscriberEvents.Deleted, AsyncPersist); + this.Deleted += AsyncPersist; } - protected virtual async void AsyncPersist(object sender, GenericEvent @event) + protected virtual async void AsyncPersist(object sender, object @event) { await Persist(); } - - + protected virtual async Task Persist() { await SetRelayerSubscriptions(Values); - Events.Trigger(SubscriberEvents.Sync, new object()); + this.Sync?.Invoke(this, EventArgs.Empty); } protected virtual async Task GetRelayerSubscriptions() @@ -285,23 +267,19 @@ protected virtual async Task Reset() await this.BatchSubscribe(batch.ToArray()); } } - - this.Events.Trigger(SubscriberEvents.Resubscribed, new object()); + + this.Resubscribed?.Invoke(this, EventArgs.Empty); } protected virtual async Task Resubscribe(ActiveSubscription subscription) { if (!Ids.Contains(subscription.Id)) { - var @params = new PendingSubscription() - { - Relay = subscription.Relay, - Topic = subscription.Topic - }; + var @params = new PendingSubscription() { Relay = subscription.Relay, Topic = subscription.Topic }; if (pending.ContainsKey(@params.Topic)) pending.Remove(@params.Topic); - + pending.Add(@params.Topic, @params); var id = await RpcSubscribe(@params.Topic, @params.Relay); @@ -314,13 +292,9 @@ protected virtual async Task RpcSubscribe(string topic, ProtocolOptions var api = RelayProtocols.GetRelayProtocol(relay.Protocol); var request = new RequestArguments() { - Method = api.Subscribe, - Params = new JsonRpcSubscriberParams() - { - Topic = topic - } + Method = api.Subscribe, Params = new JsonRpcSubscriberParams() { Topic = topic } }; - + var subscribe = _relayer.Request(request); await subscribe.WithTimeout(20000); @@ -332,12 +306,7 @@ protected virtual Task RpcUnsubscribe(string topic, string id, ProtocolOptions r var api = RelayProtocols.GetRelayProtocol(relay.Protocol); var request = new RequestArguments() { - Method = api.Unsubscribe, - Params = new JsonRpcUnsubscribeParams() - { - Id = id, - Topic = topic - } + Method = api.Unsubscribe, Params = new JsonRpcUnsubscribeParams() { Id = id, Topic = topic } }; return _relayer.Request(request); @@ -347,7 +316,7 @@ protected virtual void OnEnabled() { _cached = Array.Empty(); _initialized = true; - + if (onSubscriberReady != null) onSubscriberReady(this, EventArgs.Empty); } @@ -368,7 +337,7 @@ protected virtual void OnDisable() protected virtual async void OnConnect() { if (RestartInProgress) return; - + await Restart(); OnEnabled(); } @@ -384,24 +353,14 @@ private async Task RestartToComplete() protected virtual void OnSubscribe(string id, PendingSubscription @params) { - SetSubscription(id, new ActiveSubscription() - { - Id = id, - Relay = @params.Relay, - Topic = @params.Topic - }); + SetSubscription(id, new ActiveSubscription() { Id = id, Relay = @params.Relay, Topic = @params.Topic }); pending.Remove(@params.Topic); } protected virtual void OnResubscribe(string id, PendingSubscription @params) { - AddSubscription(id, new ActiveSubscription() - { - Id = id, - Relay = @params.Relay, - Topic = @params.Topic - }); + AddSubscription(id, new ActiveSubscription() { Id = id, Relay = @params.Relay, Topic = @params.Topic }); pending.Remove(@params.Topic); } @@ -415,14 +374,14 @@ protected virtual async Task OnUnsubscribe(string topic, string id, Error reason { DeleteSubscription(id, reason); } - + await _relayer.Messages.Delete(topic); } protected virtual void SetSubscription(string id, ActiveSubscription subscription) { if (_subscriptions.ContainsKey(id)) return; - + AddSubscription(id, subscription); } @@ -430,23 +389,17 @@ protected virtual void AddSubscription(string id, ActiveSubscription subscriptio { if (_subscriptions.ContainsKey(id)) _subscriptions.Remove(id); - + _subscriptions.Add(id, subscription); _topicMap.Set(subscription.Topic, id); - Events.Trigger(SubscriberEvents.Created, subscription); + this.Created?.Invoke(this, subscription); } protected virtual Task UnsubscribeByTopic(string topic, UnsubscribeOptions opts = null) { if (opts == null) { - opts = new UnsubscribeOptions() - { - Relay = new ProtocolOptions() - { - Protocol = RelayProtocols.Default - } - }; + opts = new UnsubscribeOptions() { Relay = new ProtocolOptions() { Protocol = RelayProtocols.Default } }; } var ids = TopicMap.Get(topic); @@ -461,13 +414,11 @@ protected virtual void DeleteSubscription(string id, Error reason) var subscription = GetSubscription(id); _subscriptions.Remove(id); _topicMap.Delete(subscription.Topic, id); - Events.Trigger(SubscriberEvents.Deleted, new DeletedSubscription() - { - Id = id, - Reason = reason, - Relay = subscription.Relay, - Topic = subscription.Topic - }); + this.Deleted?.Invoke(this, + new DeletedSubscription() + { + Id = id, Reason = reason, Relay = subscription.Relay, Topic = subscription.Topic + }); } protected virtual async Task UnsubscribeById(string topic, string id, UnsubscribeOptions opts) @@ -476,11 +427,7 @@ protected virtual async Task UnsubscribeById(string topic, string id, Unsubscrib { opts = new UnsubscribeOptions() { - Id = id, - Relay = new ProtocolOptions() - { - Protocol = RelayProtocols.Default - } + Id = id, Relay = new ProtocolOptions() { Protocol = RelayProtocols.Default } }; } @@ -530,26 +477,16 @@ protected virtual void IsInitialized() public async Task Subscribe(string topic, SubscribeOptions opts = null) { await RestartToComplete(); - + if (opts == null) { - opts = new SubscribeOptions() - { - Relay = new ProtocolOptions() - { - Protocol = RelayProtocols.Default - } - }; + opts = new SubscribeOptions() { Relay = new ProtocolOptions() { Protocol = RelayProtocols.Default } }; } - + IsInitialized(); - var @params = new PendingSubscription() - { - Relay = opts.Relay, - Topic = topic - }; - + var @params = new PendingSubscription() { Relay = opts.Relay, Topic = topic }; + pending.Add(topic, @params); var id = await RpcSubscribe(topic, @params.Relay); OnSubscribe(id, @params); @@ -564,7 +501,7 @@ public async Task Subscribe(string topic, SubscribeOptions opts = null) public async Task Unsubscribe(string topic, UnsubscribeOptions opts = null) { await RestartToComplete(); - + IsInitialized(); if (opts != null && !string.IsNullOrWhiteSpace(opts.Id)) @@ -615,8 +552,7 @@ protected virtual async Task RpcBatchSubscribe(string[] topics, Protoc var api = RelayProtocols.GetRelayProtocol(relay.Protocol); var request = new RequestArguments() { - Method = api.BatchSubscribe, - Params = new BatchSubscribeParams() { Topics = topics } + Method = api.BatchSubscribe, Params = new BatchSubscribeParams() { Topics = topics } }; try { @@ -625,7 +561,7 @@ protected virtual async Task RpcBatchSubscribe(string[] topics, Protoc } catch (Exception e) { - this._relayer.Events.Trigger(RelayerEvents.ConnectionStalled, new object()); + this._relayer.TriggerConnectionStalled(); throw; } } @@ -636,12 +572,9 @@ protected virtual async Task BatchSubscribe(PendingSubscription[] subscriptions) var topics = subscriptions.Select(s => s.Topic).ToArray(); var relay = subscriptions[0].Relay; var result = await this.RpcBatchSubscribe(topics, relay); - OnBatchSubscribe(result.Select((r, i) => new ActiveSubscription() - { - Id = r, - Relay = relay, - Topic = topics[i] - }).ToArray()); + OnBatchSubscribe(result + .Select((r, i) => new ActiveSubscription() { Id = r, Relay = relay, Topic = topics[i] }) + .ToArray()); } private void OnBatchSubscribe(ActiveSubscription[] subscriptions) @@ -656,7 +589,6 @@ private void OnBatchSubscribe(ActiveSubscription[] subscriptions) public void Dispose() { - Events?.Dispose(); } } } diff --git a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs index c542234..c88102f 100644 --- a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs +++ b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs @@ -1,12 +1,11 @@ using Newtonsoft.Json; +using WalletConnectSharp.Common.Events; using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Crypto.Models; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Core.Controllers @@ -17,7 +16,8 @@ public class TypedMessageHandler : ITypedMessageHandler private Dictionary _decodeOptionsMap = new Dictionary(); private HashSet _typeSafeCache = new HashSet(); - public EventDelegator Events { get; } + public event EventHandler RawMessage; + private EventHandlerMap messageEventHandlerMap = new(); public ICore Core { get; } @@ -46,35 +46,34 @@ public string Context public TypedMessageHandler(ICore core) { this.Core = core; - this.Events = new EventDelegator(this); } public Task Init() { if (!_initialized) { - this.Core.Relayer.On(RelayerEvents.Message, RelayerMessageCallback); + this.Core.Relayer.OnMessageReceived += RelayerMessageCallback; } _initialized = true; return Task.CompletedTask; } - async void RelayerMessageCallback(object sender, GenericEvent e) + async void RelayerMessageCallback(object sender, MessageEvent e) { - var topic = e.EventData.Topic; - var message = e.EventData.Message; + 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) { - Events.Trigger($"request_{payload.Method}", e.EventData); + messageEventHandlerMap[$"request_{payload.Method}"](this, e); } else if (payload.IsResponse) { - Events.Trigger($"response_raw", new DecodedMessageEvent() + this.RawMessage?.Invoke(this, new DecodedMessageEvent() { Topic = topic, Message = message, @@ -96,12 +95,12 @@ public async void HandleMessageType(Func, Task> var method = RpcMethodAttribute.MethodForType(); var rpcHistory = await this.Core.History.JsonRpcHistoryOfType(); - async void RequestCallback(object sender, GenericEvent e) + async void RequestCallback(object sender, MessageEvent e) { if (requestCallback == null) return; - var topic = e.EventData.Topic; - var message = e.EventData.Message; + var topic = e.Topic; + var message = e.Message; var options = DecodeOptionForTopic(topic); @@ -112,12 +111,12 @@ async void RequestCallback(object sender, GenericEvent e) await requestCallback(topic, payload); } - async void ResponseCallback(object sender, GenericEvent e) + async void ResponseCallback(object sender, MessageEvent e) { if (responseCallback == null) return; - var topic = e.EventData.Topic; - var message = e.EventData.Message; + var topic = e.Topic; + var message = e.Message; var options = DecodeOptionForTopic(topic); @@ -142,12 +141,12 @@ async void ResponseCallback(object sender, GenericEvent e) } } - async void InspectResponseRaw(object sender, GenericEvent e) + async void InspectResponseRaw(object sender, DecodedMessageEvent e) { - var topic = e.EventData.Topic; - var message = e.EventData.Message; + var topic = e.Topic; + var message = e.Message; - var payload = e.EventData.Payload; + var payload = e.Payload; try { @@ -158,7 +157,7 @@ async void InspectResponseRaw(object sender, GenericEvent e var resMethod = record.Request.Method; // Trigger the true response event, which will trigger ResponseCallback - Events.Trigger($"response_{resMethod}", new MessageEvent() + messageEventHandlerMap[$"response_{resMethod}"](this, new MessageEvent() { Topic = topic, Message = message @@ -172,14 +171,13 @@ async void InspectResponseRaw(object sender, GenericEvent e // ignored if we can't find anything in the history } } - - Events.ListenFor($"request_{method}", RequestCallback); - - Events.ListenFor($"response_{method}", ResponseCallback); + + messageEventHandlerMap[$"request_{method}"] += RequestCallback; + messageEventHandlerMap[$"response_{method}"] += ResponseCallback; // Handle response_raw in this context // This will allow us to examine response_raw in every typed context registered - Events.ListenFor($"response_raw", InspectResponseRaw); + this.RawMessage += InspectResponseRaw; } /// @@ -374,7 +372,6 @@ public async Task SendError(long id, string topic, Error error, EncodeOpt public void Dispose() { - Events?.Dispose(); } private void EnsureTypeIsSerializerSafe(T testObject) diff --git a/WalletConnectSharp.Core/Interfaces/ICore.cs b/WalletConnectSharp.Core/Interfaces/ICore.cs index f23fb61..5ba2545 100644 --- a/WalletConnectSharp.Core/Interfaces/ICore.cs +++ b/WalletConnectSharp.Core/Interfaces/ICore.cs @@ -1,9 +1,7 @@ -using System.Threading.Tasks; using WalletConnectSharp.Common; using WalletConnectSharp.Core.Models; using WalletConnectSharp.Core.Models.Verify; using WalletConnectSharp.Crypto.Interfaces; -using WalletConnectSharp.Events.Interfaces; using WalletConnectSharp.Storage.Interfaces; namespace WalletConnectSharp.Core.Interfaces @@ -11,7 +9,7 @@ namespace WalletConnectSharp.Core.Interfaces /// /// Represents the Core module and all fields the Core module will have /// - public interface ICore : IModule, IEvents + public interface ICore : IModule { /// /// The Protocol string this Core module will use diff --git a/WalletConnectSharp.Core/Interfaces/IExpirer.cs b/WalletConnectSharp.Core/Interfaces/IExpirer.cs index 78db756..357542a 100644 --- a/WalletConnectSharp.Core/Interfaces/IExpirer.cs +++ b/WalletConnectSharp.Core/Interfaces/IExpirer.cs @@ -1,6 +1,5 @@ using WalletConnectSharp.Common; using WalletConnectSharp.Core.Models.Expirer; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Core.Interfaces { @@ -8,8 +7,16 @@ namespace WalletConnectSharp.Core.Interfaces /// The interface for the Expirer module. The Expirer module keeps track of expiration dates and triggers an event when an expiration date /// has passed /// - public interface IExpirer : IModule, IEvents + public interface IExpirer : IModule { + event EventHandler Created; + + event EventHandler Deleted; + + event EventHandler Expired; + + event EventHandler Sync; + /// /// The number of expirations this module is tracking /// diff --git a/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs b/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs index 225512d..f010a09 100644 --- a/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs +++ b/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs @@ -1,6 +1,4 @@ -using System.Threading.Tasks; using WalletConnectSharp.Common; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Core.Interfaces { @@ -8,8 +6,10 @@ namespace WalletConnectSharp.Core.Interfaces /// The HeartBeat module emits a pulse event at a specific interval simulating /// a heartbeat. It can be used as an setInterval replacement or timing actions /// - public interface IHeartBeat : IEvents, IModule + public interface IHeartBeat : IModule { + event EventHandler OnPulse; + /// /// The interval (in milliseconds) the Pulse event gets emitted/triggered /// diff --git a/WalletConnectSharp.Core/Interfaces/IJsonRpcHistory.cs b/WalletConnectSharp.Core/Interfaces/IJsonRpcHistory.cs index c41d434..88df109 100644 --- a/WalletConnectSharp.Core/Interfaces/IJsonRpcHistory.cs +++ b/WalletConnectSharp.Core/Interfaces/IJsonRpcHistory.cs @@ -1,10 +1,6 @@ -using System.Collections.Generic; -using System.Threading.Tasks; using WalletConnectSharp.Common; using WalletConnectSharp.Core.Models.History; -using WalletConnectSharp.Events.Interfaces; using WalletConnectSharp.Network; -using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Core.Interfaces { @@ -14,8 +10,16 @@ namespace WalletConnectSharp.Core.Interfaces /// /// The JSON RPC Request type /// The JSON RPC Response type - public interface IJsonRpcHistory : IModule, IEvents + public interface IJsonRpcHistory : IModule { + event EventHandler> Created; + + event EventHandler> Updated; + + event EventHandler> Deleted; + + event EventHandler Sync; + /// /// A mapping of Json RPC Records to their corresponding Json RPC id /// diff --git a/WalletConnectSharp.Core/Interfaces/IPairing.cs b/WalletConnectSharp.Core/Interfaces/IPairing.cs index 967e1c5..bc57cf4 100644 --- a/WalletConnectSharp.Core/Interfaces/IPairing.cs +++ b/WalletConnectSharp.Core/Interfaces/IPairing.cs @@ -1,14 +1,19 @@ using WalletConnectSharp.Common; using WalletConnectSharp.Core.Models.Pairing; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Core.Interfaces { /// /// The interface for a module that handles pairing two peers and storing related data /// - public interface IPairing : IModule, IEvents + public interface IPairing : IModule { + event EventHandler PairingExpired; + + event EventHandler PairingPinged; + + event EventHandler PairingDeleted; + /// /// Get the module that is handling the storage of /// diff --git a/WalletConnectSharp.Core/Interfaces/IPublisher.cs b/WalletConnectSharp.Core/Interfaces/IPublisher.cs index a0f2f9d..14b5861 100644 --- a/WalletConnectSharp.Core/Interfaces/IPublisher.cs +++ b/WalletConnectSharp.Core/Interfaces/IPublisher.cs @@ -1,7 +1,6 @@ -using System.Threading.Tasks; using WalletConnectSharp.Common; +using WalletConnectSharp.Core.Models.Publisher; using WalletConnectSharp.Core.Models.Relay; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Core.Interfaces { @@ -9,8 +8,10 @@ namespace WalletConnectSharp.Core.Interfaces /// An interface for the Publisher module. The Publisher module is responsible for sending messages to the /// WalletConnect relay server. /// - public interface IPublisher : IEvents, IModule + public interface IPublisher : IModule { + event EventHandler OnPublishedMessage; + /// /// The IRelayer instance this publisher is using to publish messages /// diff --git a/WalletConnectSharp.Core/Interfaces/IRelayer.cs b/WalletConnectSharp.Core/Interfaces/IRelayer.cs index d58f95e..c895c59 100644 --- a/WalletConnectSharp.Core/Interfaces/IRelayer.cs +++ b/WalletConnectSharp.Core/Interfaces/IRelayer.cs @@ -1,7 +1,6 @@ using WalletConnectSharp.Common; using WalletConnectSharp.Common.Model.Relay; using WalletConnectSharp.Core.Models.Relay; -using WalletConnectSharp.Events.Interfaces; using WalletConnectSharp.Network; namespace WalletConnectSharp.Core.Interfaces @@ -10,8 +9,20 @@ namespace WalletConnectSharp.Core.Interfaces /// The Relayer module handles the interaction with the WalletConnect relayer server. /// Each Relayer module uses a Publisher, Subscriber and a JsonRPCProvider. /// - public interface IRelayer : IEvents, IModule + public interface IRelayer : IModule { + event EventHandler OnConnected; + + event EventHandler OnDisconnected; + + event EventHandler OnErrored; + + event EventHandler OnMessageReceived; + + event EventHandler OnTransportClosed; + + event EventHandler OnConnectionStalled; + /// /// /// @@ -113,5 +124,7 @@ public interface IRelayer : IEvents, IModule public Task TransportOpen(string relayUrl = null); public Task RestartTransport(string relayUrl = null); + + internal void TriggerConnectionStalled(); } } diff --git a/WalletConnectSharp.Core/Interfaces/ISubscriber.cs b/WalletConnectSharp.Core/Interfaces/ISubscriber.cs index d6911e5..b2837c4 100644 --- a/WalletConnectSharp.Core/Interfaces/ISubscriber.cs +++ b/WalletConnectSharp.Core/Interfaces/ISubscriber.cs @@ -1,9 +1,6 @@ -using System.Collections.Generic; -using System.Threading.Tasks; using WalletConnectSharp.Common; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Core.Models.Subscriber; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Core.Interfaces { @@ -12,8 +9,13 @@ namespace WalletConnectSharp.Core.Interfaces /// of active and pending subscriptions. It will also resubscribe to topics if /// the backing Relayer connection disconnects /// - public interface ISubscriber : IEvents, IModule - { + public interface ISubscriber : IModule + { + event EventHandler Sync; + event EventHandler Resubscribed; + event EventHandler Created; + event EventHandler Deleted; + /// /// A dictionary of active subscriptions where the key is the id of the Subscription /// diff --git a/WalletConnectSharp.Core/Interfaces/ITypedMessageHandler.cs b/WalletConnectSharp.Core/Interfaces/ITypedMessageHandler.cs index 5a7236d..b73400a 100644 --- a/WalletConnectSharp.Core/Interfaces/ITypedMessageHandler.cs +++ b/WalletConnectSharp.Core/Interfaces/ITypedMessageHandler.cs @@ -1,7 +1,6 @@ using WalletConnectSharp.Common; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Crypto.Models; -using WalletConnectSharp.Events.Interfaces; using WalletConnectSharp.Network.Models; namespace WalletConnectSharp.Core.Interfaces @@ -10,8 +9,10 @@ namespace WalletConnectSharp.Core.Interfaces /// An interface for a module that handles both typed message sending (requests, responses and errors) and handles /// typed message listening (requests and responses) /// - public interface ITypedMessageHandler : IModule, IEvents + public interface ITypedMessageHandler : IModule { + event EventHandler RawMessage; + /// /// The this module is using to send / listen for messages /// diff --git a/WalletConnectSharp.Core/Models/Expirer/ExpirerEvents.cs b/WalletConnectSharp.Core/Models/Expirer/ExpirerEvents.cs deleted file mode 100644 index fbdc296..0000000 --- a/WalletConnectSharp.Core/Models/Expirer/ExpirerEvents.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace WalletConnectSharp.Core.Models.Expirer -{ - /// - /// A static class that holds all event ids of events the module emits - /// - public static class ExpirerEvents - { - public static readonly string Created = "expirer_created"; - - public static readonly string Deleted = "expirer_deleted"; - - public static readonly string Expired = "expirer_expired"; - - public static readonly string Sync = "expirer_sync"; - } -} diff --git a/WalletConnectSharp.Core/Models/Heartbeat/HeartbeatEvents.cs b/WalletConnectSharp.Core/Models/Heartbeat/HeartbeatEvents.cs deleted file mode 100644 index df86a57..0000000 --- a/WalletConnectSharp.Core/Models/Heartbeat/HeartbeatEvents.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace WalletConnectSharp.Core.Models.Heartbeat -{ - /// - /// A class containing all events the Heartbeat module emits - /// - public static class HeartbeatEvents - { - /// - /// The Pulse event id - /// - public static readonly string Pulse = "heartbeat_pulse"; - } -} diff --git a/WalletConnectSharp.Core/Models/History/HistoryEvents.cs b/WalletConnectSharp.Core/Models/History/HistoryEvents.cs deleted file mode 100644 index 8c1bd51..0000000 --- a/WalletConnectSharp.Core/Models/History/HistoryEvents.cs +++ /dev/null @@ -1,32 +0,0 @@ -using WalletConnectSharp.Core.Interfaces; - -namespace WalletConnectSharp.Core.Models.History -{ - /// - /// A class containing all events emitted by the JsonRpcHistory module - /// - public static class HistoryEvents - { - /// - /// The event id emitted when a new history entry was created - /// - public static readonly string Created = "history_created"; - - /// - /// The event id emitted when a history entry was updated, usually - /// through when the method - /// is invoked. - /// - public static readonly string Updated = "history_updated"; - - /// - /// The event id emitted when a history entry was deleted. - /// - public static readonly string Deleted = "history_deleted"; - - /// - /// The event id emitted when the history module has synced data to/from storage - /// - public static readonly string Sync = "history_sync"; - } -} diff --git a/WalletConnectSharp.Core/Models/Pairing/PairingEvents.cs b/WalletConnectSharp.Core/Models/Pairing/PairingEvents.cs deleted file mode 100644 index d0d1cd9..0000000 --- a/WalletConnectSharp.Core/Models/Pairing/PairingEvents.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace WalletConnectSharp.Core.Models.Pairing -{ - public static class PairingEvents - { - /// - /// The event id for the pairing expire event. Triggered when - /// a pairing has expired - /// - public const string PairingExpire = "pairing_expire"; - - /// - /// The event id for the pairing ping event. Triggered - /// when a pairing ping is received - /// - public const string PairingPing = "pairing_ping"; - - /// - /// The event id for the pairing delete event. Triggered - /// when a pairing has been deleted - /// - public const string PairingDelete = "pairing_delete"; - } -} diff --git a/WalletConnectSharp.Core/Models/Relay/RelayerEvents.cs b/WalletConnectSharp.Core/Models/Relay/RelayerEvents.cs deleted file mode 100644 index fedd92d..0000000 --- a/WalletConnectSharp.Core/Models/Relay/RelayerEvents.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace WalletConnectSharp.Core.Models.Relay -{ - /// - /// A static class that contains the several event ids emitted by the Relayer module - /// - public static class RelayerEvents - { - public static readonly string TransportClosed = "relayer_transport_closed"; - - public static readonly string ConnectionStalled = "relayer_connection_stalled"; - - /// - /// The event id for the publish event - /// - public static readonly string Publish = "relayer_publish"; - - /// - /// The event id for the message event - /// - public static readonly string Message = "relayer_message"; - - /// - /// The event id for the connect event - /// - public static readonly string Connect = "relayer_connect"; - - /// - /// The event id for the disconnect event - /// - public static readonly string Disconnect = "relayer_disconnect"; - - /// - /// The event id for the error event - /// - public static readonly string Error = "relayer_error"; - } -} diff --git a/WalletConnectSharp.Core/WalletConnectCore.cs b/WalletConnectSharp.Core/WalletConnectCore.cs index f576897..ad00dcf 100644 --- a/WalletConnectSharp.Core/WalletConnectCore.cs +++ b/WalletConnectSharp.Core/WalletConnectCore.cs @@ -1,4 +1,3 @@ -using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Core.Controllers; using WalletConnectSharp.Core.Interfaces; using WalletConnectSharp.Core.Models; @@ -6,7 +5,6 @@ using WalletConnectSharp.Core.Models.Verify; using WalletConnectSharp.Crypto; using WalletConnectSharp.Crypto.Interfaces; -using WalletConnectSharp.Events; using WalletConnectSharp.Network; using WalletConnectSharp.Storage; using WalletConnectSharp.Storage.Interfaces; @@ -51,11 +49,6 @@ public string Context } } - /// - /// - /// - public EventDelegator Events { get; } - /// /// If this module is initialized or not /// @@ -165,23 +158,6 @@ public WalletConnectCore(CoreOptions options = null) HeartBeat = new HeartBeat(); _optName = options.Name; - try - { - Events = new EventDelegator(this); - } - catch (ArgumentException) - { - // the context is likely being re-used. Let's randomize the context - // and log an error - WCLogger.LogError("The WalletConnectCore class is being re-initialized! It's likely a previous " + - "instance was not disposed of. It's recommended to re-use the same WalletConnectCore " + - "instance for the same project in the same runtime, event listener leaking can occur."); - - guid = $"-{Guid.NewGuid().ToString()}"; - - Events = new EventDelegator(this); - } - Expirer = new Expirer(this); Pairing = new Pairing(this); Verify = new Verifier(); @@ -224,7 +200,6 @@ private async Task Initialize() public void Dispose() { - Events?.Dispose(); HeartBeat?.Dispose(); Crypto?.Dispose(); Relayer?.Dispose(); diff --git a/WalletConnectSharp.Sign/Engine.cs b/WalletConnectSharp.Sign/Engine.cs index e301f12..de57db1 100644 --- a/WalletConnectSharp.Sign/Engine.cs +++ b/WalletConnectSharp.Sign/Engine.cs @@ -1,18 +1,15 @@ using System.Text.RegularExpressions; using Newtonsoft.Json; using WalletConnectSharp.Common; +using WalletConnectSharp.Common.Events; using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Model.Relay; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Core.Models.Expirer; using WalletConnectSharp.Core.Models.Pairing; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Core.Models.Verify; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Interfaces; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign.Interfaces; using WalletConnectSharp.Sign.Models; @@ -25,16 +22,11 @@ namespace WalletConnectSharp.Sign /// /// The Engine for running the Sign client protocol and code flow. /// - public partial class Engine : IEnginePrivate, IEngine, IModule, IEvents + public partial class Engine : IEnginePrivate, IEngine, IModule { private const long ProposalExpiry = Clock.THIRTY_DAYS; private const long SessionExpiry = Clock.SEVEN_DAYS; private const int KeyLength = 32; - - /// - /// The EventDelegator that should be used to listen to (or trigger) events - /// - public EventDelegator Events { get; } private bool _initialized = false; @@ -47,6 +39,8 @@ public partial class Engine : IEnginePrivate, IEngine, IModule, IEvents private ITypedMessageHandler MessageHandler => Client.Core.MessageHandler; + private EventHandlerMap> sessionEventsHandlerMap = new(); + /// /// The name of this Engine module /// @@ -72,7 +66,6 @@ public string Context public Engine(ISignClient client) { this.Client = client; - Events = new EventDelegator(this); logger = WCLogger.WithContext(Context); } @@ -86,6 +79,8 @@ public async Task Init() { if (!this._initialized) { + SetupEvents(); + await PrivateThis.Cleanup(); this.RegisterRelayerEvents(); this.RegisterExpirerEvents(); @@ -93,9 +88,20 @@ public async Task Init() } } + private void SetupEvents() + { + WrapPairingEvents(); + } + + private void WrapPairingEvents() + { + this.Client.Core.Pairing.PairingPinged += (sender, @event) => this.PairingPinged?.Invoke(sender, @event); + this.Client.Core.Pairing.PairingDeleted += (sender, @event) => this.PairingDeleted?.Invoke(sender, @event); + } + private void RegisterExpirerEvents() { - this.Client.Core.Expirer.On(ExpirerEvents.Expired, ExpiredCallback); + this.Client.Core.Expirer.Expired += ExpiredCallback; } private void RegisterRelayerEvents() @@ -109,6 +115,22 @@ private void RegisterRelayerEvents() MessageHandler.HandleMessageType(PrivateThis.OnSessionPingRequest, PrivateThis.OnSessionPingResponse); } + public event EventHandler SessionExpired; + public event EventHandler PairingExpired; + public event EventHandler SessionProposed; + public event EventHandler SessionConnected; + public event EventHandler SessionConnectionErrored; + public event EventHandler SessionUpdateRequest; + public event EventHandler SessionExtendRequest; + public event EventHandler SessionUpdated; + public event EventHandler SessionExtended; + public event EventHandler SessionPinged; + public event EventHandler SessionDeleted; + public event EventHandler SessionRejected; + public event EventHandler SessionApproved; + public event EventHandler PairingPinged; + public event EventHandler PairingDeleted; + /// /// Get static event handlers for requests / responses for the given type T, TR. This is similar to /// but uses EventHandler rather than callback functions @@ -141,7 +163,6 @@ public void HandleSessionRequestMessageType(FuncThe callback function to invoke when a request is received with the given request type /// The callback function to invoke when a response is received with the given response type /// The request type to trigger the requestCallback for. Will be wrapped in - /// The response type to trigger the responseCallback for public void HandleEventMessageType(Func>, Task> requestCallback, Func, Task> responseCallback) { Client.Core.MessageHandler.HandleMessageType(requestCallback, responseCallback); @@ -258,7 +279,7 @@ public async Task Connect(ConnectOptions options) WCLogger.Log($"Created public key pair"); TaskCompletionSource approvalTask = new TaskCompletionSource(); - this.Events.ListenForOnce("session_connect", async (sender, e) => + this.SessionConnected += async (sender, session) => { logger.Log("Got session_connect event for session struct"); if (approvalTask.Task.IsCompleted) @@ -267,7 +288,6 @@ public async Task Connect(ConnectOptions options) return; } - var session = e.EventData; session.Self.PublicKey = publicKey; var completeSession = session with { RequiredNamespaces = requiredNamespaces }; await PrivateThis.SetExpiry(session.Topic, session.Expiry.Value); @@ -278,9 +298,9 @@ public async Task Connect(ConnectOptions options) await this.Client.Core.Pairing.UpdateMetadata(topic, session.Peer.Metadata); } approvalTask.SetResult(completeSession); - }); - - this.Events.ListenForOnce>("session_connect", (sender, e) => + }; + + this.SessionConnectionErrored += (sender, exception) => { logger.Log("Got session_connect event for rpc response"); if (approvalTask.Task.IsCompleted) @@ -288,13 +308,15 @@ public async Task Connect(ConnectOptions options) logger.Log("approval already received though, skipping"); return; } - - if (e.EventData.IsError) + + if (exception == null) { - logger.LogError("Got session_connect error " + e.EventData.Error.Message); - approvalTask.SetException(e.EventData.Error.ToException()); + return; } - }); + + logger.LogError("Got session_connect error " + exception.Message); + approvalTask.SetException(exception); + }; if (string.IsNullOrWhiteSpace(topic)) { @@ -341,20 +363,19 @@ public async Task Pair(string uri) var topic = pairing.Topic; TaskCompletionSource sessionProposeTask = new TaskCompletionSource(); - - Client.Once(EngineEvents.SessionProposal, - delegate(object sender, GenericEvent @event) - { - var proposal = @event.EventData.Proposal; - if (topic != proposal.PairingTopic) - return; - if (@event.EventData.VerifiedContext.Validation == Validation.Invalid) - sessionProposeTask.SetException(new Exception( - $"Could not validate, invalid validation status {@event.EventData.VerifiedContext.Validation} for origin {@event.EventData.VerifiedContext.Origin}")); - else - sessionProposeTask.SetResult(proposal); - }); + Client.ListenOnce(nameof(Client.SessionProposed), (sender, args) => + { + var proposal = args.Proposal; + if (topic != proposal.PairingTopic) + return; + + if (args.VerifiedContext.Validation == Validation.Invalid) + sessionProposeTask.SetException(new Exception( + $"Could not validate, invalid validation status {args.VerifiedContext.Validation} for origin {args.VerifiedContext.Origin}")); + else + sessionProposeTask.SetResult(proposal); + }); return await sessionProposeTask.Task; } @@ -406,11 +427,11 @@ public async Task Approve(ApproveParams @params) var requestId = await MessageHandler.SendRequest(sessionTopic, sessionSettle); var acknowledgedTask = new TaskCompletionSource(); - - this.Events.ListenForOnce>($"session_approve{requestId}", (sender, e) => + + this.sessionEventsHandlerMap.ListenOnce($"session_approve{requestId}", (sender, args) => { - if (e.EventData.IsError) - acknowledgedTask.SetException(e.EventData.Error.ToException()); + if (args.IsError) + acknowledgedTask.SetException(args.Error.ToException()); else acknowledgedTask.SetResult(this.Client.Session.Get(sessionTopic)); }); @@ -491,12 +512,12 @@ public async Task UpdateSession(string topic, Namespaces names }); TaskCompletionSource acknowledgedTask = new TaskCompletionSource(); - this.Events.ListenForOnce>($"session_update{id}", (sender, e) => + this.sessionEventsHandlerMap.ListenOnce($"session_update{id}", (sender, args) => { - if (e.EventData.IsError) - acknowledgedTask.SetException(e.EventData.Error.ToException()); + if (args.IsError) + acknowledgedTask.SetException(args.Error.ToException()); else - acknowledgedTask.SetResult(e.EventData.Result); + acknowledgedTask.SetResult(args.Result); }); await this.Client.Session.Update(topic, new SessionStruct() @@ -519,12 +540,13 @@ public async Task Extend(string topic) var id = await MessageHandler.SendRequest(topic, new SessionExtend()); TaskCompletionSource acknowledgedTask = new TaskCompletionSource(); - this.Events.ListenForOnce>($"session_extend{id}", (sender, e) => + + this.sessionEventsHandlerMap.ListenOnce($"session_extend{id}", (sender, args) => { - if (e.EventData.IsError) - acknowledgedTask.SetException(e.EventData.Error.ToException()); + if (args.IsError) + acknowledgedTask.SetException(args.Error.ToException()); else - acknowledgedTask.SetResult(e.EventData.Result); + acknowledgedTask.SetResult(args.Result); }); await PrivateThis.SetExpiry(topic, Clock.CalculateExpiry(SessionExpiry)); @@ -655,12 +677,12 @@ public async Task Ping(string topic) { var id = await MessageHandler.SendRequest(topic, new SessionPing()); var done = new TaskCompletionSource(); - this.Events.ListenForOnce>($"session_ping{id}", (sender, e) => + this.sessionEventsHandlerMap.ListenOnce($"session_ping{id}", (sender, args) => { - if (e.EventData.IsError) - done.SetException(e.EventData.Error.ToException()); + if (args.IsError) + done.SetException(args.Error.ToException()); else - done.SetResult(e.EventData.Result); + done.SetResult(args.Result); }); await done.Task; } @@ -744,7 +766,6 @@ public Task Reject(ProposalStruct proposalStruct, Error error) public void Dispose() { - Events?.Dispose(); Client?.Dispose(); } } diff --git a/WalletConnectSharp.Sign/EngineEvents.cs b/WalletConnectSharp.Sign/EngineEvents.cs deleted file mode 100644 index f205f10..0000000 --- a/WalletConnectSharp.Sign/EngineEvents.cs +++ /dev/null @@ -1,87 +0,0 @@ -using WalletConnectSharp.Sign.Interfaces; -using WalletConnectSharp.Sign.Models.Engine.Events; - -namespace WalletConnectSharp.Sign -{ - /// - /// A static class that holds all event ids the module - /// will emit - /// - public static class EngineEvents - { - /// - /// The event id for the session expire event. Triggered - /// when a session has expired - /// - public const string SessionExpire = "session_expire"; - - /// - /// The event id for the pairing expire event. Triggered when - /// a pairing has expired - /// - public const string PairingExpire = "pairing_expire"; - - /// - /// The event id for the session proposal event. Triggered - /// when a new session proposal is received - /// - public const string SessionProposal = "session_proposal"; - - /// - /// The event id for the session connect event. Triggered - /// when a new session has been connected - /// - public const string SessionConnect = "session_connect"; - - /// - /// The event id for the session update event. Triggered - /// when a session's data has been updated - /// - public const string SessionUpdate = "session_update"; - - /// - /// The event id for the session extend event. Triggered - /// when a session's expiration date has been extended - /// - public const string SessionExtend = "session_extend"; - - /// - /// The event id for the session ping event. Triggered - /// when a session ping is received - /// - public const string SessionPing = "session_ping"; - - /// - /// The event id for the pairing ping event. Triggered - /// when a pairing ping is received - /// - public const string PairingPing = "pairing_ping"; - - /// - /// The event id for the session delete event. Triggered - /// when a session has been deleted - /// - public const string SessionDelete = "session_delete"; - - /// - /// The event id for the pairing delete event. Triggered - /// when a pairing has been deleted - /// - public const string PairingDelete = "pairing_delete"; - - /// - /// The event id for the session request event. Triggered - /// when ANY session request is received during a session - /// - public const string SessionRequest = "session_request"; - - /// - /// The event id for the session event event. Triggered - /// when ANY session event is received during a session - /// - /// NOTE: Session events are only received/triggered through the - /// function. - /// - public const string SessionEvent = "session_event"; - } -} diff --git a/WalletConnectSharp.Sign/Interfaces/IEngine.cs b/WalletConnectSharp.Sign/Interfaces/IEngine.cs index 333fbaa..7f9ae03 100644 --- a/WalletConnectSharp.Sign/Interfaces/IEngine.cs +++ b/WalletConnectSharp.Sign/Interfaces/IEngine.cs @@ -20,7 +20,7 @@ public interface IEngine : IEngineAPI /// /// The this Engine is using /// - ISignClient Client { get; } + ISignClient Client { get; } /// /// Initialize the Engine. This loads any persistant state and connects to the WalletConnect @@ -29,15 +29,6 @@ public interface IEngine : IEngineAPI /// Task Init(); - /// - /// Get static event handlers for requests / responses for the given type T, TR. This is similar to - /// but uses EventHandler rather than callback functions - /// - /// The request type to trigger the requestCallback for - /// The response type to trigger the responseCallback for - /// The managing events for the given types T, TR - TypedEventHandler SessionRequestEvents(); - /// /// Parse a session proposal URI and return all information in the URI. /// diff --git a/WalletConnectSharp.Sign/Interfaces/IEngineAPI.cs b/WalletConnectSharp.Sign/Interfaces/IEngineAPI.cs index 21f6746..b544125 100644 --- a/WalletConnectSharp.Sign/Interfaces/IEngineAPI.cs +++ b/WalletConnectSharp.Sign/Interfaces/IEngineAPI.cs @@ -1,3 +1,4 @@ +using WalletConnectSharp.Core.Models.Pairing; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign.Models; @@ -13,6 +14,45 @@ namespace WalletConnectSharp.Sign.Interfaces /// public interface IEngineAPI { + event EventHandler SessionExpired; + + event EventHandler PairingExpired; + + event EventHandler SessionProposed; + + event EventHandler SessionConnected; + + event EventHandler SessionConnectionErrored; + + event EventHandler SessionUpdateRequest; + + event EventHandler SessionExtendRequest; + + event EventHandler SessionUpdated; + + event EventHandler SessionExtended; + + event EventHandler SessionPinged; + + event EventHandler SessionDeleted; + + event EventHandler SessionRejected; + + event EventHandler SessionApproved; + + event EventHandler PairingPinged; + + event EventHandler PairingDeleted; + + /// + /// Get static event handlers for requests / responses for the given type T, TR. This is similar to + /// but uses EventHandler rather than callback functions + /// + /// The request type to trigger the requestCallback for + /// The response type to trigger the responseCallback for + /// The managing events for the given types T, TR + TypedEventHandler SessionRequestEvents(); + /// /// Get all pending session requests as an array /// diff --git a/WalletConnectSharp.Sign/Interfaces/IEnginePrivate.cs b/WalletConnectSharp.Sign/Interfaces/IEnginePrivate.cs index 9e0c4bd..908b293 100644 --- a/WalletConnectSharp.Sign/Interfaces/IEnginePrivate.cs +++ b/WalletConnectSharp.Sign/Interfaces/IEnginePrivate.cs @@ -41,10 +41,6 @@ public interface IEnginePrivate internal Task OnSessionDeleteRequest(string topic, JsonRpcRequest payload); - internal Task OnSessionRequest(string topic, JsonRpcRequest> payload); - - internal Task OnSessionEventRequest(string topic, JsonRpcRequest> payload); - internal Task IsValidConnect(ConnectOptions options); internal Task IsValidPair(string uri); diff --git a/WalletConnectSharp.Sign/Interfaces/ISignClient.cs b/WalletConnectSharp.Sign/Interfaces/ISignClient.cs index 4d64cc5..5367685 100644 --- a/WalletConnectSharp.Sign/Interfaces/ISignClient.cs +++ b/WalletConnectSharp.Sign/Interfaces/ISignClient.cs @@ -1,9 +1,6 @@ using WalletConnectSharp.Common; using WalletConnectSharp.Core; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Core.Models; -using WalletConnectSharp.Core.Models.Pairing; -using WalletConnectSharp.Events.Interfaces; using WalletConnectSharp.Sign.Models; namespace WalletConnectSharp.Sign.Interfaces @@ -12,7 +9,7 @@ namespace WalletConnectSharp.Sign.Interfaces /// An interface for the Sign Client. This includes modules the Sign Client will use, the ICore module /// this Sign Client is using, as well as public facing Engine functions and properties. /// - public interface ISignClient : IModule, IEvents, IEngineAPI + public interface ISignClient : IModule, IEngineAPI { /// /// The Metadata this Sign Client is broadcasting with diff --git a/WalletConnectSharp.Sign/Internals/EngineHandler.cs b/WalletConnectSharp.Sign/Internals/EngineHandler.cs index 710b94c..f06fee2 100644 --- a/WalletConnectSharp.Sign/Internals/EngineHandler.cs +++ b/WalletConnectSharp.Sign/Internals/EngineHandler.cs @@ -3,7 +3,6 @@ using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Utils; using WalletConnectSharp.Core.Models.Expirer; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign.Interfaces; using WalletConnectSharp.Sign.Models; @@ -14,9 +13,9 @@ namespace WalletConnectSharp.Sign { public partial class Engine { - async void ExpiredCallback(object sender, GenericEvent e) + async void ExpiredCallback(object sender, ExpirerEventArgs e) { - var target = new ExpirerTarget(e.EventData.Target); + var target = new ExpirerTarget(e.Target); if (target.Id != null && this.Client.PendingRequests.Keys.Contains((long)target.Id)) { @@ -33,8 +32,9 @@ await PrivateThis.DeletePendingSessionRequest((long)target.Id, return; } + var session = this.Client.Session.Get(topic); await PrivateThis.DeleteSession(topic); - this.Client.Events.Trigger(EngineEvents.SessionExpire, topic); + this.SessionExpired?.Invoke(this, session); } else if (target.Id != null) { @@ -63,7 +63,7 @@ async Task IEnginePrivate.OnSessionProposeRequest(string topic, JsonRpcRequest(payload.Id, topic, true); - this.Events.Trigger(EngineEvents.SessionConnect, session); + this.SessionConnected?.Invoke(this, session); } catch (WalletConnectException e) { @@ -172,10 +172,15 @@ async Task IEnginePrivate.OnSessionSettleRequest(string topic, JsonRpcRequest payload) { var id = payload.Id; + var session = this.Client.Session.Get(topic); if (payload.IsError) { - await this.Client.Session.Delete(topic, Error.FromErrorType(ErrorType.USER_DISCONNECTED)); - this.Events.Trigger($"session_approve{id}", payload); + var error = Error.FromErrorType(ErrorType.USER_DISCONNECTED); + await this.Client.Session.Delete(topic, error); + this.SessionRejected?.Invoke(this, session); + + // Still used do not remove + this.sessionEventsHandlerMap[$"session_approve{id}"](this, payload); } else { @@ -183,7 +188,8 @@ async Task IEnginePrivate.OnSessionSettleResponse(string topic, JsonRpcResponse< { Acknowledged = true }); - this.Events.Trigger($"session_approve{id}", payload); + this.SessionApproved?.Invoke(this, session); + this.sessionEventsHandlerMap[$"session_approve{id}"](this, payload); } } @@ -201,7 +207,7 @@ async Task IEnginePrivate.OnSessionUpdateRequest(string topic, JsonRpcRequest(id, topic, true); - this.Client.Events.Trigger(EngineEvents.SessionUpdate, new SessionUpdateEvent() + this.SessionUpdateRequest?.Invoke(this, new SessionUpdateEvent() { Id = id, Topic = topic, @@ -217,7 +223,13 @@ async Task IEnginePrivate.OnSessionUpdateRequest(string topic, JsonRpcRequest payload) { var id = payload.Id; - this.Events.Trigger($"session_update{id}", payload); + this.SessionUpdated?.Invoke(this, new SessionEvent() + { + Id = id, + Topic = topic, + }); + // Still used, do not remove + this.sessionEventsHandlerMap[$"session_update{id}"](this, payload); } async Task IEnginePrivate.OnSessionExtendRequest(string topic, JsonRpcRequest payload) @@ -228,7 +240,7 @@ async Task IEnginePrivate.OnSessionExtendRequest(string topic, JsonRpcRequest(id, topic, true); - this.Client.Events.Trigger(EngineEvents.SessionExtend, new SessionEvent() + this.SessionExtendRequest?.Invoke(this, new SessionEvent() { Id = id, Topic = topic @@ -243,7 +255,13 @@ async Task IEnginePrivate.OnSessionExtendRequest(string topic, JsonRpcRequest payload) { var id = payload.Id; - this.Events.Trigger($"session_extend{id}", payload); + this.SessionExtended?.Invoke(this, new SessionEvent() + { + Topic = topic, + Id = id + }); + // Still used, do not remove + this.sessionEventsHandlerMap[$"session_extend{id}"](this, payload); } async Task IEnginePrivate.OnSessionPingRequest(string topic, JsonRpcRequest payload) @@ -253,7 +271,7 @@ async Task IEnginePrivate.OnSessionPingRequest(string topic, JsonRpcRequest(id, topic, true); - this.Client.Events.Trigger(EngineEvents.SessionPing, new SessionEvent() + this.SessionPinged?.Invoke(this, new SessionEvent() { Id = id, Topic = topic @@ -272,8 +290,15 @@ async Task IEnginePrivate.OnSessionPingResponse(string topic, JsonRpcResponse payload) @@ -285,7 +310,7 @@ async Task IEnginePrivate.OnSessionDeleteRequest(string topic, JsonRpcRequest(id, topic, true); await PrivateThis.DeleteSession(topic); - this.Client.Events.Trigger(EngineEvents.SessionDelete, new SessionEvent() + this.SessionDeleted?.Invoke(this, new SessionEvent() { Topic = topic, Id = id @@ -296,46 +321,5 @@ async Task IEnginePrivate.OnSessionDeleteRequest(string topic, JsonRpcRequest(id, topic, Error.FromException(e)); } } - - async Task IEnginePrivate.OnSessionRequest(string topic, JsonRpcRequest> payload) - { - var id = payload.Id; - var @params = payload.Params; - try - { - await PrivateThis.IsValidRequest(topic, @params.Request, @params.ChainId); - this.Client.Events.Trigger(EngineEvents.SessionRequest, new SessionRequestEvent() - { - Topic = topic, - Id = id, - ChainId = @params.ChainId, - Request = @params.Request - }); - } - catch (WalletConnectException e) - { - await MessageHandler.SendError, TR>(id, topic, Error.FromException(e)); - } - } - - async Task IEnginePrivate.OnSessionEventRequest(string topic, JsonRpcRequest> payload) - { - var id = payload.Id; - var @params = payload.Params; - try - { - await PrivateThis.IsValidEmit(topic, @params.Event, @params.ChainId); - this.Client.Events.Trigger(EngineEvents.SessionEvent, new EmitEvent() - { - Topic = topic, - Id = id, - Params = @params - }); - } - catch (WalletConnectException e) - { - await MessageHandler.SendError, object>(id, topic, Error.FromException(e)); - } - } } } diff --git a/WalletConnectSharp.Sign/Internals/EngineTasks.cs b/WalletConnectSharp.Sign/Internals/EngineTasks.cs index dd3e445..71c7874 100644 --- a/WalletConnectSharp.Sign/Internals/EngineTasks.cs +++ b/WalletConnectSharp.Sign/Internals/EngineTasks.cs @@ -1,4 +1,5 @@ using System.Security.Cryptography; +using WalletConnectSharp.Common.Logging; using WalletConnectSharp.Common.Model.Errors; using WalletConnectSharp.Common.Model.Relay; using WalletConnectSharp.Common.Utils; @@ -89,8 +90,13 @@ async Task IEnginePrivate.SetProposal(long id, ProposalStruct proposal) Task IEnginePrivate.Cleanup() { - List sessionTopics = (from session in this.Client.Session.Values.Where(e => e.Expiry != null) where Clock.IsExpired(session.Expiry.Value) select session.Topic).ToList(); - List proposalIds = (from p in this.Client.Proposal.Values.Where(e => e.Expiry != null) where Clock.IsExpired(p.Expiry.Value) select p.Id).ToList(); + List sessionTopics = (from session in this.Client.Session.Values where session.Expiry != null && Clock.IsExpired(session.Expiry.Value) select session.Topic).ToList(); + List proposalIds = (from p in this.Client.Proposal.Values where p.Expiry != null && Clock.IsExpired(p.Expiry.Value) select p.Id).ToList(); + + if (sessionTopics.Count == 0 && proposalIds.Count == 0) + return Task.CompletedTask; + + WCLogger.Log($"Clearing {sessionTopics.Count} expired sessions and {proposalIds.Count} expired proposals"); return Task.WhenAll( sessionTopics.Select(t => PrivateThis.DeleteSession(t)).Concat( diff --git a/WalletConnectSharp.Sign/WalletConnectSignClient.cs b/WalletConnectSharp.Sign/WalletConnectSignClient.cs index 4e3e242..9a57fc8 100644 --- a/WalletConnectSharp.Sign/WalletConnectSignClient.cs +++ b/WalletConnectSharp.Sign/WalletConnectSignClient.cs @@ -2,9 +2,9 @@ using WalletConnectSharp.Core; using WalletConnectSharp.Core.Controllers; using WalletConnectSharp.Core.Interfaces; +using WalletConnectSharp.Core.Models.Pairing; using WalletConnectSharp.Core.Models.Relay; using WalletConnectSharp.Crypto; -using WalletConnectSharp.Events; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign.Controllers; using WalletConnectSharp.Sign.Interfaces; @@ -52,12 +52,6 @@ public class WalletConnectSignClient : ISignClient /// The context string for this Sign Client module /// public string Context { get; } - - /// - /// The this Sign Client module will use - /// to trigger events. Listen to Client events using this. - /// - public EventDelegator Events { get; } /// /// The Metadata for this instance of the Sign Client module @@ -118,8 +112,29 @@ public int Version return VERSION; } } - - + + + public event EventHandler SessionExpired; + public event EventHandler PairingExpired; + public event EventHandler SessionProposed; + public event EventHandler SessionConnected; + public event EventHandler SessionConnectionErrored; + public event EventHandler SessionUpdateRequest; + public event EventHandler SessionExtendRequest; + public event EventHandler SessionUpdated; + public event EventHandler SessionExtended; + public event EventHandler SessionPinged; + public event EventHandler SessionDeleted; + public event EventHandler SessionRejected; + public event EventHandler SessionApproved; + public event EventHandler PairingPinged; + public event EventHandler PairingDeleted; + + public TypedEventHandler SessionRequestEvents() + { + return Engine.SessionRequestEvents(); + } + public PendingRequestStruct[] PendingSessionRequests { get @@ -181,13 +196,36 @@ private WalletConnectSignClient(SignClientOptions options) else Core = new WalletConnectCore(options); - Events = new EventDelegator(this); - PendingRequests = new PendingRequests(Core); PairingStore = new PairingStore(Core); Session = new Session(Core); Proposal = new Proposal(Core); Engine = new Engine(this); + + SetupEvents(); + } + + private void SetupEvents() + { + WrapEngineEvents(); + } + + private void WrapEngineEvents() + { + Engine.SessionExpired += (sender, @struct) => this.SessionExpired?.Invoke(sender, @struct); + Engine.PairingExpired += (sender, @struct) => this.PairingExpired?.Invoke(sender, @struct); + Engine.SessionProposed += (sender, @event) => this.SessionProposed?.Invoke(sender, @event); + Engine.SessionConnected += (sender, @struct) => this.SessionConnected?.Invoke(sender, @struct); + Engine.SessionConnectionErrored += + (sender, exception) => this.SessionConnectionErrored?.Invoke(sender, exception); + Engine.SessionUpdateRequest += (sender, @event) => this.SessionUpdateRequest?.Invoke(sender, @event); + Engine.SessionExtendRequest += (sender, @event) => this.SessionExtendRequest?.Invoke(sender, @event); + Engine.SessionPinged += (sender, @event) => this.SessionPinged?.Invoke(sender, @event); + Engine.SessionDeleted += (sender, @event) => this.SessionDeleted?.Invoke(sender, @event); + Engine.SessionRejected += (sender, @struct) => this.SessionRejected?.Invoke(sender, @struct); + Engine.SessionApproved += (sender, @struct) => this.SessionApproved?.Invoke(sender, @struct); + Engine.SessionExtended += (sender, @event) => this.SessionExtended?.Invoke(sender, @event); + Engine.SessionUpdated += (sender, @event) => this.SessionUpdated?.Invoke(sender, @event); } /// @@ -408,7 +446,6 @@ private async Task Initialize() public void Dispose() { - Events?.Dispose(); Core?.Dispose(); PairingStore?.Dispose(); Session?.Dispose(); diff --git a/WalletConnectSharp.Web3Wallet/Controllers/Web3WalletEngine.cs b/WalletConnectSharp.Web3Wallet/Controllers/Web3WalletEngine.cs index 57c65ba..737b6c5 100644 --- a/WalletConnectSharp.Web3Wallet/Controllers/Web3WalletEngine.cs +++ b/WalletConnectSharp.Web3Wallet/Controllers/Web3WalletEngine.cs @@ -2,9 +2,6 @@ using WalletConnectSharp.Auth.Interfaces; using WalletConnectSharp.Auth.Models; using WalletConnectSharp.Common.Model.Errors; -using WalletConnectSharp.Events; -using WalletConnectSharp.Events.Interfaces; -using WalletConnectSharp.Events.Model; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign; using WalletConnectSharp.Sign.Interfaces; @@ -19,6 +16,15 @@ public class Web3WalletEngine : IWeb3WalletEngine { private bool _initialized; + public event EventHandler SessionExpired; + public event EventHandler SessionProposed; + public event EventHandler SessionConnected; + public event EventHandler SessionConnectionErrored; + public event EventHandler SessionUpdated; + public event EventHandler SessionExtended; + public event EventHandler SessionPinged; + public event EventHandler SessionDeleted; + public IDictionary ActiveSessions { get @@ -171,21 +177,18 @@ public string FormatMessage(Cacao.CacaoRequestPayload payload, string iss) return this.AuthClient.FormatMessage(payload, iss); } - private void PropagateEventToClient(string eventName, IEvents source) - { - EventHandler> eventHandler = (sender, @event) => - { - this.Client.Events.TriggerType(eventName, @event.EventData, @event.EventData.GetType()); - }; - - source.On(eventName, eventHandler); - } - private void InitializeEventListeners() { - PropagateEventToClient("session_proposal", SignClient); - PropagateEventToClient("session_request", SignClient); - PropagateEventToClient("session_delete", SignClient); + // Propagate sign events + SignClient.SessionProposed += (sender, @event) => this.SessionProposed?.Invoke(sender, @event); + SignClient.SessionDeleted += (sender, @event) => this.SessionDeleted?.Invoke(sender, @event); + SignClient.SessionPinged += (sender, @event) => this.SessionPinged?.Invoke(sender, @event); + SignClient.SessionExtendRequest += (sender, @event) => this.SessionExtended?.Invoke(sender, @event); + SignClient.SessionExpired += (sender, @struct) => this.SessionExpired?.Invoke(sender, @struct); + SignClient.SessionConnected += (sender, @struct) => this.SessionConnected?.Invoke(sender, @struct); + SignClient.SessionConnectionErrored += + (sender, exception) => this.SessionConnectionErrored?.Invoke(sender, exception); + SignClient.SessionUpdateRequest += (sender, @event) => this.SessionUpdated?.Invoke(sender, @event); // Propagate auth events AuthClient.AuthRequested += OnAuthRequest; diff --git a/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3Wallet.cs b/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3Wallet.cs index 89283b3..fc1639d 100644 --- a/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3Wallet.cs +++ b/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3Wallet.cs @@ -1,12 +1,10 @@ -using WalletConnectSharp.Auth; -using WalletConnectSharp.Common; +using WalletConnectSharp.Common; using WalletConnectSharp.Core; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Events.Interfaces; namespace WalletConnectSharp.Web3Wallet.Interfaces; -public interface IWeb3Wallet : IModule, IEvents, IWeb3WalletApi +public interface IWeb3Wallet : IModule, IWeb3WalletApi { IWeb3WalletEngine Engine { get; } diff --git a/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3WalletApi.cs b/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3WalletApi.cs index f0a796a..d7b2888 100644 --- a/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3WalletApi.cs +++ b/WalletConnectSharp.Web3Wallet/Interfaces/IWeb3WalletApi.cs @@ -9,6 +9,22 @@ namespace WalletConnectSharp.Web3Wallet.Interfaces; public interface IWeb3WalletApi : IAuthClientEvents { + event EventHandler SessionExpired; + + event EventHandler SessionProposed; + + event EventHandler SessionConnected; + + event EventHandler SessionConnectionErrored; + + event EventHandler SessionUpdated; + + event EventHandler SessionExtended; + + event EventHandler SessionPinged; + + event EventHandler SessionDeleted; + IDictionary ActiveSessions { get; } IDictionary PendingSessionProposals { get; } diff --git a/WalletConnectSharp.Web3Wallet/Web3WalletClient.cs b/WalletConnectSharp.Web3Wallet/Web3WalletClient.cs index 4446485..4fc411a 100644 --- a/WalletConnectSharp.Web3Wallet/Web3WalletClient.cs +++ b/WalletConnectSharp.Web3Wallet/Web3WalletClient.cs @@ -2,7 +2,6 @@ using WalletConnectSharp.Auth.Models; using WalletConnectSharp.Core; using WalletConnectSharp.Core.Interfaces; -using WalletConnectSharp.Events; using WalletConnectSharp.Network.Models; using WalletConnectSharp.Sign.Models; using WalletConnectSharp.Sign.Models.Engine.Events; @@ -15,7 +14,15 @@ public class Web3WalletClient : IWeb3Wallet { public string Name { get; } public string Context { get; } - public EventDelegator Events { get; } + + public event EventHandler SessionExpired; + public event EventHandler SessionProposed; + public event EventHandler SessionConnected; + public event EventHandler SessionConnectionErrored; + public event EventHandler SessionUpdated; + public event EventHandler SessionExtended; + public event EventHandler SessionPinged; + public event EventHandler SessionDeleted; public IDictionary ActiveSessions { @@ -71,8 +78,22 @@ private Web3WalletClient(ICore core, Metadata metadata, string name = null) this.Context = $"{Name}-context"; this.Core = core; - this.Events = new EventDelegator(this); this.Engine = new Web3WalletEngine(this); + + WrapEngineEvents(); + } + + private void WrapEngineEvents() + { + Engine.SessionExpired += (sender, @struct) => this.SessionExpired?.Invoke(sender, @struct); + Engine.SessionProposed += (sender, @event) => this.SessionProposed?.Invoke(sender, @event); + Engine.SessionConnected += (sender, @struct) => this.SessionConnected?.Invoke(sender, @struct); + Engine.SessionConnectionErrored += + (sender, exception) => this.SessionConnectionErrored?.Invoke(sender, exception); + Engine.SessionUpdated += (sender, @event) => this.SessionUpdated?.Invoke(sender, @event); + Engine.SessionExtended += (sender, @event) => this.SessionExtended?.Invoke(sender, @event); + Engine.SessionPinged += (sender, @event) => this.SessionPinged?.Invoke(sender, @event); + Engine.SessionDeleted += (sender, @event) => this.SessionDeleted?.Invoke(sender, @event); } public Task Pair(string uri, bool activatePairing = false) @@ -196,7 +217,6 @@ public event EventHandler AuthError public void Dispose() { - Events?.Dispose(); Core?.Dispose(); } } diff --git a/WalletConnectSharpV2.sln b/WalletConnectSharpV2.sln index 9a2fbcf..295cf79 100644 --- a/WalletConnectSharpV2.sln +++ b/WalletConnectSharpV2.sln @@ -6,16 +6,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Storage" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Crypto", "Core Modules\WalletConnectSharp.Crypto\WalletConnectSharp.Crypto.csproj", "{CE7D22CE-523B-47D1-8093-BB9643C4F6FB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Events", "Core Modules\WalletConnectSharp.Events\WalletConnectSharp.Events.csproj", "{FD172F4E-A33D-47F9-AD46-AD346F5B767B}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Network.Websocket", "Core Modules\WalletConnectSharp.Network.Websocket\WalletConnectSharp.Network.Websocket.csproj", "{53A4B228-6AFA-4BAE-B3CE-4C4711A8878B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Network.Tests", "Tests\WalletConnectSharp.Network.Tests\WalletConnectSharp.Network.Tests.csproj", "{F237BAA4-EE57-4E34-91CA-37380FBA4D2F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Common", "Core Modules\WalletConnectSharp.Common\WalletConnectSharp.Common.csproj", "{90B59A93-273C-49A3-8A26-37E487780B1A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Events.Tests", "Tests\WalletConnectSharp.Events.Tests\WalletConnectSharp.Events.Tests.csproj", "{AFAA1188-AF03-4A79-A3A3-E25D08ED5757}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Storage.Test", "Tests\WalletConnectSharp.Storage.Test\WalletConnectSharp.Storage.Test.csproj", "{5EDF7334-9F47-4E0E-9964-6EA7934F0292}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalletConnectSharp.Crypto.Tests", "Tests\WalletConnectSharp.Crypto.Tests\WalletConnectSharp.Crypto.Tests.csproj", "{23897558-4177-425D-B2FA-75AB0B6FEDAE}" @@ -62,10 +58,6 @@ Global {46EC1C68-C0C1-4515-B841-F117651C866E}.Debug|Any CPU.Build.0 = Debug|Any CPU {46EC1C68-C0C1-4515-B841-F117651C866E}.Release|Any CPU.ActiveCfg = Release|Any CPU {46EC1C68-C0C1-4515-B841-F117651C866E}.Release|Any CPU.Build.0 = Release|Any CPU - {FD172F4E-A33D-47F9-AD46-AD346F5B767B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FD172F4E-A33D-47F9-AD46-AD346F5B767B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FD172F4E-A33D-47F9-AD46-AD346F5B767B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FD172F4E-A33D-47F9-AD46-AD346F5B767B}.Release|Any CPU.Build.0 = Release|Any CPU {53A4B228-6AFA-4BAE-B3CE-4C4711A8878B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {53A4B228-6AFA-4BAE-B3CE-4C4711A8878B}.Debug|Any CPU.Build.0 = Debug|Any CPU {53A4B228-6AFA-4BAE-B3CE-4C4711A8878B}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -78,10 +70,6 @@ Global {90B59A93-273C-49A3-8A26-37E487780B1A}.Debug|Any CPU.Build.0 = Debug|Any CPU {90B59A93-273C-49A3-8A26-37E487780B1A}.Release|Any CPU.ActiveCfg = Release|Any CPU {90B59A93-273C-49A3-8A26-37E487780B1A}.Release|Any CPU.Build.0 = Release|Any CPU - {AFAA1188-AF03-4A79-A3A3-E25D08ED5757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AFAA1188-AF03-4A79-A3A3-E25D08ED5757}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AFAA1188-AF03-4A79-A3A3-E25D08ED5757}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AFAA1188-AF03-4A79-A3A3-E25D08ED5757}.Release|Any CPU.Build.0 = Release|Any CPU {5EDF7334-9F47-4E0E-9964-6EA7934F0292}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5EDF7334-9F47-4E0E-9964-6EA7934F0292}.Debug|Any CPU.Build.0 = Debug|Any CPU {5EDF7334-9F47-4E0E-9964-6EA7934F0292}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -129,12 +117,10 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {23897558-4177-425D-B2FA-75AB0B6FEDAE} = {3A55D6C7-0EF8-4EEA-90A5-89F5AFB97BA0} - {AFAA1188-AF03-4A79-A3A3-E25D08ED5757} = {3A55D6C7-0EF8-4EEA-90A5-89F5AFB97BA0} {F237BAA4-EE57-4E34-91CA-37380FBA4D2F} = {3A55D6C7-0EF8-4EEA-90A5-89F5AFB97BA0} {5EDF7334-9F47-4E0E-9964-6EA7934F0292} = {3A55D6C7-0EF8-4EEA-90A5-89F5AFB97BA0} {90B59A93-273C-49A3-8A26-37E487780B1A} = {CDB4264E-3F30-4D4D-90BC-15E537BB739B} {CE7D22CE-523B-47D1-8093-BB9643C4F6FB} = {CDB4264E-3F30-4D4D-90BC-15E537BB739B} - {FD172F4E-A33D-47F9-AD46-AD346F5B767B} = {CDB4264E-3F30-4D4D-90BC-15E537BB739B} {0797C687-3123-4502-A441-F48A31E6EF46} = {CDB4264E-3F30-4D4D-90BC-15E537BB739B} {53A4B228-6AFA-4BAE-B3CE-4C4711A8878B} = {CDB4264E-3F30-4D4D-90BC-15E537BB739B} {46EC1C68-C0C1-4515-B841-F117651C866E} = {CDB4264E-3F30-4D4D-90BC-15E537BB739B}