1
+ // ----------------------------------------------------------------------------------
2
+ //
3
+ // Copyright Microsoft Corporation
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ // ----------------------------------------------------------------------------------
14
+
15
+
16
+ using System ;
17
+ using System . Collections . Generic ;
18
+ using System . ComponentModel ;
19
+ using System . Diagnostics . Tracing ;
20
+ using System . Net . Http ;
21
+ using System . Threading ;
22
+ using System . Threading . Tasks ;
23
+ using GetEventData = System . Func < Microsoft . Azure . Commands . Common . EventData > ;
24
+
25
+
26
+ namespace Microsoft . Azure . Commands . Common
27
+ {
28
+
29
+
30
+ using EventListenerDelegate = Func < EventData , Task > ;
31
+ using GetParameterDelegate = Func < string , Dictionary < string , object > , string , object > ;
32
+ using SendAsyncStep = Func < HttpRequestMessage , IEventListener , ISendAsync , Task < HttpResponseMessage > > ;
33
+ using PipelineChangeDelegate = Action < EventData > ;
34
+
35
+ /// <summary>
36
+ /// The IEventListener Interface defines the communication mechanism for Signaling events during a remote call.
37
+ /// </summary>
38
+ /// <remarks>
39
+ /// The interface is designed to be as minimal as possible, allow for quick peeking of the event type (<c>id</c>)
40
+ /// and the cancellation status and provides a delegate for retrieving the event details themselves.
41
+ /// </remarks>
42
+ public interface IEventListener
43
+ {
44
+ Task Signal ( string id , CancellationToken token , GetEventData createMessage ) ;
45
+ CancellationToken Token { get ; }
46
+ System . Action Cancel { get ; }
47
+ }
48
+
49
+ public class Response : EventData
50
+ {
51
+ public Response ( ) : base ( )
52
+ {
53
+ }
54
+ }
55
+
56
+ public class Response < T > : Response
57
+ {
58
+ private Func < Task < T > > _resultDelegate ;
59
+ private Task < T > _resultValue ;
60
+
61
+ public Response ( T value ) : base ( ) => _resultValue = Task . FromResult ( value ) ;
62
+ public Response ( Func < T > value ) : base ( ) => _resultDelegate = ( ) => Task . FromResult ( value ( ) ) ;
63
+ public Response ( Func < Task < T > > value ) : base ( ) => _resultDelegate = value ;
64
+ public Task < T > Result => _resultValue ?? ( _resultValue = this . _resultDelegate ( ) ) ;
65
+ }
66
+
67
+
68
+ /// <summary>
69
+ /// The interface for sending an HTTP request across the wire.
70
+ /// </summary>
71
+ public interface ISendAsync
72
+ {
73
+ Task < HttpResponseMessage > SendAsync ( HttpRequestMessage request , IEventListener callback ) ;
74
+ }
75
+
76
+
77
+
78
+ [ TypeConverter ( typeof ( EventDataConverter ) ) ]
79
+ /// <remarks>
80
+ /// In PowerShell, we add on the EventDataConverter to support sending events between modules.
81
+ /// Obviously, this code would need to be duplcated on both modules.
82
+ /// This is preferable to sharing a common library, as versioning makes that problematic.
83
+ /// </remarks>
84
+ public partial class EventData : EventArgs
85
+ {
86
+ /// <summary>
87
+ /// The type of the event being signaled
88
+ /// </summary>
89
+ public string Id ;
90
+
91
+ /// <summary>
92
+ /// The user-ready message from the event.
93
+ /// </summary>
94
+ public string Message ;
95
+
96
+ /// <summary>
97
+ /// When the event is about a parameter, this is the parameter name.
98
+ /// Used in Validation Events
99
+ /// </summary>
100
+ public string Parameter ;
101
+
102
+ /// <summary>
103
+ /// This represents a numeric value associated with the event.
104
+ /// Use for progress-style events
105
+ /// </summary>
106
+ public double Value ;
107
+
108
+ /// <summary>
109
+ /// Any extended data for an event should be serialized to JSON and stored here.
110
+ /// </summary>
111
+ public string ExtendedData ;
112
+
113
+ /// <summary>
114
+ /// If the event triggers after the request message has been created, this will contain the Request Message (which in HTTP calls would be HttpRequestMessage)
115
+ ///
116
+ /// Typically you'd cast this to the expected type to use it:
117
+ /// <code>
118
+ /// if(eventData.RequestMessgae is HttpRequestMessage httpRequest)
119
+ /// {
120
+ /// httpRequest.Headers.Add("x-request-flavor", "vanilla");
121
+ /// }
122
+ /// </code>
123
+ /// </summary>
124
+ public object RequestMessage ;
125
+
126
+ /// <summary>
127
+ /// If the event triggers after the response is back, this will contain the Response Message (which in HTTP calls would be HttpResponseMessage)
128
+ ///
129
+ /// Typically you'd cast this to the expected type to use it:
130
+ /// <code>
131
+ /// if(eventData.ResponseMessage is HttpResponseMessage httpResponse){
132
+ /// var flavor = httpResponse.Headers.GetValue("x-request-flavor");
133
+ /// }
134
+ /// </code>
135
+ /// </summary>
136
+ public object ResponseMessage ;
137
+
138
+ /// <summary>
139
+ /// Cancellation method for this event.
140
+ ///
141
+ /// If the event consumer wishes to cancel the request that initiated this event, call <c>Cancel()</c>
142
+ /// </summary>
143
+ /// <remarks>
144
+ /// The original initiator of the request must provide the implementation of this.
145
+ /// </remarks>
146
+ public System . Action Cancel ;
147
+ }
148
+
149
+ /// <summary>
150
+ /// A PowerShell PSTypeConverter to adapt an <c>EventData</c> object that has been passed.
151
+ /// Usually used between modules.
152
+ /// </summary>
153
+ public class EventDataConverter : System . Management . Automation . PSTypeConverter
154
+ {
155
+ public override bool CanConvertTo ( object sourceValue , Type destinationType ) => false ;
156
+ public override object ConvertTo ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase ) => null ;
157
+ public override bool CanConvertFrom ( dynamic sourceValue , Type destinationType ) => destinationType == typeof ( EventData ) && CanConvertFrom ( sourceValue ) ;
158
+ public override object ConvertFrom ( dynamic sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase ) => ConvertFrom ( sourceValue ) ;
159
+
160
+ public static bool CanConvertFrom ( dynamic sv )
161
+ {
162
+ var result = true ;
163
+ try
164
+ {
165
+ // check if this has required parameters...
166
+ sv ? . Id ? . GetType ( ) ;
167
+ sv ? . Message ? . GetType ( ) ;
168
+ sv ? . Parameter ? . GetType ( ) ;
169
+ sv ? . Value ? . GetType ( ) ;
170
+ sv ? . RequestMessage ? . GetType ( ) ;
171
+ sv ? . ResponseMessage ? . GetType ( ) ;
172
+ sv ? . Cancel ? . GetType ( ) ;
173
+ }
174
+ catch
175
+ {
176
+ return false ;
177
+ }
178
+ return result ;
179
+ }
180
+
181
+ public static EventData ConvertFrom ( dynamic sv )
182
+ {
183
+ try
184
+ {
185
+ return new EventData
186
+ {
187
+ Id = sv . Id ,
188
+ Message = sv . Message ,
189
+ Parameter = sv . Parameter ,
190
+ Value = sv . Value ,
191
+ RequestMessage = sv . RequestMessage ,
192
+ ResponseMessage = sv . ResponseMessage ,
193
+ Cancel = sv . Cancel
194
+ } ;
195
+ }
196
+ catch
197
+ {
198
+ }
199
+ return null ;
200
+ }
201
+ }
202
+ public static class Events
203
+ {
204
+ public const string Log = nameof ( Log ) ;
205
+ public const string Validation = nameof ( Validation ) ;
206
+ public const string ValidationWarning = nameof ( ValidationWarning ) ;
207
+ public const string AfterValidation = nameof ( AfterValidation ) ;
208
+ public const string RequestCreated = nameof ( RequestCreated ) ;
209
+ public const string ResponseCreated = nameof ( ResponseCreated ) ;
210
+ public const string URLCreated = nameof ( URLCreated ) ;
211
+ public const string Finally = nameof ( Finally ) ;
212
+ public const string HeaderParametersAdded = nameof ( HeaderParametersAdded ) ;
213
+ public const string BodyContentSet = nameof ( BodyContentSet ) ;
214
+ public const string BeforeCall = nameof ( BeforeCall ) ;
215
+ public const string BeforeResponseDispatch = nameof ( BeforeResponseDispatch ) ;
216
+ public const string CmdletProcessRecordStart = nameof ( CmdletProcessRecordStart ) ;
217
+ public const string CmdletException = nameof ( CmdletException ) ;
218
+ public const string CmdletGetPipeline = nameof ( CmdletGetPipeline ) ;
219
+ public const string CmdletBeforeAPICall = nameof ( CmdletBeforeAPICall ) ;
220
+ public const string CmdletAfterAPICall = nameof ( CmdletAfterAPICall ) ;
221
+ public const string FollowingNextLink = nameof ( FollowingNextLink ) ;
222
+ public const string DelayBeforePolling = nameof ( DelayBeforePolling ) ;
223
+ public const string Polling = nameof ( Polling ) ;
224
+ }
225
+
226
+ }
0 commit comments