Skip to content

Commit ca00838

Browse files
committed
Refactored interface
1 parent 5606f92 commit ca00838

File tree

8 files changed

+297
-211
lines changed

8 files changed

+297
-211
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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+
using System;
16+
using System.Threading;
17+
using System.Threading.Tasks;
18+
using System.Management.Automation;
19+
using System.Net.Http;
20+
using System.Collections.Generic;
21+
using Microsoft.WindowsAzure.Commands.Utilities.Common;
22+
23+
namespace Microsoft.Azure.Commands.Common
24+
{
25+
26+
using GetEventData = Func<EventArgs>;
27+
using SignalDelegate = Func<string, CancellationToken, Func<EventArgs>, Task>;
28+
using PipelineChangeDelegate = Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>;
29+
30+
/// <summary>
31+
/// Cheap and dirty implementation of module functions (does not have to look like this!)
32+
/// </summary>
33+
public class AzModule
34+
{
35+
ICommandRuntime _runtime;
36+
public AzModule(ICommandRuntime runtime)
37+
{
38+
_runtime = runtime;
39+
}
40+
41+
/// <summary>
42+
/// Called when the module is loading. Allows adding HTTP pipeline steps that will always be present.
43+
/// </summary>
44+
/// <param name="resourceId"><c>string</c>containing the expected resource id (ie, ARM).</param>
45+
/// <param name="moduleName"><c>string</c>containing the name of the module being loaded.</param>
46+
/// <param name="prependStep">a delegate which allows the module to prepend a step in the HTTP Pipeline</param>
47+
/// <param name="appendStep">a delegate which allows the module to append a step in the HTTP Pipeline</param>
48+
public void OnModuleLoad(string resourceId, string moduleName, PipelineChangeDelegate prependStep, PipelineChangeDelegate appendStep)
49+
{
50+
// this will be called once when the module starts up
51+
// the common module can prepend or append steps to the pipeline at this point.
52+
prependStep(UniqueId.Instance.SendAsync);
53+
54+
// appendStep( RetryHandler.SendAsync );
55+
}
56+
57+
/// <summary>
58+
/// The cmdlet will call this for every event during the pipeline.
59+
/// </summary>
60+
/// <param name="id">a <c>string</c> containing the name of the event being raised (well-known events are in <see cref="Microsoft.Azure.Commands.Common.Events"/></param>
61+
/// <param name="cancellationToken">a <c>CancellationToken</c> indicating if this request is being cancelled.</param>
62+
/// <param name="getEventData">a delegate to call to get the event data for this event</param>
63+
/// <param name="signal">a delegate to signal an event from the handler to the cmdlet.</param>
64+
/// <param name="invocationInfo">The <see cref="System.Management.Automation.InvocationInfo" /> from the cmdlet</param>
65+
/// <param name="parameterSetName">The <see cref="string" /> containing the name of the parameter set for this invocation (if available></param>
66+
/// <param name="correlationId">The <see cref="string" /> containing the correlation id for the cmdlet (if available)</param>
67+
/// <param name="processRecordId">The <see cref="string" /> containing the correlation id for the individual process record. (if available)</param>
68+
/// <param name="exception">The <see cref="System.Exception" /> that is being thrown (if available)</param>
69+
public async Task EventListener(string id, CancellationToken cancellationToken, GetEventData getEventData, SignalDelegate signal, System.Management.Automation.InvocationInfo invocationInfo, string parameterSetName, string correlationId, string processRecordId, System.Exception exception)
70+
{
71+
switch (id)
72+
{
73+
case Events.CmdletException:
74+
{
75+
var data = EventDataConverter.ConvertFrom(getEventData());
76+
await signal("Warning", cancellationToken, () => EventHelper.CreateLogEvent($"Received Exception with message '{data?.Message}'"));
77+
}
78+
79+
break;
80+
81+
case Events.BeforeCall:
82+
{
83+
var data = EventDataConverter.ConvertFrom(getEventData()); // also, we manually use our TypeConverter to return an appropriate type
84+
await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent($"BEFORE CALL The contents are '{data?.Id}' and '{data?.Message}'"));
85+
var request = data?.RequestMessage as HttpRequestMessage;
86+
if (request != null)
87+
{
88+
// alias/casting the request message to an HttpRequestMessage is necessary so that we can
89+
// support other protocols later on. (ie, JSONRPC, MQTT, GRPC ,AMPQ, Etc..)
90+
91+
// at this point, we can do with the request
92+
request.Headers.Add("x-ms-peekaboo", "true");
93+
await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(request)));
94+
}
95+
}
96+
break;
97+
98+
case Events.ResponseCreated:
99+
{
100+
// once we're sure we're handling the event, then we can retrieve the event data.
101+
// (this ensures that we're not doing any of the work unless we really care about the event. )
102+
var data = EventDataConverter.ConvertFrom(getEventData());
103+
await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent($"RESPONSE CREATED The contents are '{data?.Id}' and '{data?.Message}'"));
104+
var response = data?.ResponseMessage as HttpResponseMessage;
105+
if (response != null)
106+
{
107+
await signal("Debug", cancellationToken, () => EventHelper.CreateLogEvent(GeneralUtilities.GetLog(response)));
108+
}
109+
}
110+
break;
111+
112+
default:
113+
// By default, just print out event details
114+
getEventData.Print(signal, cancellationToken, "Verbose", id);
115+
break;
116+
}
117+
}
118+
}
119+
120+
}

