diff --git a/Core Modules/WalletConnectSharp.Crypto/Crypto.cs b/Core Modules/WalletConnectSharp.Crypto/Crypto.cs
index 0e083e6..5925fa7 100644
--- a/Core Modules/WalletConnectSharp.Crypto/Crypto.cs
+++ b/Core Modules/WalletConnectSharp.Crypto/Crypto.cs
@@ -30,7 +30,7 @@ namespace WalletConnectSharp.Crypto
public class Crypto : ICrypto
{
private readonly string CRYPTO_CLIENT_SEED = $"client_ed25519_seed";
-
+
private const string MULTICODEC_ED25519_ENCODING = "base58btc";
private const string MULTICODEC_ED25519_BASE = "z";
private const string MULTICODEC_ED25519_HEADER = "K36";
@@ -48,7 +48,7 @@ public class Crypto : ICrypto
private const int TYPE_LENGTH = 1;
private const int IV_LENGTH = 12;
private const int KEY_LENGTH = 32;
-
+
///
/// The name of the crypto module
///
@@ -71,12 +71,12 @@ public string Context
return "walletconnectsharp";
}
}
-
+
///
/// The current KeyChain this crypto module instance is using
///
public IKeyChain KeyChain { get; private set; }
-
+
///
/// The current storage module this crypto module instance is using
///
@@ -84,6 +84,7 @@ public string Context
private bool _initialized;
private bool _newStorage;
+ protected bool Disposed;
///
/// Create a new instance of the crypto module, with a given storage module.
@@ -97,7 +98,7 @@ public Crypto(IKeyValueStorage storage)
this.KeyChain = new KeyChain(storage);
this.Storage = storage;
}
-
+
///
/// Create a new instance of the crypto module, with a given keychain.
///
@@ -128,7 +129,7 @@ public async Task Init()
{
if (_newStorage)
await this.Storage.Init();
-
+
await this.KeyChain.Init();
this._initialized = true;
}
@@ -159,7 +160,7 @@ public Task GenerateKeyPair()
var options = new KeyGenerationParameters(SecureRandom.GetInstance("SHA256PRNG"), 1);
X25519KeyPairGenerator generator = new X25519KeyPairGenerator();
generator.Init(options);
-
+
var keypair = generator.GenerateKeyPair();
var publicKeyData = keypair.Public as X25519PublicKeyParameters;
var privateKeyData = keypair.Private as X25519PrivateKeyParameters;
@@ -281,7 +282,7 @@ public Task Encrypt(EncryptParams @params)
var typeRaw = Bases.Base10.Decode($"{@params.Type}");
var iv = @params.Iv;
-
+
byte[] rawIv;
if (iv == null)
{
@@ -308,7 +309,7 @@ public Task Encrypt(EncryptParams @params)
{
byte[] temp = new byte[encoded.Length * 3];
int len = aead.ProcessBytes(encoded, 0, encoded.Length, temp, 0);
-
+
if (len > 0)
{
encryptedStream.Write(temp, 0, len);
@@ -327,7 +328,7 @@ public Task Encrypt(EncryptParams @params)
{
if (senderPublicKey == null)
throw new ArgumentException("Missing sender public key for type1 envelope");
-
+
return Task.FromResult(Convert.ToBase64String(
typeRaw.Concat(senderPublicKey).Concat(rawIv).Concat(encrypted).ToArray()
));
@@ -380,10 +381,7 @@ public async Task Encode(string topic, IJsonRpcPayload payload, EncodeOp
var message = JsonConvert.SerializeObject(payload);
var results = await Encrypt(new EncryptParams()
{
- Message = message,
- Type = type,
- SenderPublicKey = senderPublicKey,
- SymKey = symKey
+ Message = message, Type = type, SenderPublicKey = senderPublicKey, SymKey = symKey
});
return results;
@@ -398,7 +396,8 @@ public async Task Encode(string topic, IJsonRpcPayload payload, EncodeOp
/// (optional) Decoding options
/// The type of the IJsonRpcPayload to convert the encoded Json to
/// The decoded, decrypted and deserialized object of type T from an async task
- public async Task Decode(string topic, string encoded, DecodeOptions options = null) where T : IJsonRpcPayload
+ public async Task Decode(string topic, string encoded, DecodeOptions options = null)
+ where T : IJsonRpcPayload
{
this.IsInitialized();
var @params = ValidateDecoding(encoded, options);
@@ -430,7 +429,8 @@ private EncodingParams Deserialize(string encoded)
var slice3 = slice2 + IV_LENGTH;
var senderPublicKey = new ArraySegment(bytes, slice1, KEY_LENGTH);
var iv = new ArraySegment(bytes, slice2, IV_LENGTH);
- var @sealed = new ArraySegment(bytes, slice3, bytes.Length - (TYPE_LENGTH + KEY_LENGTH + IV_LENGTH));
+ var @sealed =
+ new ArraySegment(bytes, slice3, bytes.Length - (TYPE_LENGTH + KEY_LENGTH + IV_LENGTH));
return new EncodingParams()
{
@@ -446,12 +446,7 @@ private EncodingParams Deserialize(string encoded)
var iv = new ArraySegment(bytes, slice1, IV_LENGTH);
var @sealed = new ArraySegment(bytes, slice2, bytes.Length - (IV_LENGTH + TYPE_LENGTH));
- return new EncodingParams()
- {
- Type = typeRaw,
- Sealed = @sealed.ToArray(),
- Iv = iv.ToArray()
- };
+ return new EncodingParams() { Type = typeRaw, Sealed = @sealed.ToArray(), Iv = iv.ToArray() };
}
}
@@ -493,12 +488,7 @@ public async Task SignJwt(string aud)
signer.BlockUpdate(data, 0, data.Length);
var signature = signer.GenerateSignature();
- return EncodeJwt(new IridiumJWTSigned()
- {
- Header = header,
- Payload = payload,
- Signature = signature
- });
+ return EncodeJwt(new IridiumJWTSigned() { Header = header, Payload = payload, Signature = signature });
}
///
@@ -516,8 +506,8 @@ public async Task GetClientId()
private string EncodeJwt(IridiumJWTSigned data)
{
- return string.Join(JWT_DELIMITER,
- EncodeJson(data.Header),
+ return string.Join(JWT_DELIMITER,
+ EncodeJson(data.Header),
EncodeJson(data.Payload),
EncodeSig(data.Signature)
);
@@ -549,7 +539,7 @@ private string EncodeIss(Ed25519PublicKeyParameters publicKey)
private Ed25519PrivateKeyParameters KeypairFromSeed(byte[] seed)
{
return new Ed25519PrivateKeyParameters(seed);
-
+
/*var options = new KeyCreationParameters()
{
ExportPolicy = KeyExportPolicies.AllowPlaintextExport
@@ -578,10 +568,8 @@ private void IsInitialized()
{
if (!this._initialized)
{
- throw WalletConnectException.FromType(ErrorType.NOT_INITIALIZED, new Dictionary()
- {
- { "Name", Name }
- });
+ throw WalletConnectException.FromType(ErrorType.NOT_INITIALIZED,
+ new Dictionary() { { "Name", Name } });
}
}
@@ -616,7 +604,7 @@ private byte[] DeriveSharedKey(string privateKeyA, string publicKeyB)
{
var keyB = PublicKey.Import(KeyAgreementAlgorithm.X25519, publicKeyB.HexToByteArray(),
KeyBlobFormat.RawPublicKey);
-
+
var options = new SharedSecretCreationParameters
{
ExportPolicy = KeyExportPolicies.AllowPlaintextArchiving
@@ -632,7 +620,7 @@ private byte[] DeriveSymmetricKey(byte[] secretKey)
generator.Init(new HkdfParameters(secretKey, Array.Empty(), Array.Empty()));
byte[] key = new byte[32];
- generator.GenerateBytes(key, 0,32);
+ generator.GenerateBytes(key, 0, 32);
return key;
}
@@ -644,14 +632,14 @@ private string DeserializeAndDecrypt(string symKey, string encoded)
var iv = param.Iv;
var type = int.Parse(Bases.Base10.Encode(param.Type));
var isType1 = type == TYPE_1;
-
+
var aead = new ChaCha20Poly1305();
aead.Init(false, new ParametersWithIV(new KeyParameter(symKey.HexToByteArray()), iv));
using MemoryStream rawDecrypted = new MemoryStream();
byte[] temp = new byte[@sealed.Length];
int len = aead.ProcessBytes(@sealed, 0, @sealed.Length, temp, 0);
-
+
if (len > 0)
{
rawDecrypted.Write(temp, 0, len);
@@ -663,7 +651,7 @@ private string DeserializeAndDecrypt(string symKey, string encoded)
{
rawDecrypted.Write(temp, 0, len);
}
-
+
return Encoding.UTF8.GetString(rawDecrypted.ToArray());
}
@@ -687,7 +675,21 @@ private async Task GetClientSeed()
public void Dispose()
{
- KeyChain?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed)
+ return;
+
+ if (disposing)
+ {
+ KeyChain?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs b/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs
index 74fc224..8ff0223 100644
--- a/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs
+++ b/Core Modules/WalletConnectSharp.Network.Websocket/WebsocketConnection.cs
@@ -16,6 +16,7 @@ public class WebsocketConnection : IJsonRpcConnection, IModule
private string _url;
private bool _registering;
private Guid _context;
+ protected bool Disposed;
///
/// The Open timeout
@@ -98,7 +99,7 @@ public WebsocketConnection(string url)
{
if (!Validation.IsWsUrl(url))
throw new ArgumentException("Provided URL is not compatible with WebSocket connection: " + url);
-
+
_context = Guid.NewGuid();
this._url = url;
}
@@ -178,7 +179,7 @@ private void OnOpen(WebsocketClient socket)
{
if (socket == null)
return;
-
+
socket.MessageReceived.Subscribe(OnPayload);
socket.DisconnectionHappened.Subscribe(OnDisconnect);
@@ -191,15 +192,15 @@ private void OnDisconnect(DisconnectionInfo obj)
{
if (obj.Exception != null)
this.ErrorReceived?.Invoke(this, obj.Exception);
-
+
OnClose(obj);
}
-
+
private void OnClose(DisconnectionInfo obj)
{
if (this._socket == null)
return;
-
+
//_socket.Dispose();
this._socket = null;
this._registering = false;
@@ -221,7 +222,7 @@ private void OnPayload(ResponseMessage obj)
}
if (string.IsNullOrWhiteSpace(json)) return;
-
+
//Console.WriteLine($"[{Name}] Got payload {json}");
this.PayloadReceived?.Invoke(this, json);
@@ -237,8 +238,9 @@ public async Task Close()
throw new IOException("Connection already closed");
await _socket.Stop(WebSocketCloseStatus.NormalClosure, "Close Invoked");
-
- OnClose(new DisconnectionInfo(DisconnectionType.Exit, WebSocketCloseStatus.Empty, "Close Invoked", null, null));
+
+ OnClose(new DisconnectionInfo(DisconnectionType.Exit, WebSocketCloseStatus.Empty, "Close Invoked", null,
+ null));
}
///
@@ -303,32 +305,37 @@ public async Task SendError(IJsonRpcError requestPayload, object context)
}
}
- ///
- /// Dispose this websocket connection. Will automatically Close this
- /// websocket if still connected.
- ///
public async void Dispose()
{
- if (Connected)
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed)
+ return;
+
+ if (disposing)
{
- await Close();
+ _socket.Dispose();
}
+
+ Disposed = true;
}
- private string addressNotFoundError = "getaddrinfo ENOTFOUND";
- private string connectionRefusedError = "connect ECONNREFUSED";
+ private const string AddressNotFoundError = "getaddrinfo ENOTFOUND";
+ private const string ConnectionRefusedError = "connect ECONNREFUSED";
+
private void OnError(IJsonRpcPayload ogPayload, Exception e)
{
- var exception = e.Message.Contains(addressNotFoundError) || e.Message.Contains(connectionRefusedError)
- ? new IOException("Unavailable WS RPC url at " + _url) : e;
+ var exception = e.Message.Contains(AddressNotFoundError) || e.Message.Contains(ConnectionRefusedError)
+ ? new IOException("Unavailable WS RPC url at " + _url)
+ : e;
var message = exception.Message;
- var payload = new JsonRpcResponse(ogPayload.Id, new Error()
- {
- Code = exception.HResult,
- Data = null,
- Message = message
- }, default(T));
+ var payload = new JsonRpcResponse(ogPayload.Id,
+ new Error() { Code = exception.HResult, Data = null, Message = message }, default(T));
//Trigger the payload event, converting the new JsonRpcResponse object to JSON string
this.PayloadReceived?.Invoke(this, JsonConvert.SerializeObject(payload));
diff --git a/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcProvider.cs b/Core Modules/WalletConnectSharp.Network/Interfaces/IJsonRpcProvider.cs
index 11aa025..9106921 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.Common;
using WalletConnectSharp.Network.Models;
namespace WalletConnectSharp.Network
@@ -7,7 +8,7 @@ namespace WalletConnectSharp.Network
///
/// The interface that represents a JSON RPC provider
///
- public interface IJsonRpcProvider : IBaseJsonRpcProvider
+ public interface IJsonRpcProvider : IBaseJsonRpcProvider, IModule
{
event EventHandler PayloadReceived;
@@ -18,7 +19,7 @@ public interface IJsonRpcProvider : IBaseJsonRpcProvider
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 0a47993..eeeda1b 100644
--- a/Core Modules/WalletConnectSharp.Network/JsonRpcProvider.cs
+++ b/Core Modules/WalletConnectSharp.Network/JsonRpcProvider.cs
@@ -30,6 +30,7 @@ public class JsonRpcProvider : IJsonRpcProvider, IModule
public event EventHandler RawMessageReceived;
private GenericEventHolder jsonResponseEventHolder = new();
+ protected bool Disposed;
///
/// Whether the provider is currently connecting or not
@@ -41,7 +42,7 @@ public bool IsConnecting
return _connectingStarted && !Connecting.Task.IsCompleted;
}
}
-
+
///
/// The current Connection for this provider
///
@@ -100,14 +101,14 @@ public async Task Connect(string connection)
{
await this._connection.Close();
}
-
+
// Reset connecting task
Connecting = new TaskCompletionSource();
_connectingStarted = true;
WCLogger.Log("[JsonRpcProvider] Opening connection");
await this._connection.Open(connection);
-
+
FinalizeConnection(this._connection);
}
@@ -123,7 +124,7 @@ public async Task Connect(IJsonRpcConnection connection)
WCLogger.Log("Current connection still open, closing connection");
await this._connection.Close();
}
-
+
// Reset connecting task
Connecting = new TaskCompletionSource();
_connectingStarted = true;
@@ -133,7 +134,7 @@ public async Task Connect(IJsonRpcConnection connection)
FinalizeConnection(connection);
}
-
+
private void FinalizeConnection(IJsonRpcConnection connection)
{
WCLogger.Log("[JsonRpcProvider] Finalizing Connection, registering event listeners");
@@ -152,7 +153,7 @@ public async Task Connect()
{
if (_connection == null)
throw new Exception("No connection is set");
-
+
WCLogger.Log("[JsonRpcProvider] Connecting with given connection object");
await Connect(_connection);
}
@@ -179,7 +180,7 @@ public async Task Disconnect()
public async Task Request(IRequestArguments requestArgs, object context = null)
{
WCLogger.Log("[JsonRpcProvider] Checking if connected");
- if (IsConnecting)
+ if (IsConnecting)
await Connecting.Task;
else if (!_connectingStarted && !_connection.Connected)
{
@@ -194,6 +195,7 @@ public async Task Request(IRequestArguments requestArgs, object co
if (id == 0)
id = null; // An id of 0 is null
}
+
var request = new JsonRpcRequest(requestArgs.Method, requestArgs.Params, id);
TaskCompletionSource requestTask = new TaskCompletionSource (TaskCreationOptions.None);
@@ -204,7 +206,7 @@ public async Task Request(IRequestArguments requestArgs, object co
return;
var result = JsonConvert.DeserializeObject>(responseJson);
-
+
if (result.Error != null)
{
requestTask.SetException(new IOException(result.Error.Message));
@@ -219,8 +221,7 @@ public async Task Request(IRequestArguments requestArgs, object co
{
if (requestTask.Task.IsCompleted)
return;
-
- //Console.WriteLine($"[{Name}] Got Response Error {exception}");
+
if (exception != null)
{
requestTask.SetException(exception);
@@ -228,9 +229,9 @@ public async Task Request(IRequestArguments requestArgs, object co
};
_lastId = request.Id;
-
- WCLogger.Log($"[JsonRpcProvider] Sending request {request.Method} with data {JsonConvert.SerializeObject(request)}");
- //Console.WriteLine($"[{Name}] Sending request {request.Method} with data {JsonConvert.SerializeObject(request)}");
+
+ WCLogger.Log(
+ $"[JsonRpcProvider] Sending request {request.Method} with data {JsonConvert.SerializeObject(request)}");
await _connection.SendRequest(request, context);
WCLogger.Log("[JsonRpcProvider] Awaiting request result");
@@ -242,15 +243,13 @@ public async Task Request(IRequestArguments requestArgs, object co
protected void RegisterEventListeners()
{
if (_hasRegisteredEventListeners) return;
-
- WCLogger.Log($"[JsonRpcProvider] Registering event listeners on connection object with context {_connection.ToString()}");
+
+ 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);*/
+
_hasRegisteredEventListeners = true;
}
@@ -277,9 +276,9 @@ private void OnPayload(object sender, string json)
if (payload.Id == 0)
payload.Id = _lastId;
-
+
WCLogger.Log($"[JsonRpcProvider] Payload has ID {payload.Id}");
-
+
this.PayloadReceived?.Invoke(this, payload);
if (payload.IsRequest)
@@ -304,7 +303,20 @@ private void OnPayload(object sender, string json)
public void Dispose()
{
- _connection?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ _connection?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/Core Modules/WalletConnectSharp.Storage/FileSystemStorage.cs b/Core Modules/WalletConnectSharp.Storage/FileSystemStorage.cs
index 2376614..5414eb9 100644
--- a/Core Modules/WalletConnectSharp.Storage/FileSystemStorage.cs
+++ b/Core Modules/WalletConnectSharp.Storage/FileSystemStorage.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
using Newtonsoft.Json;
using WalletConnectSharp.Common.Logging;
@@ -19,8 +14,9 @@ public class FileSystemStorage : InMemoryStorage
/// The file path to store the JSON file
///
public string FilePath { get; private set; }
- private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1);
-
+
+ private readonly SemaphoreSlim _semaphoreSlim = new(1);
+
///
/// A new FileSystemStorage module that reads/writes all storage
/// values from storage
@@ -30,7 +26,7 @@ public FileSystemStorage(string filePath = null)
{
if (filePath == null)
{
- var home =
+ var home =
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
filePath = Path.Combine(home, ".wc", "store.json");
}
@@ -62,7 +58,7 @@ public override async Task SetItem(string key, T value)
await base.SetItem(key, value);
await Save();
}
-
+
///
/// The RemoveItem function deletes the value stored based off of the specified key.
/// Will also update the JSON file
@@ -73,7 +69,7 @@ public override async Task RemoveItem(string key)
await base.RemoveItem(key);
await Save();
}
-
+
///
/// Clear all entries in this storage. WARNING: This will delete all data!
/// This will also update the JSON file
@@ -91,12 +87,10 @@ private async Task Save()
{
Directory.CreateDirectory(path);
}
-
- var json = JsonConvert.SerializeObject(Entries, new JsonSerializerSettings()
- {
- TypeNameHandling = TypeNameHandling.All
- });
-
+
+ var json = JsonConvert.SerializeObject(Entries,
+ new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
+
await _semaphoreSlim.WaitAsync();
await File.WriteAllTextAsync(FilePath, json, Encoding.UTF8);
_semaphoreSlim.Release();
@@ -114,7 +108,7 @@ private async Task Load()
try
{
Entries = JsonConvert.DeserializeObject>(json,
- new JsonSerializerSettings() {TypeNameHandling = TypeNameHandling.Auto});
+ new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto });
}
catch (JsonSerializationException e)
{
@@ -128,5 +122,17 @@ private async Task Load()
Entries = new Dictionary();
}
}
+
+ protected override void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ _semaphoreSlim.Dispose();
+ }
+
+ Disposed = true;
+ }
}
}
diff --git a/Core Modules/WalletConnectSharp.Storage/InMemoryStorage.cs b/Core Modules/WalletConnectSharp.Storage/InMemoryStorage.cs
index 80d6c92..8ff6bde 100644
--- a/Core Modules/WalletConnectSharp.Storage/InMemoryStorage.cs
+++ b/Core Modules/WalletConnectSharp.Storage/InMemoryStorage.cs
@@ -1,7 +1,3 @@
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using WalletConnectSharp.Common;
using WalletConnectSharp.Common.Model.Errors;
using WalletConnectSharp.Storage.Interfaces;
@@ -11,6 +7,7 @@ public class InMemoryStorage : IKeyValueStorage
{
protected Dictionary Entries = new Dictionary();
private bool _initialized = false;
+ protected bool Disposed;
public virtual Task Init()
{
@@ -41,13 +38,14 @@ public virtual Task GetItem(string key)
IsInitialized();
return Task.FromResult(Entries[key] is T ? (T)Entries[key] : default);
}
-
+
public virtual Task SetItem(string key, T value)
{
IsInitialized();
Entries[key] = value;
return Task.CompletedTask;
}
+
public virtual Task RemoveItem(string key)
{
IsInitialized();
@@ -78,7 +76,13 @@ protected void IsInitialized()
public void Dispose()
{
- Entries?.Clear();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/Expirer.cs b/WalletConnectSharp.Core/Controllers/Expirer.cs
index e262c51..26d8f60 100644
--- a/WalletConnectSharp.Core/Controllers/Expirer.cs
+++ b/WalletConnectSharp.Core/Controllers/Expirer.cs
@@ -15,7 +15,9 @@ public class Expirer : IExpirer
/// The version of this module
///
public static readonly string Version = "0.3";
-
+
+ protected bool Disposed;
+
private Dictionary _expirations = new Dictionary();
private bool initialized = false;
private Expiration[] _cached = Array.Empty();
@@ -185,22 +187,14 @@ public void Set(long key, long expiry)
private void SetWithTarget(string targetType, object key, long expiry)
{
var target = FormatTarget(targetType, key);
- var expiration = new Expiration()
- {
- Target = target,
- Expiry = expiry
- };
+ var expiration = new Expiration() { Target = target, Expiry = expiry };
if (_expirations.ContainsKey(target))
_expirations.Remove(target); // We cannot override, so remove first
-
+
_expirations.Add(target, expiration);
CheckExpiry(target, expiration);
- this.Created?.Invoke(this, new ExpirerEventArgs()
- {
- Expiration = expiration,
- Target = target
- });
+ this.Created?.Invoke(this, new ExpirerEventArgs() { Expiration = expiration, Target = target });
}
///
@@ -242,7 +236,7 @@ public Task Delete(string key)
return Task.CompletedTask;
}
-
+
///
/// Delete a expiration with the given long key (usually a id).
///
@@ -263,11 +257,7 @@ private void DeleteWithTarget(string targetType, object key)
{
var expiration = GetExpiration(target);
_expirations.Remove(target);
- this.Deleted?.Invoke(this, new ExpirerEventArgs()
- {
- Target = target,
- Expiration = expiration
- });
+ this.Deleted?.Invoke(this, new ExpirerEventArgs() { Target = target, Expiration = expiration });
}
}
@@ -320,11 +310,7 @@ private void CheckExpiry(string target, Expiration expiration)
private void Expire(string target, Expiration expiration)
{
_expirations.Remove(target);
- this.Expired?.Invoke(this, new ExpirerEventArgs()
- {
- Target = target,
- Expiration = expiration
- });
+ this.Expired?.Invoke(this, new ExpirerEventArgs() { Target = target, Expiration = expiration });
}
private void CheckExpirations(object sender, EventArgs args)
@@ -372,12 +358,30 @@ private string FormatTarget(string targetType, object key)
default:
throw new ArgumentException($"Unknown expirer target type: ${targetType}");
}
-
+
return $"{targetType}:{key}";
}
public void Dispose()
{
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ _core.HeartBeat.OnPulse -= CheckExpirations;
+
+ this.Created -= Persist;
+ this.Expired -= Persist;
+ this.Deleted -= Persist;
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/HeartBeat.cs b/WalletConnectSharp.Core/Controllers/HeartBeat.cs
index 2832126..261bc64 100644
--- a/WalletConnectSharp.Core/Controllers/HeartBeat.cs
+++ b/WalletConnectSharp.Core/Controllers/HeartBeat.cs
@@ -9,9 +9,9 @@ namespace WalletConnectSharp.Core.Controllers
public class HeartBeat : IHeartBeat
{
///
- /// The CancellationToken that stops the Heartbeat module
+ /// The CancellationTokenSource that can be used to stop the Heartbeat module
///
- public CancellationToken HeartBeatCancellationToken { get; private set; }
+ public CancellationTokenSource CancellationTokenSource { get; private set; } = new();
public event EventHandler OnPulse;
@@ -19,11 +19,11 @@ public class HeartBeat : IHeartBeat
/// The interval (in milliseconds) the Pulse event gets emitted/triggered
///
public int Interval { get; }
-
+
///
- /// The context UUID that this heartboeat module uses
+ /// The context UUID that this heartbeat module uses
///
- public readonly Guid contextGuid = Guid.NewGuid();
+ public readonly Guid ContextGuid = Guid.NewGuid();
///
/// The name of this Heartbeat module
@@ -32,7 +32,7 @@ public string Name
{
get
{
- return $"heartbeat-{contextGuid}";
+ return $"heartbeat-{ContextGuid}";
}
}
@@ -47,6 +47,8 @@ public string Context
}
}
+ protected bool Disposed;
+
///
/// Create a new Heartbeat module, optionally specifying options
///
@@ -62,19 +64,22 @@ public HeartBeat(int interval = 5000)
/// HeartBeatCancellationToken is cancelled, then the interval will be halted.
///
///
- public Task Init()
+ public Task InitAsync(CancellationToken cancellationToken = default)
{
- HeartBeatCancellationToken = new CancellationToken();
+ if (cancellationToken != default)
+ {
+ CancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ }
Task.Run(async () =>
{
- while (!HeartBeatCancellationToken.IsCancellationRequested)
+ while (!CancellationTokenSource.Token.IsCancellationRequested)
{
Pulse();
- await Task.Delay(Interval, HeartBeatCancellationToken);
+ await Task.Delay(Interval, CancellationTokenSource.Token);
}
- }, HeartBeatCancellationToken);
+ }, CancellationTokenSource.Token);
return Task.CompletedTask;
}
@@ -86,6 +91,20 @@ private void Pulse()
public void Dispose()
{
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ CancellationTokenSource?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs b/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs
index 608f6a3..995c4fb 100644
--- a/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs
+++ b/WalletConnectSharp.Core/Controllers/JsonRpcHistory.cs
@@ -17,7 +17,7 @@ public class JsonRpcHistory : IJsonRpcHistory
/// The storage version of this module
///
public static readonly string Version = "0.3";
-
+
///
/// The name of this module instance
///
@@ -51,6 +51,8 @@ public string StorageKey
}
}
+ protected bool Disposed;
+
private JsonRpcRecord[] _cached = Array.Empty>();
private Dictionary> _records = new Dictionary>();
private bool initialized = false;
@@ -155,12 +157,7 @@ public void Set(string topic, IJsonRpcRequest request, string chainId)
IsInitialized();
if (_records.ContainsKey(request.Id)) return;
- var record = new JsonRpcRecord(request)
- {
- Id = request.Id,
- Topic = topic,
- ChainId = chainId,
- };
+ var record = new JsonRpcRecord(request) { Id = request.Id, Topic = topic, ChainId = chainId, };
_records.Add(record.Id, record);
this.Created?.Invoke(this, record);
}
@@ -176,13 +173,13 @@ public Task> Get(string topic, long id)
IsInitialized();
var record = GetRecord(id);
-
+
// TODO Log
/*if (topic != record.Topic)
{
throw WalletConnectException.FromType(ErrorType.MISMATCHED_TOPIC, $"{Name}: {id}");
}*/
-
+
return Task.FromResult>(record);
}
@@ -269,10 +266,8 @@ private JsonRpcRecord GetRecord(long id)
if (!_records.ContainsKey(id))
{
- throw WalletConnectException.FromType(ErrorType.NO_MATCHING_KEY, new Dictionary()
- {
- {"Tag", $"{Name}: {id}"}
- });
+ throw WalletConnectException.FromType(ErrorType.NO_MATCHING_KEY,
+ new Dictionary() { { "Tag", $"{Name}: {id}" } });
}
return _records[id];
@@ -321,7 +316,22 @@ private void IsInitialized()
public void Dispose()
{
- _core?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ this.Created -= SaveRecordCallback;
+ this.Updated -= SaveRecordCallback;
+ this.Deleted -= SaveRecordCallback;
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/Pairing.cs b/WalletConnectSharp.Core/Controllers/Pairing.cs
index cce3042..33cbe9f 100644
--- a/WalletConnectSharp.Core/Controllers/Pairing.cs
+++ b/WalletConnectSharp.Core/Controllers/Pairing.cs
@@ -1,6 +1,7 @@
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using WalletConnectSharp.Common.Events;
+using WalletConnectSharp.Common.Logging;
using WalletConnectSharp.Common.Model.Errors;
using WalletConnectSharp.Common.Model.Relay;
using WalletConnectSharp.Common.Utils;
@@ -18,10 +19,12 @@ namespace WalletConnectSharp.Core.Controllers
///
public class Pairing : IPairing
{
+ protected bool Disposed;
+
private const int KeyLength = 32;
private bool _initialized;
private HashSet _registeredMethods = new HashSet();
-
+
///
/// The name for this module instance
///
@@ -55,7 +58,7 @@ public string Context
///
///
public IPairingStore Store { get; }
-
+
///
/// Get all active and inactive pairings
///
@@ -136,23 +139,17 @@ public async Task Pair(string uri, bool activatePairing = true)
{
throw new ArgumentException($"Topic {topic} already has keychain");
}
-
+
var expiry = Clock.CalculateExpiry(Clock.FIVE_MINUTES);
var pairing = new PairingStruct()
{
- Topic = topic,
- Relay = relay,
- Expiry = expiry,
- Active = false,
+ Topic = topic, Relay = relay, Expiry = expiry, Active = false,
};
-
+
await this.Store.Set(topic, pairing);
await this.Core.Crypto.SetSymKey(symKey, topic);
- await this.Core.Relayer.Subscribe(topic, new SubscribeOptions()
- {
- Relay = relay
- });
-
+ await this.Core.Relayer.Subscribe(topic, new SubscribeOptions() { Relay = relay });
+
this.Core.Expirer.Set(topic, expiry);
if (activatePairing)
@@ -173,7 +170,9 @@ public async Task Pair(string uri, bool activatePairing = true)
public UriParameters ParseUri(string uri)
{
var pathStart = uri.IndexOf(":", StringComparison.Ordinal);
- int? pathEnd = uri.IndexOf("?", StringComparison.Ordinal) != -1 ? uri.IndexOf("?", StringComparison.Ordinal) : (int?)null;
+ int? pathEnd = uri.IndexOf("?", StringComparison.Ordinal) != -1
+ ? uri.IndexOf("?", StringComparison.Ordinal)
+ : (int?)null;
var protocol = uri.Substring(0, pathStart);
string path;
@@ -213,16 +212,10 @@ public async Task Create()
var symKey = symKeyRaw.ToHex();
var topic = await this.Core.Crypto.SetSymKey(symKey);
var expiry = Clock.CalculateExpiry(Clock.FIVE_MINUTES);
- var relay = new ProtocolOptions()
- {
- Protocol = RelayProtocols.Default
- };
+ var relay = new ProtocolOptions() { Protocol = RelayProtocols.Default };
var pairing = new PairingStruct()
{
- Topic = topic,
- Expiry = expiry,
- Relay = relay,
- Active = false,
+ Topic = topic, Expiry = expiry, Relay = relay, Active = false,
};
var uri = $"{ICore.Protocol}:{topic}@{ICore.Version}?"
.AddQueryParam("symKey", symKey)
@@ -235,11 +228,7 @@ public async Task Create()
await this.Core.Relayer.Subscribe(topic);
this.Core.Expirer.Set(topic, expiry);
- return new CreatePairingData()
- {
- Topic = topic,
- Uri = uri
- };
+ return new CreatePairingData() { Topic = topic, Uri = uri };
}
///
@@ -275,7 +264,7 @@ public Task Register(string[] methods)
public Task UpdateExpiry(string topic, long expiration)
{
IsInitialized();
- return this.Store.Update(topic, new PairingStruct() {Expiry = expiration});
+ return this.Store.Update(topic, new PairingStruct() { Expiry = expiration });
}
///
@@ -286,7 +275,7 @@ public Task UpdateExpiry(string topic, long expiration)
public Task UpdateMetadata(string topic, Metadata metadata)
{
IsInitialized();
- return this.Store.Update(topic, new PairingStruct() {PeerMetadata = metadata});
+ return this.Store.Update(topic, new PairingStruct() { PeerMetadata = metadata });
}
///
@@ -309,7 +298,7 @@ public async Task Ping(string topic)
else
done.SetResult(args.Result);
});
-
+
await done.Task;
}
}
@@ -327,7 +316,7 @@ public async Task Disconnect(string topic)
{
var error = Error.FromErrorType(ErrorType.USER_DISCONNECTED);
await Core.MessageHandler.SendRequest(topic,
- new PairingDelete() {Code = error.Code, Message = error.Message});
+ new PairingDelete() { Code = error.Code, Message = error.Message });
await DeletePairing(topic);
}
}
@@ -335,24 +324,22 @@ await Core.MessageHandler.SendRequest(topic,
private async Task ActivatePairing(string topic)
{
var expiry = Clock.CalculateExpiry(Clock.THIRTY_DAYS);
- await this.Store.Update(topic, new PairingStruct()
- {
- Active = true,
- Expiry = expiry
- });
+ await this.Store.Update(topic, new PairingStruct() { Active = true, Expiry = expiry });
this.Core.Expirer.Set(topic, expiry);
}
-
+
private async Task DeletePairing(string topic)
{
bool expirerHasDeleted = !this.Core.Expirer.Has(topic);
bool pairingHasDeleted = !this.Store.Keys.Contains(topic);
bool symKeyHasDeleted = !(await this.Core.Crypto.HasKeys(topic));
-
+
await this.Core.Relayer.Unsubscribe(topic);
await Task.WhenAll(
- pairingHasDeleted ? Task.CompletedTask : this.Store.Delete(topic, Error.FromErrorType(ErrorType.USER_DISCONNECTED)),
+ pairingHasDeleted
+ ? Task.CompletedTask
+ : this.Store.Delete(topic, Error.FromErrorType(ErrorType.USER_DISCONNECTED)),
symKeyHasDeleted ? Task.CompletedTask : this.Core.Crypto.DeleteSymKey(topic),
expirerHasDeleted ? Task.CompletedTask : this.Core.Expirer.Delete(topic)
);
@@ -360,13 +347,15 @@ await Task.WhenAll(
private Task Cleanup()
{
- List pairingTopics = (from pair in this.Store.Values.Where(e => e.Expiry != null) where Clock.IsExpired(pair.Expiry.Value) select pair.Topic).ToList();
-
+ List pairingTopics = (from pair in this.Store.Values.Where(e => e.Expiry != null)
+ where Clock.IsExpired(pair.Expiry.Value)
+ select pair.Topic).ToList();
+
return Task.WhenAll(
pairingTopics.Select(DeletePairing)
);
}
-
+
private async Task IsValidPairingTopic(string topic)
{
if (string.IsNullOrWhiteSpace(topic))
@@ -384,11 +373,11 @@ private async Task IsValidPairingTopic(string topic)
throw WalletConnectException.FromType(ErrorType.EXPIRED, $"pairing topic: {topic}");
}
}
-
+
private bool IsValidUrl(string url)
{
if (string.IsNullOrWhiteSpace(url)) return false;
-
+
try
{
new Uri(url);
@@ -399,14 +388,14 @@ private bool IsValidUrl(string url)
return false;
}
}
-
+
private Task IsValidPair(string uri)
{
if (!IsValidUrl(uri))
throw WalletConnectException.FromType(ErrorType.MISSING_OR_INVALID, $"pair() uri: {uri}");
return Task.CompletedTask;
}
-
+
private void IsInitialized()
{
if (!_initialized)
@@ -414,7 +403,7 @@ private void IsInitialized()
throw WalletConnectException.FromType(ErrorType.NOT_INITIALIZED, this.Name);
}
}
-
+
private async Task OnPairingPingRequest(string topic, JsonRpcRequest payload)
{
var id = payload.Id;
@@ -423,11 +412,7 @@ private async Task OnPairingPingRequest(string topic, JsonRpcRequest(id, topic, true);
- this.PairingPinged?.Invoke(this, new PairingEvent()
- {
- Topic = topic,
- Id = id
- });
+ this.PairingPinged?.Invoke(this, new PairingEvent() { Topic = topic, Id = id });
}
catch (WalletConnectException e)
{
@@ -438,20 +423,16 @@ private async Task OnPairingPingRequest(string topic, JsonRpcRequest payload)
{
var id = payload.Id;
-
+
// put at the end of the stack to avoid a race condition
// where session_ping listener is not yet initialized
await Task.Delay(500);
- this.PairingPinged?.Invoke(this, new PairingEvent()
- {
- Id = id,
- Topic = topic
- });
+ this.PairingPinged?.Invoke(this, new PairingEvent() { Id = id, Topic = topic });
PairingPingResponseEvents[$"pairing_ping{id}"](this, payload);
}
-
+
private async Task OnPairingDeleteRequest(string topic, JsonRpcRequest payload)
{
var id = payload.Id;
@@ -461,18 +442,14 @@ private async Task OnPairingDeleteRequest(string topic, JsonRpcRequest(id, topic, true);
await DeletePairing(topic);
- this.PairingDeleted?.Invoke(this, new PairingEvent()
- {
- Topic = topic,
- Id = id
- });
+ this.PairingDeleted?.Invoke(this, new PairingEvent() { Topic = topic, Id = id });
}
catch (WalletConnectException e)
{
await Core.MessageHandler.SendError(id, topic, Error.FromException(e));
}
}
-
+
private async Task IsValidDisconnect(string topic, Error reason)
{
if (string.IsNullOrWhiteSpace(topic))
@@ -482,9 +459,10 @@ private async Task IsValidDisconnect(string topic, Error reason)
await IsValidPairingTopic(topic);
}
-
+
private async void ExpiredCallback(object sender, ExpirerEventArgs e)
{
+ WCLogger.Log($"Expired topic {e.Target}");
var target = new ExpirerTarget(e.Target);
if (string.IsNullOrWhiteSpace(target.Topic)) return;
@@ -493,16 +471,26 @@ private async void ExpiredCallback(object sender, ExpirerEventArgs e)
if (this.Store.Keys.Contains(topic))
{
await DeletePairing(topic);
- this.PairingExpired?.Invoke(this, new PairingEvent()
- {
- Topic = topic,
- });
+ this.PairingExpired?.Invoke(this, new PairingEvent() { Topic = topic, });
}
}
public void Dispose()
{
- Store?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ Store?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/Relayer.cs b/WalletConnectSharp.Core/Controllers/Relayer.cs
index 1e11f87..219fa8d 100644
--- a/WalletConnectSharp.Core/Controllers/Relayer.cs
+++ b/WalletConnectSharp.Core/Controllers/Relayer.cs
@@ -122,6 +122,7 @@ public bool TransportExplicitlyClosed
private string projectId;
private bool initialized;
private bool reconnecting = false;
+ protected bool Disposed;
///
/// Create a new Relayer with the given RelayerOptions.
@@ -488,9 +489,23 @@ private async Task ToEstablishConnection()
public void Dispose()
{
- Subscriber?.Dispose();
- Publisher?.Dispose();
- Messages?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ Subscriber?.Dispose();
+ Publisher?.Dispose();
+ Messages?.Dispose();
+ Provider?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/Store.cs b/WalletConnectSharp.Core/Controllers/Store.cs
index 9cfb68f..4e6091c 100644
--- a/WalletConnectSharp.Core/Controllers/Store.cs
+++ b/WalletConnectSharp.Core/Controllers/Store.cs
@@ -17,15 +17,17 @@ namespace WalletConnectSharp.Core.Controllers
/// The type of the values stored, the value must contain the key
public class Store : IStore where TValue : IKeyHolder
{
+ protected bool Disposed;
+
private bool initialized;
private Dictionary map = new Dictionary();
private TValue[] cached = Array.Empty();
-
+
///
/// The ICore module using this Store module
///
public ICore Core { get; }
-
+
///
/// The StoragePrefix this Store module will prepend to the storage key
///
@@ -41,12 +43,12 @@ public string Version
return "0.3";
}
}
-
+
///
/// The Name of this Store module
///
public string Name { get; }
-
+
///
/// The context string of this Store module
///
@@ -109,7 +111,7 @@ public Store(ICore core, string name, string storagePrefix = null)
name = $"{core.Name}-{name}";
Name = name;
Context = name;
-
+
if (storagePrefix == null)
StoragePrefix = WalletConnectCore.STORAGE_PREFIX;
else
@@ -152,6 +154,7 @@ public Task Set(TKey key, TValue value)
{
return Update(key, value);
}
+
map.Add(key, value);
return Persist();
}
@@ -179,7 +182,7 @@ public TValue Get(TKey key)
public Task Update(TKey key, TValue update)
{
IsInitialized();
-
+
// Partial updates aren't built into C#
// However, we can use reflection to sort of
// get the same thing
@@ -205,7 +208,7 @@ public Task Update(TKey key, TValue update)
previousValue = (TValue)test;
}
}
-
+
var fields = t.GetFields();
// Loop through all of them
@@ -221,7 +224,7 @@ public Task Update(TKey key, TValue update)
previousValue = (TValue)test;
}
}
-
+
// Now, set the update variable to be the new modified
// previousValue object
update = previousValue;
@@ -312,7 +315,22 @@ protected virtual void IsInitialized()
public void Dispose()
{
- Core?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ map.Clear();
+ map = null;
+ cached = null;
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs
index c88102f..fbaa626 100644
--- a/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs
+++ b/WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs
@@ -18,7 +18,9 @@ public class TypedMessageHandler : ITypedMessageHandler
public event EventHandler RawMessage;
private EventHandlerMap messageEventHandlerMap = new();
-
+
+ protected bool Disposed;
+
public ICore Core { get; }
///
@@ -47,7 +49,7 @@ public TypedMessageHandler(ICore core)
{
this.Core = core;
}
-
+
public Task Init()
{
if (!_initialized)
@@ -58,7 +60,7 @@ public Task Init()
_initialized = true;
return Task.CompletedTask;
}
-
+
async void RelayerMessageCallback(object sender, MessageEvent e)
{
var topic = e.Topic;
@@ -73,12 +75,8 @@ async void RelayerMessageCallback(object sender, MessageEvent e)
}
else if (payload.IsResponse)
{
- this.RawMessage?.Invoke(this, new DecodedMessageEvent()
- {
- Topic = topic,
- Message = message,
- Payload = payload
- });
+ this.RawMessage?.Invoke(this,
+ new DecodedMessageEvent() { Topic = topic, Message = message, Payload = payload });
}
}
@@ -90,34 +88,35 @@ async void RelayerMessageCallback(object sender, MessageEvent e)
/// The callback function to invoke when a response is received with the given response type
/// The request type to trigger the requestCallback for
/// The response type to trigger the responseCallback for
- public async void HandleMessageType(Func, Task> requestCallback, Func, Task> responseCallback)
+ public async void HandleMessageType(Func, Task> requestCallback,
+ Func, Task> responseCallback)
{
var method = RpcMethodAttribute.MethodForType();
var rpcHistory = await this.Core.History.JsonRpcHistoryOfType();
-
+
async void RequestCallback(object sender, MessageEvent e)
{
if (requestCallback == null) return;
-
+
var topic = e.Topic;
var message = e.Message;
-
+
var options = DecodeOptionForTopic(topic);
var payload = await this.Core.Crypto.Decode>(topic, message, options);
-
+
(await this.Core.History.JsonRpcHistoryOfType()).Set(topic, payload, null);
await requestCallback(topic, payload);
}
-
+
async void ResponseCallback(object sender, MessageEvent e)
{
if (responseCallback == null) return;
-
+
var topic = e.Topic;
var message = e.Message;
-
+
var options = DecodeOptionForTopic(topic);
var rawResultPayload = await this.Core.Crypto.Decode(topic, message, options);
@@ -128,7 +127,7 @@ async void ResponseCallback(object sender, MessageEvent e)
try
{
var payload = await this.Core.Crypto.Decode>(topic, message, options);
-
+
await history.Resolve(payload);
await responseCallback(topic, payload);
@@ -155,26 +154,23 @@ async void InspectResponseRaw(object sender, DecodedMessageEvent e)
// ignored if we can't find anything in the history
if (record == null) return;
var resMethod = record.Request.Method;
-
+
// Trigger the true response event, which will trigger ResponseCallback
- messageEventHandlerMap[$"response_{resMethod}"](this, new MessageEvent()
- {
- Topic = topic,
- Message = message
- });
+ messageEventHandlerMap[$"response_{resMethod}"](this,
+ new MessageEvent() { Topic = topic, Message = message });
}
- catch(WalletConnectException err)
+ catch (WalletConnectException err)
{
if (err.CodeType != ErrorType.NO_MATCHING_KEY)
throw;
-
+
// ignored if we can't find anything in the history
}
}
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
this.RawMessage += InspectResponseRaw;
@@ -197,7 +193,8 @@ public PublishOptions RpcRequestOptionsFromType()
opts = RpcRequestOptionsForType();
if (opts == null)
{
- throw new Exception($"No RpcRequestOptions attribute found in either {typeof(T1).FullName} or {typeof(T2).FullName}!");
+ throw new Exception(
+ $"No RpcRequestOptions attribute found in either {typeof(T1).FullName} or {typeof(T2).FullName}!");
}
}
@@ -222,11 +219,7 @@ public PublishOptions RpcRequestOptionsForType()
var opts = attributes.Cast().First();
- return new PublishOptions()
- {
- Tag = opts.Tag,
- TTL = opts.TTL
- };
+ return new PublishOptions() { Tag = opts.Tag, TTL = opts.TTL };
}
///
@@ -249,12 +242,13 @@ public PublishOptions RpcResponseOptionsFromTypes()
opts = RpcResponseOptionsForType();
if (opts == null)
{
- throw new Exception($"No RpcResponseOptions attribute found in either {typeof(T1).FullName} or {typeof(T2).FullName}!");
+ throw new Exception(
+ $"No RpcResponseOptions attribute found in either {typeof(T1).FullName} or {typeof(T2).FullName}!");
}
return opts;
}
-
+
///
/// Build from an from
/// the given type T
@@ -273,11 +267,7 @@ public PublishOptions RpcResponseOptionsForType()
var opts = attributes.Cast().First();
- return new PublishOptions()
- {
- Tag = opts.Tag,
- TTL = opts.TTL
- };
+ return new PublishOptions() { Tag = opts.Tag, TTL = opts.TTL };
}
public void SetDecodeOptionsForTopic(DecodeOptions options, string topic)
@@ -287,9 +277,7 @@ public void SetDecodeOptionsForTopic(DecodeOptions options, string topic)
public DecodeOptions DecodeOptionForTopic(string topic)
{
- if (_decodeOptionsMap.ContainsKey(topic))
- return _decodeOptionsMap[topic];
- return null;
+ return _decodeOptionsMap.TryGetValue(topic, out var option) ? option : null;
}
///
@@ -301,14 +289,15 @@ public DecodeOptions DecodeOptionForTopic(string topic)
/// The request type
/// The response type
/// The id of the request sent
- public async Task SendRequest(string topic, T parameters, long? expiry = null, EncodeOptions options = null)
+ public async Task SendRequest(string topic, T parameters, long? expiry = null,
+ EncodeOptions options = null)
{
EnsureTypeIsSerializerSafe(parameters);
-
+
var method = RpcMethodAttribute.MethodForType();
var payload = new JsonRpcRequest(method, parameters);
-
+
WCLogger.Log(JsonConvert.SerializeObject(payload));
var message = await this.Core.Crypto.Encode(topic, payload, options);
@@ -319,7 +308,7 @@ public async Task SendRequest(string topic, T parameters, long? exp
{
opts.TTL = (long)expiry;
}
-
+
(await this.Core.History.JsonRpcHistoryOfType()).Set(topic, payload, null);
// await is intentionally omitted here because of a possible race condition
@@ -342,7 +331,7 @@ public async Task SendRequest(string topic, T parameters, long? exp
public async Task SendResult(long id, string topic, TR result, EncodeOptions options = null)
{
EnsureTypeIsSerializerSafe(result);
-
+
var payload = new JsonRpcResponse(id, null, result);
var message = await this.Core.Crypto.Encode(topic, payload, options);
var opts = RpcResponseOptionsFromTypes();
@@ -362,7 +351,7 @@ public async Task SendError(long id, string topic, Error error, EncodeOpt
{
// Type Error is always serializer safe
// EnsureTypeIsSerializerSafe(error);
-
+
var payload = new JsonRpcResponse(id, error, default);
var message = await this.Core.Crypto.Encode(topic, payload, options);
var opts = RpcResponseOptionsFromTypes();
@@ -370,21 +359,36 @@ public async Task SendError(long id, string topic, Error error, EncodeOpt
await (await this.Core.History.JsonRpcHistoryOfType()).Resolve(payload);
}
- public void Dispose()
- {
- }
-
private void EnsureTypeIsSerializerSafe(T testObject)
{
var typeString = typeof(T).FullName;
if (_typeSafeCache.Contains(typeString))
return;
-
+
// Throw any serialization exceptions now
// before it's too late
TypeSafety.EnsureTypeSerializerSafe(testObject);
_typeSafeCache.Add(typeString);
}
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed)
+ return;
+
+ if (disposing)
+ {
+ this.Core.Relayer.OnMessageReceived -= RelayerMessageCallback;
+ }
+
+ Disposed = true;
+ }
}
}
diff --git a/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs b/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs
index f010a09..2d2093f 100644
--- a/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs
+++ b/WalletConnectSharp.Core/Interfaces/IHeartBeat.cs
@@ -9,7 +9,7 @@ namespace WalletConnectSharp.Core.Interfaces
public interface IHeartBeat : IModule
{
event EventHandler OnPulse;
-
+
///
/// The interval (in milliseconds) the Pulse event gets emitted/triggered
///
@@ -21,6 +21,6 @@ public interface IHeartBeat : IModule
/// HeartBeatCancellationToken is cancelled, then the interval will be halted.
///
///
- public Task Init();
+ public Task InitAsync(CancellationToken cancellationToken = default);
}
}
diff --git a/WalletConnectSharp.Core/WalletConnectCore.cs b/WalletConnectSharp.Core/WalletConnectCore.cs
index ad00dcf..e3d06af 100644
--- a/WalletConnectSharp.Core/WalletConnectCore.cs
+++ b/WalletConnectSharp.Core/WalletConnectCore.cs
@@ -112,6 +112,8 @@ public string Context
public CoreOptions Options { get; }
+ protected bool Disposed;
+
///
/// Create a new Core with the given options.
///
@@ -192,7 +194,7 @@ private async Task Initialize()
await Storage.Init();
await Crypto.Init();
await Relayer.Init();
- await HeartBeat.Init();
+ await HeartBeat.InitAsync();
await Expirer.Init();
await MessageHandler.Init();
await Pairing.Init();
@@ -200,13 +202,26 @@ private async Task Initialize()
public void Dispose()
{
- HeartBeat?.Dispose();
- Crypto?.Dispose();
- Relayer?.Dispose();
- Storage?.Dispose();
- MessageHandler?.Dispose();
- Expirer?.Dispose();
- Pairing?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ HeartBeat?.Dispose();
+ Crypto?.Dispose();
+ Relayer?.Dispose();
+ Storage?.Dispose();
+ MessageHandler?.Dispose();
+ Expirer?.Dispose();
+ Pairing?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Sign/Engine.cs b/WalletConnectSharp.Sign/Engine.cs
index 94b1ddd..7bdda1b 100644
--- a/WalletConnectSharp.Sign/Engine.cs
+++ b/WalletConnectSharp.Sign/Engine.cs
@@ -24,12 +24,14 @@ namespace WalletConnectSharp.Sign
///
public partial class Engine : IEnginePrivate, IEngine, IModule
{
+ protected bool Disposed;
+
private const long ProposalExpiry = Clock.THIRTY_DAYS;
private const long SessionExpiry = Clock.SEVEN_DAYS;
private const int KeyLength = 32;
private bool _initialized = false;
-
+
///
/// The using this Engine
///
@@ -80,7 +82,7 @@ public async Task Init()
if (!this._initialized)
{
SetupEvents();
-
+
await PrivateThis.Cleanup();
this.RegisterRelayerEvents();
this.RegisterExpirerEvents();
@@ -108,100 +110,105 @@ private void RegisterExpirerEvents()
private void RegisterRelayerEvents()
{
// Register all Request Types
- MessageHandler.HandleMessageType(PrivateThis.OnSessionProposeRequest, PrivateThis.OnSessionProposeResponse);
- MessageHandler.HandleMessageType(PrivateThis.OnSessionSettleRequest, PrivateThis.OnSessionSettleResponse);
- MessageHandler.HandleMessageType(PrivateThis.OnSessionUpdateRequest, PrivateThis.OnSessionUpdateResponse);
- MessageHandler.HandleMessageType(PrivateThis.OnSessionExtendRequest, PrivateThis.OnSessionExtendResponse);
+ MessageHandler.HandleMessageType(
+ PrivateThis.OnSessionProposeRequest, PrivateThis.OnSessionProposeResponse);
+ MessageHandler.HandleMessageType(PrivateThis.OnSessionSettleRequest,
+ PrivateThis.OnSessionSettleResponse);
+ MessageHandler.HandleMessageType(PrivateThis.OnSessionUpdateRequest,
+ PrivateThis.OnSessionUpdateResponse);
+ MessageHandler.HandleMessageType(PrivateThis.OnSessionExtendRequest,
+ PrivateThis.OnSessionExtendResponse);
MessageHandler.HandleMessageType(PrivateThis.OnSessionDeleteRequest, null);
- MessageHandler.HandleMessageType(PrivateThis.OnSessionPingRequest, PrivateThis.OnSessionPingResponse);
+ MessageHandler.HandleMessageType(PrivateThis.OnSessionPingRequest,
+ PrivateThis.OnSessionPingResponse);
}
-
+
///
/// This event is invoked when the given session has expired
/// Event Side: dApp & Wallet
///
public event EventHandler SessionExpired;
-
+
///
/// This event is invoked when the given pairing has expired
/// Event Side: Wallet
///
public event EventHandler PairingExpired;
-
+
///
/// This event is invoked when a new session is proposed. This is usually invoked
/// after a new pairing has been activated from a URI
/// Event Side: Wallet
///
public event EventHandler SessionProposed;
-
+
///
/// This event is invoked when a proposed session has been connected to a wallet. This event is
/// triggered after the session has been approved by a wallet
/// Event Side: dApp
///
public event EventHandler SessionConnected;
-
+
///
/// This event is invoked when a proposed session connection failed with an error
/// Event Side: dApp
///
public event EventHandler SessionConnectionErrored;
-
+
///
/// This event is invoked when a given session sent a update request.
/// Event Side: Wallet
///
public event EventHandler SessionUpdateRequest;
-
+
///
/// This event is invoked when a given session sent a extend request.
/// Event Side: Wallet
///
public event EventHandler SessionExtendRequest;
-
+
///
/// This event is invoked when a given session update request was successful.
/// Event Side: dApp
///
public event EventHandler SessionUpdated;
-
+
///
/// This event is invoked when a given session extend request was successful.
/// Event Side: dApp
///
public event EventHandler SessionExtended;
-
+
///
/// This event is invoked when a given session has been pinged
/// Event Side: dApp & Wallet
///
public event EventHandler SessionPinged;
-
+
///
/// This event is invoked whenever a session has been deleted
/// Event Side: dApp & Wallet
///
public event EventHandler SessionDeleted;
-
+
///
/// This event is invoked whenever a session has been rejected
/// Event Side: Wallet
///
public event EventHandler SessionRejected;
-
+
///
/// This event is invoked whenever a session has been approved
/// Event Side: Wallet
///
public event EventHandler SessionApproved;
-
+
///
/// This event is invoked whenever a pairing is pinged
/// Event Side: dApp & Wallet
///
public event EventHandler PairingPinged;
-
+
///
/// This event is invoked whenever a pairing is deleted
/// Event Side: dApp & Wallet
@@ -228,11 +235,13 @@ public TypedEventHandler SessionRequestEvents()
/// 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 HandleSessionRequestMessageType(Func>, Task> requestCallback, Func, Task> responseCallback)
+ public void HandleSessionRequestMessageType(
+ Func>, Task> requestCallback,
+ Func, Task> responseCallback)
{
Client.Core.MessageHandler.HandleMessageType(requestCallback, responseCallback);
}
-
+
///
/// An alias for where T is and
/// TR is unchanged
@@ -240,7 +249,8 @@ 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
- public void HandleEventMessageType(Func>, Task> requestCallback, Func, Task> responseCallback)
+ public void HandleEventMessageType(Func>, Task> requestCallback,
+ Func, Task> responseCallback)
{
Client.Core.MessageHandler.HandleMessageType(requestCallback, responseCallback);
}
@@ -292,7 +302,9 @@ public Task Disconnect(Error reason = null)
public UriParameters ParseUri(string uri)
{
var pathStart = uri.IndexOf(":", StringComparison.Ordinal);
- int? pathEnd = uri.IndexOf("?", StringComparison.Ordinal) != -1 ? uri.IndexOf("?", StringComparison.Ordinal) : (int?)null;
+ int? pathEnd = uri.IndexOf("?", StringComparison.Ordinal) != -1
+ ? uri.IndexOf("?", StringComparison.Ordinal)
+ : (int?)null;
var protocol = uri.Substring(0, pathStart);
string path;
@@ -344,7 +356,7 @@ public async Task Connect(ConnectOptions options)
await PrivateThis.IsValidConnect(options);
var requiredNamespaces = options.RequiredNamespaces;
var optionalNamespaces = options.OptionalNamespaces;
- var sessionProperties = options.SessionProperties;
+ var sessionProperties = options.SessionProperties;
var relays = options.Relays;
var topic = options.PairingTopic;
string uri = "";
@@ -355,7 +367,7 @@ public async Task Connect(ConnectOptions options)
var pairing = this.Client.Core.Pairing.Store.Get(topic);
if (pairing.Active != null)
active = pairing.Active.Value;
-
+
WCLogger.Log($"Loaded pairing for {topic}");
}
@@ -364,7 +376,7 @@ public async Task Connect(ConnectOptions options)
var CreatePairing = await this.Client.Core.Pairing.Create();
topic = CreatePairing.Topic;
uri = CreatePairing.Uri;
-
+
WCLogger.Log($"Created pairing for new topic: {topic}");
}
@@ -374,22 +386,12 @@ public async Task Connect(ConnectOptions options)
RequiredNamespaces = requiredNamespaces,
Relays = relays != null
? new[] { relays }
- : new[]
- {
- new ProtocolOptions()
- {
- Protocol = RelayProtocols.Default
- }
- },
- Proposer = new Participant()
- {
- PublicKey = publicKey,
- Metadata = this.Client.Metadata
- },
+ : new[] { new ProtocolOptions() { Protocol = RelayProtocols.Default } },
+ Proposer = new Participant() { PublicKey = publicKey, Metadata = this.Client.Metadata },
OptionalNamespaces = optionalNamespaces,
SessionProperties = sessionProperties,
};
-
+
WCLogger.Log($"Created public key pair");
TaskCompletionSource approvalTask = new TaskCompletionSource();
@@ -406,11 +408,12 @@ public async Task Connect(ConnectOptions options)
var completeSession = session with { RequiredNamespaces = requiredNamespaces };
await PrivateThis.SetExpiry(session.Topic, session.Expiry.Value);
await Client.Session.Set(session.Topic, completeSession);
-
+
if (!string.IsNullOrWhiteSpace(topic))
{
await this.Client.Core.Pairing.UpdateMetadata(topic, session.Peer.Metadata);
}
+
approvalTask.SetResult(completeSession);
};
@@ -438,9 +441,9 @@ public async Task Connect(ConnectOptions options)
}
logger.Log($"Sending request JSON {JsonConvert.SerializeObject(proposal)} to topic {topic}");
-
+
var id = await MessageHandler.SendRequest(topic, proposal);
-
+
logger.Log($"Got back {id} as request pending id");
var expiry = Clock.CalculateExpiry(options.Expiry);
@@ -456,11 +459,7 @@ public async Task Connect(ConnectOptions options)
SessionProperties = proposal.SessionProperties,
});
- return new ConnectedData()
- {
- Uri = uri,
- Approval = approvalTask.Task
- };
+ return new ConnectedData() { Uri = uri, Approval = approvalTask.Task };
}
///
@@ -524,16 +523,9 @@ public async Task Approve(ApproveParams @params)
var sessionSettle = new SessionSettle()
{
- Relay = new ProtocolOptions()
- {
- Protocol = relayProtocol != null ? relayProtocol : "irn"
- },
+ Relay = new ProtocolOptions() { Protocol = relayProtocol != null ? relayProtocol : "irn" },
Namespaces = namespaces,
- Controller = new Participant()
- {
- PublicKey = selfPublicKey,
- Metadata = this.Client.Metadata
- },
+ Controller = new Participant() { PublicKey = selfPublicKey, Metadata = this.Client.Metadata },
Expiry = Clock.CalculateExpiry(SessionExpiry)
};
@@ -573,16 +565,13 @@ public async Task Approve(ApproveParams @params)
await MessageHandler.SendResult(id, pairingTopic,
new SessionProposeResponse()
{
- Relay = new ProtocolOptions()
- {
- Protocol = relayProtocol != null ? relayProtocol : "irn"
- },
+ Relay = new ProtocolOptions() { Protocol = relayProtocol != null ? relayProtocol : "irn" },
ResponderPublicKey = selfPublicKey
});
await this.Client.Proposal.Delete(id, Error.FromErrorType(ErrorType.USER_DISCONNECTED));
await this.Client.Core.Pairing.Activate(pairingTopic);
}
-
+
return IApprovedData.FromTask(sessionTopic, acknowledgedTask.Task);
}
@@ -620,10 +609,8 @@ public async Task UpdateSession(string topic, Namespaces names
{
IsInitialized();
await PrivateThis.IsValidUpdate(topic, namespaces);
- var id = await MessageHandler.SendRequest(topic, new SessionUpdate()
- {
- Namespaces = namespaces
- });
+ var id = await MessageHandler.SendRequest(topic,
+ new SessionUpdate() { Namespaces = namespaces });
TaskCompletionSource acknowledgedTask = new TaskCompletionSource();
this.sessionEventsHandlerMap.ListenOnce($"session_update{id}", (sender, args) =>
@@ -634,11 +621,8 @@ public async Task UpdateSession(string topic, Namespaces names
acknowledgedTask.SetResult(args.Result);
});
- await this.Client.Session.Update(topic, new SessionStruct()
- {
- Namespaces = namespaces
- });
-
+ await this.Client.Session.Update(topic, new SessionStruct() { Namespaces = namespaces });
+
return IAcknowledgement.FromTask(acknowledgedTask.Task);
}
@@ -652,7 +636,7 @@ public async Task Extend(string topic)
IsInitialized();
await PrivateThis.IsValidExtend(topic);
var id = await MessageHandler.SendRequest(topic, new SessionExtend());
-
+
TaskCompletionSource acknowledgedTask = new TaskCompletionSource();
this.sessionEventsHandlerMap.ListenOnce($"session_extend{id}", (sender, args) =>
@@ -664,7 +648,7 @@ public async Task Extend(string topic)
});
await PrivateThis.SetExpiry(topic, Clock.CalculateExpiry(SessionExpiry));
-
+
return IAcknowledgement.FromTask(acknowledgedTask.Task);
}
@@ -704,13 +688,13 @@ public async Task Request(string topic, T data, string chainId = null
}
var request = new JsonRpcRequest(method, data);
-
+
IsInitialized();
await PrivateThis.IsValidRequest(topic, request, defaultChainId);
long[] id = new long[1];
-
+
var taskSource = new TaskCompletionSource();
-
+
SessionRequestEvents()
.FilterResponses((e) => e.Topic == topic && e.Response.Id == id[0])
.OnResponse += args =>
@@ -723,12 +707,9 @@ public async Task Request(string topic, T data, string chainId = null
return Task.CompletedTask;
};
- id[0] = await MessageHandler.SendRequest, TR>(topic, new SessionRequest()
- {
- ChainId = defaultChainId,
- Request = request
- });
-
+ id[0] = await MessageHandler.SendRequest, TR>(topic,
+ new SessionRequest() { ChainId = defaultChainId, Request = request });
+
return await taskSource.Task;
}
@@ -770,12 +751,8 @@ public async Task Respond(string topic, JsonRpcResponse response)
public async Task Emit(string topic, EventData @event, string chainId = null)
{
IsInitialized();
- await MessageHandler.SendRequest, object>(topic, new SessionEvent()
- {
- ChainId = chainId,
- Event = @event,
- Topic = topic,
- });
+ await MessageHandler.SendRequest, object>(topic,
+ new SessionEvent() { ChainId = chainId, Event = @event, Topic = topic, });
}
///
@@ -786,7 +763,7 @@ public async Task Ping(string topic)
{
IsInitialized();
await PrivateThis.IsValidPing(topic);
-
+
if (this.Client.Session.Keys.Contains(topic))
{
var id = await MessageHandler.SendRequest(topic, new SessionPing());
@@ -799,7 +776,7 @@ public async Task Ping(string topic)
done.SetResult(args.Result);
});
await done.Task;
- }
+ }
else if (this.Client.Core.Pairing.Store.Keys.Contains(topic))
{
await this.Client.Core.Pairing.Ping(topic);
@@ -816,22 +793,14 @@ public async Task Disconnect(string topic, Error reason)
IsInitialized();
var error = reason ?? Error.FromErrorType(ErrorType.USER_DISCONNECTED);
await PrivateThis.IsValidDisconnect(topic, error);
-
+
if (this.Client.Session.Keys.Contains(topic))
{
- var id = await MessageHandler.SendRequest(topic, new SessionDelete()
- {
- Code = error.Code,
- Message = error.Message,
- Data = error.Data
- });
+ var id = await MessageHandler.SendRequest(topic,
+ new SessionDelete() { Code = error.Code, Message = error.Message, Data = error.Data });
await PrivateThis.DeleteSession(topic);
- this.SessionDeleted?.Invoke(this, new SessionEvent()
- {
- Topic = topic,
- Id = id
- });
- }
+ this.SessionDeleted?.Invoke(this, new SessionEvent() { Topic = topic, Id = id });
+ }
else if (this.Client.Core.Pairing.Store.Keys.Contains(topic))
{
await this.Client.Core.Pairing.Disconnect(topic);
@@ -885,7 +854,20 @@ public Task Reject(ProposalStruct proposalStruct, Error error)
public void Dispose()
{
- Client?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ Client?.Dispose();
+ }
+
+ Disposed = true;
}
}
}
diff --git a/WalletConnectSharp.Sign/WalletConnectSignClient.cs b/WalletConnectSharp.Sign/WalletConnectSignClient.cs
index 7f8cb82..6a793ee 100644
--- a/WalletConnectSharp.Sign/WalletConnectSignClient.cs
+++ b/WalletConnectSharp.Sign/WalletConnectSignClient.cs
@@ -27,12 +27,12 @@ public class WalletConnectSignClient : ISignClient
/// The protocol ALL Sign Client will use as a protocol string
///
public static readonly string PROTOCOL = "wc";
-
+
///
/// The protocol version ALL Sign Client use
///
public static readonly int VERSION = 2;
-
+
///
/// The base context string ALL Sign Client use
///
@@ -52,7 +52,7 @@ public class WalletConnectSignClient : ISignClient
/// The context string for this Sign Client module
///
public string Context { get; }
-
+
///
/// The Metadata for this instance of the Sign Client module
///
@@ -64,23 +64,23 @@ public class WalletConnectSignClient : ISignClient
/// The module this Sign Client module is using
///
public ICore Core { get; }
-
+
///
/// The module this Sign Client module is using. Used to do all
/// protocol activities behind the scenes, should not be used directly.
///
public IEngine Engine { get; }
-
+
///
/// The module this Sign Client module is using. Used for storing pairing data
///
public IPairingStore PairingStore { get; }
-
+
///
/// The module this Sign Client module is using. Used for storing session data
///
public ISession Session { get; }
-
+
///
/// The module this Sign Client module is using. Used for storing proposal data
///
@@ -115,6 +115,7 @@ public int Version
}
}
+ protected bool Disposed;
public event EventHandler SessionExpired;
public event EventHandler PairingExpired;
@@ -165,7 +166,7 @@ private WalletConnectSignClient(SignClientOptions options)
throw new ArgumentException("The Metadata field must be set in the SignClientOptions object");
else
Metadata = options.Metadata;
-
+
Options = options;
if (string.IsNullOrWhiteSpace(options.Name))
@@ -175,7 +176,7 @@ private WalletConnectSignClient(SignClientOptions options)
else
throw new ArgumentException("The Name field in Metadata must be set");
}
-
+
Name = options.Name;
if (string.IsNullOrWhiteSpace(options.BaseContext))
@@ -204,7 +205,7 @@ private WalletConnectSignClient(SignClientOptions options)
Proposal = new Proposal(Core);
Engine = new Engine(this);
AddressProvider = new AddressProvider(this);
-
+
SetupEvents();
}
@@ -293,7 +294,7 @@ public Task Reject(RejectParams @params)
{
return Engine.Reject(@params);
}
-
+
///
/// Reject a proposal that was recently paired. If the given proposal was not from a recent pairing,
/// or the proposal has expired, then an Exception will be thrown.
@@ -308,13 +309,9 @@ public Task Reject(ProposalStruct proposalStruct, string message = null)
if (message == null)
message = "Proposal denied by remote host";
- return Reject(proposalStruct, new Error()
- {
- Message = message,
- Code = (long) ErrorType.USER_DISCONNECTED,
- });
+ return Reject(proposalStruct, new Error() { Message = message, Code = (long)ErrorType.USER_DISCONNECTED, });
}
-
+
///
/// Reject a proposal that was recently paired. If the given proposal was not from a recent pairing,
/// or the proposal has expired, then an Exception will be thrown.
@@ -326,12 +323,8 @@ public Task Reject(ProposalStruct proposalStruct, Error error)
if (proposalStruct.Id == null)
throw new ArgumentException("No proposal Id given");
- var rejectParams = new RejectParams()
- {
- Id = (long) proposalStruct.Id,
- Reason = error
- };
-
+ var rejectParams = new RejectParams() { Id = (long)proposalStruct.Id, Reason = error };
+
return Reject(rejectParams);
}
@@ -434,7 +427,8 @@ public SessionStruct[] Find(RequiredNamespaces requiredNamespaces)
return Engine.Find(requiredNamespaces);
}
- public void HandleEventMessageType(Func>, Task> requestCallback, Func, Task> responseCallback)
+ public void HandleEventMessageType(Func>, Task> requestCallback,
+ Func, Task> responseCallback)
{
this.Engine.HandleEventMessageType(requestCallback, responseCallback);
}
@@ -486,11 +480,24 @@ private async Task Initialize()
public void Dispose()
{
- Core?.Dispose();
- PairingStore?.Dispose();
- Session?.Dispose();
- Proposal?.Dispose();
- PendingRequests?.Dispose();
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (Disposed) return;
+
+ if (disposing)
+ {
+ Core?.Dispose();
+ PairingStore?.Dispose();
+ Session?.Dispose();
+ Proposal?.Dispose();
+ PendingRequests?.Dispose();
+ }
+
+ Disposed = true;
}
}
}