Skip to content

Commit a1a794e

Browse files
committed
pulled common stuff in
1 parent 378875e commit a1a794e

File tree

2 files changed

+521
-0
lines changed

2 files changed

+521
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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

Comments
 (0)