src/Accounts/Accounts/CommonModule/ContextAdapter.cs

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,25 +25,57 @@
2525

2626
namespace Microsoft.Azure.Commands.Common
2727
{
28-
using NextDelegate = Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>;
29-
using SignalDelegate = Func<string, CancellationToken, Func<EventArgs>, Task>;
30-
using PipelineChangeDelegate = Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>;
28+
using NextDelegate = Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>;
29+
using SignalDelegate = Func<string, CancellationToken, Func<EventArgs>, Task>;
30+
using PipelineChangeDelegate = Action<Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Func<HttpRequestMessage, CancellationToken, Action, Func<string, CancellationToken, Func<EventArgs>, Task>, Task<HttpResponseMessage>>, Task<HttpResponseMessage>>>;
3131

32-
internal class ContextAdapter
32+
internal class ContextAdapter
3333
{
3434
IProfileProvider _provider = AzureRmProfileProvider.Instance;
3535
IAuthenticationFactory _authenticator = AzureSession.Instance.AuthenticationFactory;
3636

3737
internal static ContextAdapter Instance => new ContextAdapter();
3838

39-
public void OnNewRequest(Dictionary<string, object> boundParameters, PipelineChangeDelegate prependStep, PipelineChangeDelegate appendStep)
39+
/// <summary>
40+
/// Implementation of the OnNewRequest Event
41+
///
42+
/// The cmdlet will call this when a new request is being created.
43+
/// </summary>
44+
/// <param name="invocationInfo">The <see cref="System.Management.Automation.InvocationInfo" /> from the cmdlet</param>
45+
/// <param name="correlationId">The <see cref="string" /> containing the correlation id for the cmdlet (if available)</param>
46+
/// <param name="processRecordId">The <see cref="string" /> containing the correlation id for the individual process record. (if available)</param>
47+
/// <param name="prependStep">a delegate which allows the module to prepend a step in the HTTP Pipeline</param>
48+
/// <param name="appendStep">a delegate which allows the module to append a step in the HTTP Pipeline</param>
49+
public void OnNewRequest(System.Management.Automation.InvocationInfo invocationInfo, string correlationId, string processRecordId, PipelineChangeDelegate prependStep, PipelineChangeDelegate appendStep)
4050
{
41-
appendStep(this.SendHandler(GetDefaultContext(_provider, boundParameters), AzureEnvironment.Endpoint.ResourceManager));
51+
appendStep(this.SendHandler(GetDefaultContext(_provider, invocationInfo), AzureEnvironment.Endpoint.ResourceManager));
4252
}
4353

44-
public object GetParameterValue(string resourceId, string moduleName, Dictionary<string, object> boundParameters, string name)
54+
/// <summary>
55+
/// Called for well-known parameters that require argument completers
56+
/// </summary>
57+
/// <param name="completerName">string - the type of completer requested (Resource, Location)</param>
58+
/// <param name="invocationInfo">The <see cref="System.Management.Automation.InvocationInfo" /> from the cmdlet</param>
59+
/// <param name="correlationId">The <see cref="string" /> containing the correlation id for the cmdlet (if available)</param>
60+
/// <param name="resourceTypes">An <see cref="System.String[]"/> containing resource (or resource types) being completed </param >
61+
/// <param name="parentResourceParameterNames"> An <see cref="System.String[]"/> containing list of parent resource parameter names (if applicable)</param >
62+
/// <returns>A <see cref="System.String[]"/> containing the valid options for the completer.</returns>
63+
public string[] CompleteArgument(string completerName, System.Management.Automation.InvocationInfo invocationInfo, string correlationId, string[] resourceTypes, string[] parentResourceParameterNames)
4564
{
46-
var defaultContext = GetDefaultContext(_provider, boundParameters);
65+
return new string[] { "" };
66+
}
67+
68+
/// <summary>
69+
/// The cmdlet will call this when it is trying to fill in a parameter value that it needs
70+
/// </summary>
71+
/// <param name="resourceId"><c>string</c>containing the expected resource id (ie, ARM).</param>
72+
/// <param name="moduleName"><c>string</c>containing the name of the module being loaded.</param>
73+
/// <param name="invocationInfo">The <see cref="System.Management.Automation.InvocationInfo" /> from the cmdlet</param>
74+
/// <param name="correlationId">The <see cref="string" /> containing the correlation id for the cmdlet</param>
75+
/// <param name="name">The <see cref="string" /> parameter name being asked for</param>
76+
public object GetParameterValue(string resourceId, string moduleName, System.Management.Automation.InvocationInfo invocationInfo, string correlationId, string name)
77+
{
78+
var defaultContext = GetDefaultContext(_provider, invocationInfo);
4779
var endpoint = GetDefaultEndpoint(defaultContext, AzureEnvironment.Endpoint.ResourceManager);
4880
switch (name)
4981
{
@@ -58,14 +90,14 @@ public object GetParameterValue(string resourceId, string moduleName, Dictionary
5890
return string.Empty;
5991
}
6092

61-
static IAzureContext GetDefaultContext(IProfileProvider provider, Dictionary<string, object> boundParameters)
93+
static IAzureContext GetDefaultContext(IProfileProvider provider, System.Management.Automation.InvocationInfo invocationInfo)
6294
{
6395
IAzureContextContainer context;
6496
var contextConverter = new AzureContextConverter();
65-
if (boundParameters.ContainsKey("DefaultContext")
66-
&& contextConverter.CanConvertFrom(boundParameters["DefaultContext"], typeof(IAzureContextContainer)))
97+
if (invocationInfo.BoundParameters.ContainsKey("DefaultContext")
98+
&& contextConverter.CanConvertFrom(invocationInfo.BoundParameters["DefaultContext"], typeof(IAzureContextContainer)))
6799
{
68-
context = contextConverter.ConvertFrom(boundParameters["DefaultContext"], typeof(IAzureContextContainer), CultureInfo.InvariantCulture, true) as IAzureContextContainer;
100+
context = contextConverter.ConvertFrom(invocationInfo.BoundParameters["DefaultContext"], typeof(IAzureContextContainer), CultureInfo.InvariantCulture, true) as IAzureContextContainer;
69101
}
70102
else
71103
{

src/Accounts/Accounts/CommonModule/EventData.cs

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,12 @@
2323

2424
namespace Microsoft.Azure.Commands.Common
2525
{
26+
using EventListenerDelegate = Func<EventData, Task>;
27+
using GetParameterDelegate = Func<string, System.Management.Automation.InvocationInfo, string, object>;
28+
using SendAsyncStep = Func<HttpRequestMessage, IEventListener, ISendAsync, Task<HttpResponseMessage>>;
29+
using PipelineChangeDelegate = Action<EventData>;
2630

27-
28-
using EventListenerDelegate = Func<EventData, Task>;
29-
using GetParameterDelegate = Func<string, Dictionary<string, object>, string, object>;
30-
using SendAsyncStep = Func<HttpRequestMessage, IEventListener, ISendAsync, Task<HttpResponseMessage>>;
31-
using PipelineChangeDelegate = Action<EventData>;
32-
33-
34-
35-
[TypeConverter(typeof(EventDataConverter))]
31+
[TypeConverter(typeof(EventDataConverter))]
3632
/// <remarks>
3733
/// In PowerShell, we add on the EventDataConverter to support sending events between modules.
3834
/// Obviously, this code would need to be duplcated on both modules.
@@ -92,38 +88,6 @@ public partial class EventData : EventArgs
9288
/// </summary>
9389
public object ResponseMessage;
9490

95-
/// <summary>
96-
/// The name of the cmdlet that is being executed
97-
/// </summary>
98-
public string CmdletName;
99-
100-
/// <summary>
101-
/// Correlation Id for cmdlet invocation
102-
/// </summary>
103-
public string CmdletInvocationId;
104-
105-
/// <summary>
106-
///
107-
/// </summary>
108-
public string ProcessRecordId;
109-
110-
/// <summary>
111-
///
112-
/// </summary>
113-
public string ParameterSet;
114-
115-
/// <summary>
116-
///
117-
/// </summary>
118-
public string RequestCorrelationId;
119-
120-
/// <summary>
121-
/// The 'this.MyInvocation.BoundParameters' from the cmdlet
122-
/// </summary>
123-
public System.Collections.Generic.IDictionary<string,object> BoundParamters;
124-
125-
public System.Exception Exception;
126-
12791
/// <summary>
12892
/// Cancellation method for this event.
12993
///

0 commit comments

Comments
 (0)