Skip to content

Commit a9da10f

Browse files
authored
Merge pull request #622 from finsharp/eventSignalling
Emit Signal method and delegate to provide hook into events for Non-Azure scenarios.
2 parents 5b06bef + f9c2b94 commit a9da10f

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

powershell/cmdlets/class.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,10 @@ export class CmdletClass extends Class {
10221022
// in azure mode, we signal the AzAccount module with every event that makes it here.
10231023
yield `await ${$this.state.project.serviceNamespace.moduleClass.declaration}.Instance.Signal(${id.value}, ${token.value}, ${messageData.value}, (i,t,m) => ((${ClientRuntime.IEventListener})this).Signal(i,t,()=> ${ClientRuntime.EventDataConverter}.ConvertFrom( m() ) as ${ClientRuntime.EventData} ), ${$this.invocationInfo.value}, this.ParameterSetName, ${$this.correlationId.value}, ${$this.processRecordId.value}, null );`;
10241024
yield If(`${token.value}.IsCancellationRequested`, Return());
1025+
} else {
1026+
// In Non-Azure Modes, emit the Signal method without coorelation and processrecordid
1027+
yield `await ${$this.state.project.serviceNamespace.moduleClass.declaration}.Instance.Signal(${id.value}, ${token.value}, ${messageData.value}, (i,t,m) => ((${ClientRuntime.IEventListener})this).Signal(i,t,()=> ${ClientRuntime.EventDataConverter}.ConvertFrom( m() ) as ${ClientRuntime.EventData} ), ${$this.invocationInfo.value}, this.ParameterSetName, null );`;
1028+
yield If(`${token.value}.IsCancellationRequested`, Return());
10251029
}
10261030
yield `WriteDebug($"{id}: {(messageData().Message ?? ${System.String.Empty})}");`;
10271031
// any handling of the signal on our side...

powershell/module/module-class.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import { Access, Alias, Class, ClassType, Constructor, dotnet, Field, LambdaMethod, LambdaProperty, LazyProperty, LiteralExpression, LocalVariable, MemberVariable, Method, Modifier, Namespace, Parameter, ParameterModifier, PartialMethod, Property, Return, Statements, StringExpression, System, TypeDeclaration, Using, valueOf, Variable } from '@azure-tools/codegen-csharp';
6+
import { Access, Alias, Class, ClassType, Constructor, dotnet, Field, LambdaMethod, LambdaProperty, LazyProperty, LiteralExpression, LocalVariable, MemberVariable, Method, Modifier, Namespace, Parameter, ParameterModifier, PartialMethod, Property, Return, Statements, StringExpression, System, TypeDeclaration, Using, valueOf, Variable, If } from '@azure-tools/codegen-csharp';
77

88
import { InvocationInfo, PSCredential, IArgumentCompleter, CompletionResult, CommandAst, CompletionResultType, } from '../internal/powershell-declarations';
99
import { State } from '../internal/state';
@@ -129,6 +129,21 @@ export class ModuleClass extends Class {
129129

130130
createInitAndPipeline(namespace: Namespace) {
131131
const $this = this;
132+
// Custom Event Listener without Azure Spefic concepts. (ProcessId and CorelationId)
133+
const customEventListenerFunc = System.Func(
134+
dotnet.String,
135+
System.Threading.CancellationToken,
136+
System.Func(System.EventArgs),
137+
this.incomingSignalFunc,
138+
InvocationInfo,
139+
dotnet.String,
140+
System.Exception,
141+
/* returns */ System.Threading.Tasks.Task());
142+
143+
const incomingSignalDelegate = namespace.add(new Alias('SignalDelegate', this.incomingSignalFunc));
144+
const eventListenerDelegate = namespace.add(new Alias('EventListenerDelegate', customEventListenerFunc));
145+
const EventListener = this.add(new Property('EventListener', eventListenerDelegate, { description: 'A delegate that gets called for each signalled event' }));
146+
132147
// non-azure init method
133148
this.initMethod.add(function* () {
134149
yield '// called at module init time...';
@@ -152,6 +167,22 @@ export class ModuleClass extends Class {
152167
});
153168

154169
this.add(new LambdaProperty('Name', dotnet.String, new StringExpression(this.state.project.moduleName), { description: 'The Name of this module ' }));
170+
171+
// Add Signal extensibility point
172+
const pSignal = new Parameter('signal', incomingSignalDelegate, { description: 'The callback for the event dispatcher ' });
173+
// Emit signal extensibility points that called EventListenerDelegate, allowing us to handle Signals emitted by the Pipeline in the Auth Module
174+
const signalImpl = this.add(new Method('Signal', System.Threading.Tasks.Task(), {
175+
parameters: [this.pId, this.pToken, this.pGetEventData, pSignal, this.pInvocationInfo, this.pParameterSetName, this.pException], async: Modifier.Async,
176+
description: 'Called to dispatch events to the common module listener',
177+
returnsDescription: `A <see cref="${System.Threading.Tasks.Task()}" /> that will be complete when handling of the event is completed.`
178+
}));
179+
180+
signalImpl.push(Using('NoSynchronizationContext', ''));
181+
signalImpl.add(function* () {
182+
// Emit call to EventListener after explicit null check.
183+
// Not using Null-Conditional operator causes Null Reference exception when Func<Task> is null, due to awaiting null Task.
184+
yield If(`${EventListener.value} != null`, `await ${EventListener.value}.Invoke(${$this.pId.value},${$this.pToken.value},${$this.pGetEventData.value}, ${pSignal.value}, ${$this.pInvocationInfo}, ${$this.pParameterSetName},${$this.pException});`)
185+
});
155186
}
156187

157188
createAzureInitAndPipeline(namespace: Namespace) {

0 commit comments

Comments
 (0)