-
Notifications
You must be signed in to change notification settings - Fork 62
/
Copy pathSessionRequestEventHandler.cs
116 lines (95 loc) · 4.57 KB
/
SessionRequestEventHandler.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using WalletConnectSharp.Common.Logging;
using WalletConnectSharp.Common.Model.Errors;
using WalletConnectSharp.Core.Interfaces;
using WalletConnectSharp.Network.Models;
using WalletConnectSharp.Sign.Interfaces;
using WalletConnectSharp.Sign.Models.Engine.Methods;
namespace WalletConnectSharp.Sign.Models
{
/// <summary>
/// A sub-class of <see cref="TypedEventHandler{T,TR}"/> that fixes complex nesting issue with
/// SessionRequest<T>. The purpose of this class is to un-nest the SessionRequest<T> object
/// </summary>
/// <typeparam name="T">The type of the session request</typeparam>
/// <typeparam name="TR">The type of the response for the session request</typeparam>
public class SessionRequestEventHandler<T, TR> : TypedEventHandler<T, TR>
{
private readonly IEnginePrivate _enginePrivate;
/// <summary>
/// Get a singleton instance of this class for the given <see cref="IEngine"/> context. The context
/// string of the given <see cref="IEngine"/> will be used to determine the singleton instance to
/// return (or if a new one needs to be created). Beware that multiple <see cref="IEngine"/> instances
/// with the same context string will share the same event handlers.
/// </summary>
/// <param name="engine">The engine this singleton instance is for, and where the context string will
/// be read from</param>
/// <returns>The singleton instance to use for request/response event handlers</returns>
public static TypedEventHandler<T, TR> GetInstance(ICore engine, IEnginePrivate enginePrivate)
{
var context = engine.Context;
if (Instances.TryGetValue(context, out var instance))
return instance;
var newInstance = new SessionRequestEventHandler<T, TR>(engine, enginePrivate);
Instances.Add(context, newInstance);
return newInstance;
}
protected SessionRequestEventHandler(ICore engine, IEnginePrivate enginePrivate) : base(engine)
{
this._enginePrivate = enginePrivate;
}
protected override TypedEventHandler<T, TR> BuildNew(ICore @ref,
Func<RequestEventArgs<T, TR>, bool> requestPredicate, Func<ResponseEventArgs<TR>, bool> responsePredicate)
{
var instance = new SessionRequestEventHandler<T, TR>(@ref, _enginePrivate)
{
RequestPredicate = requestPredicate, ResponsePredicate = responsePredicate
};
_disposeActions.Add(instance.Dispose);
return instance;
}
protected override void Setup()
{
var wrappedRef = TypedEventHandler<SessionRequest<T>, TR>.GetInstance(Ref);
wrappedRef.OnRequest += WrappedRefOnOnRequest;
wrappedRef.OnResponse += WrappedRefOnOnResponse;
_disposeActions.Add(() =>
{
wrappedRef.OnRequest -= WrappedRefOnOnRequest;
wrappedRef.OnResponse -= WrappedRefOnOnResponse;
wrappedRef.Dispose();
});
}
private Task WrappedRefOnOnResponse(ResponseEventArgs<TR> e)
{
return base.ResponseCallback(e.Topic, e.Response);
}
private async Task WrappedRefOnOnRequest(RequestEventArgs<SessionRequest<T>, TR> e)
{
// Ensure that the request is for us
var method = RpcMethodAttribute.MethodForType<T>();
var sessionRequest = e.Request.Params.Request;
if (sessionRequest.Method != method) return;
//Set inner request id to match outer request id
sessionRequest.Id = e.Request.Id;
//Add to pending requests
//We can't do a simple cast, so we need to copy all the data
await _enginePrivate.SetPendingSessionRequest(new PendingRequestStruct()
{
Id = e.Request.Id,
Parameters = new SessionRequest<object>()
{
ChainId = e.Request.Params.ChainId,
Request = new JsonRpcRequest<object>()
{
Id = sessionRequest.Id,
Method = sessionRequest.Method,
Params = sessionRequest.Params
}
},
Topic = e.Topic
});
await base.RequestCallback(e.Topic, sessionRequest);
await _enginePrivate.DeletePendingSessionRequest(e.Request.Id, Error.FromErrorType(ErrorType.GENERIC));
}
}
}