diff --git a/azure-functions-powershell-worker.sln b/azure-functions-powershell-worker.sln
index 1b8c5d61..06985175 100644
--- a/azure-functions-powershell-worker.sln
+++ b/azure-functions-powershell-worker.sln
@@ -5,11 +5,11 @@ VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8C758288-3909-4CE1-972D-1BE966628D6C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Functions.PowerShell.Worker", "src\Azure.Functions.PowerShell.Worker\Azure.Functions.PowerShell.Worker.csproj", "{939262BA-4823-405E-81CD-436C0B77D524}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Functions.PowerShell.Worker", "src\Azure.Functions.PowerShell.Worker.csproj", "{939262BA-4823-405E-81CD-436C0B77D524}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{12092936-4F2A-4B40-9AF2-56C840D44FEA}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Functions.PowerShell.Worker.Test", "test\Azure.Functions.PowerShell.Worker.Test\Azure.Functions.PowerShell.Worker.Test.csproj", "{535C8DA3-479D-42BF-B1AF-5B03ECAF67A4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Functions.PowerShell.Worker.Test", "test\Azure.Functions.PowerShell.Worker.Test.csproj", "{535C8DA3-479D-42BF-B1AF-5B03ECAF67A4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/src/Azure.Functions.PowerShell.Worker/Properties/AssemblyInfo.cs b/src/AssemblyInfo.cs
similarity index 99%
rename from src/Azure.Functions.PowerShell.Worker/Properties/AssemblyInfo.cs
rename to src/AssemblyInfo.cs
index dd8b6b66..8b0dcdf5 100644
--- a/src/Azure.Functions.PowerShell.Worker/Properties/AssemblyInfo.cs
+++ b/src/AssemblyInfo.cs
@@ -6,3 +6,4 @@
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("Azure.Functions.PowerShell.Worker.Test")]
+
diff --git a/src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.csproj b/src/Azure.Functions.PowerShell.Worker.csproj
similarity index 93%
rename from src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.csproj
rename to src/Azure.Functions.PowerShell.Worker.csproj
index 06608836..8773f1fc 100644
--- a/src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.csproj
+++ b/src/Azure.Functions.PowerShell.Worker.csproj
@@ -14,6 +14,7 @@
true
en-US
+
@@ -27,7 +28,8 @@
PreserveNewest
-
+
+ Modules\%(RecursiveDir)\%(FileName)%(Extension)
PreserveNewest
diff --git a/src/Azure.Functions.PowerShell.Worker/Requests/HandleFunctionLoadRequest.cs b/src/Azure.Functions.PowerShell.Worker/Requests/HandleFunctionLoadRequest.cs
deleted file mode 100644
index b5a45f29..00000000
--- a/src/Azure.Functions.PowerShell.Worker/Requests/HandleFunctionLoadRequest.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using System;
-
-using Microsoft.Azure.Functions.PowerShellWorker.Utility;
-using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
-
-namespace Microsoft.Azure.Functions.PowerShellWorker.Requests
-{
- using System.Management.Automation;
- using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
-
- internal static class HandleFunctionLoadRequest
- {
- public static StreamingMessage Invoke(
- PowerShellManager powerShellManager,
- FunctionLoader functionLoader,
- StreamingMessage request,
- RpcLogger logger)
- {
- FunctionLoadRequest functionLoadRequest = request.FunctionLoadRequest;
-
- // Assume success unless something bad happens
- StatusResult status = new StatusResult()
- {
- Status = StatusResult.Types.Status.Success
- };
-
- // Try to load the functions
- try
- {
- functionLoader.Load(functionLoadRequest.FunctionId, functionLoadRequest.Metadata);
- }
- catch (Exception e)
- {
- status.Status = StatusResult.Types.Status.Failure;
- status.Exception = e.ToRpcException();
- }
-
- return new StreamingMessage()
- {
- RequestId = request.RequestId,
- FunctionLoadResponse = new FunctionLoadResponse()
- {
- FunctionId = functionLoadRequest.FunctionId,
- Result = status
- }
- };
- }
- }
-}
diff --git a/src/Azure.Functions.PowerShell.Worker/Requests/HandleInvocationRequest.cs b/src/Azure.Functions.PowerShell.Worker/Requests/HandleInvocationRequest.cs
deleted file mode 100644
index 8f3a15ab..00000000
--- a/src/Azure.Functions.PowerShell.Worker/Requests/HandleInvocationRequest.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-using Microsoft.Azure.Functions.PowerShellWorker.Utility;
-using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
-using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
-
-namespace Microsoft.Azure.Functions.PowerShellWorker.Requests
-{
- internal static class HandleInvocationRequest
- {
- public static StreamingMessage Invoke(
- PowerShellManager powerShellManager,
- FunctionLoader functionLoader,
- StreamingMessage request,
- RpcLogger logger)
- {
- InvocationRequest invocationRequest = request.InvocationRequest;
-
- // Set the RequestId and InvocationId for logging purposes
- logger.SetContext(request.RequestId, invocationRequest.InvocationId);
-
- // Load information about the function
- var functionInfo = functionLoader.GetInfo(invocationRequest.FunctionId);
- (string scriptPath, string entryPoint) = functionLoader.GetFunc(invocationRequest.FunctionId);
-
- // Bundle all TriggerMetadata into Hashtable to send down to PowerShell
- Hashtable triggerMetadata = new Hashtable();
- foreach (var dataItem in invocationRequest.TriggerMetadata)
- {
- triggerMetadata.Add(dataItem.Key, dataItem.Value.ToObject());
- }
-
- // Assume success unless something bad happens
- var status = new StatusResult() { Status = StatusResult.Types.Status.Success };
- var response = new StreamingMessage()
- {
- RequestId = request.RequestId,
- InvocationResponse = new InvocationResponse()
- {
- InvocationId = invocationRequest.InvocationId,
- Result = status
- }
- };
-
- // Invoke powershell logic and return hashtable of out binding data
- Hashtable result = null;
- try
- {
- result = powerShellManager
- .InvokeFunctionAndSetGlobalReturn(scriptPath, entryPoint, triggerMetadata, invocationRequest.InputData)
- .ReturnBindingHashtable(functionInfo.OutputBindings);
- }
- catch (Exception e)
- {
- status.Status = StatusResult.Types.Status.Failure;
- status.Exception = e.ToRpcException();
- return response;
- }
-
- // Set out binding data and return response to be sent back to host
- foreach (KeyValuePair binding in functionInfo.OutputBindings)
- {
- ParameterBinding paramBinding = new ParameterBinding()
- {
- Name = binding.Key,
- Data = result[binding.Key].ToTypedData()
- };
-
- response.InvocationResponse.OutputData.Add(paramBinding);
-
- // if one of the bindings is $return we need to also set the ReturnValue
- if(binding.Key == "$return")
- {
- response.InvocationResponse.ReturnValue = paramBinding.Data;
- }
- }
-
- return response;
- }
- }
-}
diff --git a/src/Azure.Functions.PowerShell.Worker/Requests/HandleWorkerInitRequest.cs b/src/Azure.Functions.PowerShell.Worker/Requests/HandleWorkerInitRequest.cs
deleted file mode 100644
index 28402d69..00000000
--- a/src/Azure.Functions.PowerShell.Worker/Requests/HandleWorkerInitRequest.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
-using Microsoft.Azure.Functions.PowerShellWorker.Utility;
-using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
-
-namespace Microsoft.Azure.Functions.PowerShellWorker.Requests
-{
- internal static class HandleWorkerInitRequest
- {
- public static StreamingMessage Invoke(
- PowerShellManager powerShellManager,
- FunctionLoader functionLoader,
- StreamingMessage request,
- RpcLogger logger)
- {
- return new StreamingMessage()
- {
- RequestId = request.RequestId,
- WorkerInitResponse = new WorkerInitResponse()
- {
- Result = new StatusResult()
- {
- Status = StatusResult.Types.Status.Success
- }
- }
- };
- }
- }
-}
diff --git a/src/Azure.Functions.PowerShell.Worker/Worker.cs b/src/Azure.Functions.PowerShell.Worker/Worker.cs
deleted file mode 100644
index 75e92e5b..00000000
--- a/src/Azure.Functions.PowerShell.Worker/Worker.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-//
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-//
-
-using System;
-using System.Threading.Tasks;
-
-using CommandLine;
-using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
-using Microsoft.Azure.Functions.PowerShellWorker.Messaging;
-using Microsoft.Azure.Functions.PowerShellWorker.Requests;
-using Microsoft.Azure.Functions.PowerShellWorker.Utility;
-using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
-
-namespace Microsoft.Azure.Functions.PowerShellWorker
-{
- ///
- /// The PowerShell language worker for Azure Function
- ///
- public static class Worker
- {
- static readonly FunctionLoader s_functionLoader = new FunctionLoader();
- static FunctionMessagingClient s_client;
- static RpcLogger s_logger;
- static PowerShellManager s_powershellManager;
-
- ///
- /// Entry point of the language worker.
- ///
- public async static Task Main(string[] args)
- {
- WorkerArguments arguments = null;
- Parser.Default.ParseArguments(args)
- .WithParsed(ops => arguments = ops)
- .WithNotParsed(err => Environment.Exit(1));
-
- // Initialize Rpc client, logger, and PowerShellManager
- s_client = new FunctionMessagingClient(arguments.Host, arguments.Port);
- s_logger = new RpcLogger(s_client);
- s_powershellManager = PowerShellManager.Create(s_logger);
-
- // Send StartStream message
- var streamingMessage = new StreamingMessage() {
- RequestId = arguments.RequestId,
- StartStream = new StartStream() { WorkerId = arguments.WorkerId }
- };
-
- await s_client.WriteAsync(streamingMessage);
- await ProcessEvent();
- }
-
- static async Task ProcessEvent()
- {
- using (s_client)
- {
- while (await s_client.MoveNext())
- {
- var message = s_client.GetCurrentMessage();
- StreamingMessage response;
- switch (message.ContentCase)
- {
- case StreamingMessage.ContentOneofCase.WorkerInitRequest:
- response = HandleWorkerInitRequest.Invoke(
- s_powershellManager,
- s_functionLoader,
- message,
- s_logger);
- break;
-
- case StreamingMessage.ContentOneofCase.FunctionLoadRequest:
- response = HandleFunctionLoadRequest.Invoke(
- s_powershellManager,
- s_functionLoader,
- message,
- s_logger);
- break;
-
- case StreamingMessage.ContentOneofCase.InvocationRequest:
- response = HandleInvocationRequest.Invoke(
- s_powershellManager,
- s_functionLoader,
- message,
- s_logger);
- break;
-
- default:
- throw new InvalidOperationException($"Not supportted message type: {message.ContentCase}");
- }
-
- await s_client.WriteAsync(response);
- }
- }
- }
- }
-
- internal class WorkerArguments
- {
- [Option("host", Required = true, HelpText = "IP Address used to connect to the Host via gRPC.")]
- public string Host { get; set; }
-
- [Option("port", Required = true, HelpText = "Port used to connect to the Host via gRPC.")]
- public int Port { get; set; }
-
- [Option("workerId", Required = true, HelpText = "Worker ID assigned to this language worker.")]
- public string WorkerId { get; set; }
-
- [Option("requestId", Required = true, HelpText = "Request ID used for gRPC communication with the Host.")]
- public string RequestId { get; set; }
-
- [Option("grpcMaxMessageLength", Required = true, HelpText = "gRPC Maximum message size.")]
- public int MaxMessageLength { get; set; }
- }
-}
diff --git a/src/Azure.Functions.PowerShell.Worker/Function/FunctionInfo.cs b/src/Function/FunctionInfo.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Function/FunctionInfo.cs
rename to src/Function/FunctionInfo.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Function/FunctionLoader.cs b/src/Function/FunctionLoader.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Function/FunctionLoader.cs
rename to src/Function/FunctionLoader.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Http/HttpRequestContext.cs b/src/Http/HttpRequestContext.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Http/HttpRequestContext.cs
rename to src/Http/HttpRequestContext.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Http/HttpResponseContext.cs b/src/Http/HttpResponseContext.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Http/HttpResponseContext.cs
rename to src/Http/HttpResponseContext.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Messaging/FunctionRpc.cs b/src/Messaging/FunctionRpc.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Messaging/FunctionRpc.cs
rename to src/Messaging/FunctionRpc.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Messaging/FunctionRpcGrpc.cs b/src/Messaging/FunctionRpcGrpc.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Messaging/FunctionRpcGrpc.cs
rename to src/Messaging/FunctionRpcGrpc.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Messaging/FunctionMessagingClient.cs b/src/Messaging/MessagingStream.cs
similarity index 83%
rename from src/Azure.Functions.PowerShell.Worker/Messaging/FunctionMessagingClient.cs
rename to src/Messaging/MessagingStream.cs
index c99dfe7d..23b1fa24 100644
--- a/src/Azure.Functions.PowerShell.Worker/Messaging/FunctionMessagingClient.cs
+++ b/src/Messaging/MessagingStream.cs
@@ -12,13 +12,13 @@
namespace Microsoft.Azure.Functions.PowerShellWorker.Messaging
{
- internal class FunctionMessagingClient : IDisposable
+ internal class MessagingStream : IDisposable
{
- SemaphoreSlim _writeStreamHandle = new SemaphoreSlim(1, 1);
- AsyncDuplexStreamingCall _call;
- public bool isDisposed;
+ private SemaphoreSlim _writeStreamHandle = new SemaphoreSlim(1, 1);
+ private AsyncDuplexStreamingCall _call;
+ private bool isDisposed;
- public FunctionMessagingClient(string host, int port)
+ public MessagingStream(string host, int port)
{
Channel channel = new Channel(host, port, ChannelCredentials.Insecure);
_call = new FunctionRpc.FunctionRpcClient(channel).EventStream();
@@ -56,4 +56,4 @@ public async Task WriteAsync(StreamingMessage message)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Azure.Functions.PowerShell.Worker/Messaging/RpcLogger.cs b/src/Messaging/RpcLogger.cs
similarity index 88%
rename from src/Azure.Functions.PowerShell.Worker/Messaging/RpcLogger.cs
rename to src/Messaging/RpcLogger.cs
index 12ea9a83..a790afb2 100644
--- a/src/Azure.Functions.PowerShell.Worker/Messaging/RpcLogger.cs
+++ b/src/Messaging/RpcLogger.cs
@@ -13,13 +13,13 @@ namespace Microsoft.Azure.Functions.PowerShellWorker.Utility
{
internal class RpcLogger : ILogger
{
- FunctionMessagingClient _client;
- string _invocationId = "";
- string _requestId = "";
+ private MessagingStream _msgStream;
+ private string _invocationId = "";
+ private string _requestId = "";
- public RpcLogger(FunctionMessagingClient client)
+ public RpcLogger(MessagingStream msgStream)
{
- _client = client;
+ _msgStream = msgStream;
}
public IDisposable BeginScope(TState state) =>
@@ -51,7 +51,7 @@ public bool IsEnabled(LogLevel logLevel) =>
public async void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
{
- if (_client != null)
+ if (_msgStream != null)
{
var logMessage = new StreamingMessage
{
@@ -65,7 +65,7 @@ public async void Log(LogLevel logLevel, EventId eventId, TState state,
}
};
- await _client.WriteAsync(logMessage);
+ await _msgStream.WriteAsync(logMessage);
}
}
diff --git a/src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psd1 b/src/Modules/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psd1
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psd1
rename to src/Modules/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psd1
diff --git a/src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psm1 b/src/Modules/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psm1
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psm1
rename to src/Modules/Azure.Functions.PowerShell.Worker.Module/Azure.Functions.PowerShell.Worker.Module.psm1
diff --git a/src/Azure.Functions.PowerShell.Worker/PowerShell/PowerShellManager.cs b/src/PowerShell/PowerShellManager.cs
similarity index 98%
rename from src/Azure.Functions.PowerShell.Worker/PowerShell/PowerShellManager.cs
rename to src/PowerShell/PowerShellManager.cs
index f4d005a2..53a7f514 100644
--- a/src/Azure.Functions.PowerShell.Worker/PowerShell/PowerShellManager.cs
+++ b/src/PowerShell/PowerShellManager.cs
@@ -46,7 +46,7 @@ internal class PowerShellManager
PowerShellManager(RpcLogger logger)
{
- _pwsh = System.Management.Automation.PowerShell.Create(InitialSessionState.CreateDefault());
+ _pwsh = PowerShell.Create(InitialSessionState.CreateDefault());
_logger = logger;
// Setup Stream event listeners
diff --git a/src/Azure.Functions.PowerShell.Worker/PowerShell/StreamHandler.cs b/src/PowerShell/StreamHandler.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/PowerShell/StreamHandler.cs
rename to src/PowerShell/StreamHandler.cs
diff --git a/src/RequestProcessor.cs b/src/RequestProcessor.cs
new file mode 100644
index 00000000..ab3a5de9
--- /dev/null
+++ b/src/RequestProcessor.cs
@@ -0,0 +1,177 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Microsoft.Azure.Functions.PowerShellWorker.Messaging;
+using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
+using Microsoft.Azure.Functions.PowerShellWorker.Utility;
+using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
+
+namespace Microsoft.Azure.Functions.PowerShellWorker
+{
+ internal class RequestProcessor
+ {
+ private readonly FunctionLoader _functionLoader;
+ private readonly RpcLogger _logger;
+ private readonly MessagingStream _msgStream;
+ private readonly PowerShellManager _powerShellManager;
+
+ internal RequestProcessor(MessagingStream msgStream)
+ {
+ _msgStream = msgStream;
+ _logger = new RpcLogger(msgStream);
+ _powerShellManager = PowerShellManager.Create(_logger);
+ _functionLoader = new FunctionLoader();
+ }
+
+ internal async Task ProcessRequestLoop()
+ {
+ using (_msgStream)
+ {
+ StreamingMessage request, response;
+ while (await _msgStream.MoveNext())
+ {
+ request = _msgStream.GetCurrentMessage();
+ switch (request.ContentCase)
+ {
+ case StreamingMessage.ContentOneofCase.WorkerInitRequest:
+ response = ProcessWorkerInitRequest(request);
+ break;
+
+ case StreamingMessage.ContentOneofCase.FunctionLoadRequest:
+ response = ProcessFunctionLoadRequest(request);
+ break;
+
+ case StreamingMessage.ContentOneofCase.InvocationRequest:
+ response = ProcessInvocationRequest(request);
+ break;
+
+ default:
+ throw new InvalidOperationException($"Not supportted message type: {request.ContentCase}");
+ }
+
+ await _msgStream.WriteAsync(response);
+ }
+ }
+ }
+
+ internal StreamingMessage ProcessWorkerInitRequest(StreamingMessage request)
+ {
+ return new StreamingMessage()
+ {
+ RequestId = request.RequestId,
+ WorkerInitResponse = new WorkerInitResponse()
+ {
+ Result = new StatusResult()
+ {
+ Status = StatusResult.Types.Status.Success
+ }
+ }
+ };
+ }
+
+ internal StreamingMessage ProcessFunctionLoadRequest(StreamingMessage request)
+ {
+ FunctionLoadRequest functionLoadRequest = request.FunctionLoadRequest;
+
+ // Assume success unless something bad happens
+ StatusResult status = new StatusResult()
+ {
+ Status = StatusResult.Types.Status.Success
+ };
+
+ // Try to load the functions
+ try
+ {
+ _functionLoader.Load(functionLoadRequest.FunctionId, functionLoadRequest.Metadata);
+ }
+ catch (Exception e)
+ {
+ status.Status = StatusResult.Types.Status.Failure;
+ status.Exception = e.ToRpcException();
+ }
+
+ return new StreamingMessage()
+ {
+ RequestId = request.RequestId,
+ FunctionLoadResponse = new FunctionLoadResponse()
+ {
+ FunctionId = functionLoadRequest.FunctionId,
+ Result = status
+ }
+ };
+ }
+
+ internal StreamingMessage ProcessInvocationRequest(StreamingMessage request)
+ {
+ InvocationRequest invocationRequest = request.InvocationRequest;
+
+ // Set the RequestId and InvocationId for logging purposes
+ _logger.SetContext(request.RequestId, invocationRequest.InvocationId);
+
+ // Load information about the function
+ var functionInfo = _functionLoader.GetInfo(invocationRequest.FunctionId);
+ (string scriptPath, string entryPoint) = _functionLoader.GetFunc(invocationRequest.FunctionId);
+
+ // Bundle all TriggerMetadata into Hashtable to send down to PowerShell
+ Hashtable triggerMetadata = new Hashtable();
+ foreach (var dataItem in invocationRequest.TriggerMetadata)
+ {
+ triggerMetadata.Add(dataItem.Key, dataItem.Value.ToObject());
+ }
+
+ // Assume success unless something bad happens
+ var status = new StatusResult() { Status = StatusResult.Types.Status.Success };
+ var response = new StreamingMessage()
+ {
+ RequestId = request.RequestId,
+ InvocationResponse = new InvocationResponse()
+ {
+ InvocationId = invocationRequest.InvocationId,
+ Result = status
+ }
+ };
+
+ // Invoke powershell logic and return hashtable of out binding data
+ Hashtable result = null;
+ try
+ {
+ result = _powerShellManager
+ .InvokeFunctionAndSetGlobalReturn(scriptPath, entryPoint, triggerMetadata, invocationRequest.InputData)
+ .ReturnBindingHashtable(functionInfo.OutputBindings);
+ }
+ catch (Exception e)
+ {
+ status.Status = StatusResult.Types.Status.Failure;
+ status.Exception = e.ToRpcException();
+ return response;
+ }
+
+ // Set out binding data and return response to be sent back to host
+ foreach (KeyValuePair binding in functionInfo.OutputBindings)
+ {
+ ParameterBinding paramBinding = new ParameterBinding()
+ {
+ Name = binding.Key,
+ Data = result[binding.Key].ToTypedData()
+ };
+
+ response.InvocationResponse.OutputData.Add(paramBinding);
+
+ // if one of the bindings is $return we need to also set the ReturnValue
+ if(binding.Key == "$return")
+ {
+ response.InvocationResponse.ReturnValue = paramBinding.Data;
+ }
+ }
+
+ return response;
+ }
+ }
+}
diff --git a/src/Azure.Functions.PowerShell.Worker/Utility/ExecutionTimer.cs b/src/Utility/ExecutionTimer.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Utility/ExecutionTimer.cs
rename to src/Utility/ExecutionTimer.cs
diff --git a/src/Azure.Functions.PowerShell.Worker/Utility/TypeExtensions.cs b/src/Utility/TypeExtensions.cs
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/Utility/TypeExtensions.cs
rename to src/Utility/TypeExtensions.cs
diff --git a/src/Worker.cs b/src/Worker.cs
new file mode 100644
index 00000000..15d4d7cf
--- /dev/null
+++ b/src/Worker.cs
@@ -0,0 +1,63 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Threading.Tasks;
+
+using CommandLine;
+using Microsoft.Azure.Functions.PowerShellWorker.PowerShell;
+using Microsoft.Azure.Functions.PowerShellWorker.Messaging;
+using Microsoft.Azure.Functions.PowerShellWorker.Utility;
+using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
+
+namespace Microsoft.Azure.Functions.PowerShellWorker
+{
+ ///
+ /// The PowerShell language worker for Azure Function
+ ///
+ public static class Worker
+ {
+ ///
+ /// Entry point of the language worker.
+ ///
+ public async static Task Main(string[] args)
+ {
+ WorkerArguments arguments = null;
+ Parser.Default.ParseArguments(args)
+ .WithParsed(ops => arguments = ops)
+ .WithNotParsed(err => Environment.Exit(1));
+
+ var msgStream = new MessagingStream(arguments.Host, arguments.Port);
+ var requestProcessor = new RequestProcessor(msgStream);
+
+ // Send StartStream message
+ var startedMessage = new StreamingMessage() {
+ RequestId = arguments.RequestId,
+ StartStream = new StartStream() { WorkerId = arguments.WorkerId }
+ };
+
+ await msgStream.WriteAsync(startedMessage);
+ await requestProcessor.ProcessRequestLoop();
+ }
+ }
+
+ internal class WorkerArguments
+ {
+ [Option("host", Required = true, HelpText = "IP Address used to connect to the Host via gRPC.")]
+ public string Host { get; set; }
+
+ [Option("port", Required = true, HelpText = "Port used to connect to the Host via gRPC.")]
+ public int Port { get; set; }
+
+ [Option("workerId", Required = true, HelpText = "Worker ID assigned to this language worker.")]
+ public string WorkerId { get; set; }
+
+ [Option("requestId", Required = true, HelpText = "Request ID used for gRPC communication with the Host.")]
+ public string RequestId { get; set; }
+
+ [Option("grpcMaxMessageLength", Required = true, HelpText = "gRPC Maximum message size.")]
+ public int MaxMessageLength { get; set; }
+ }
+}
diff --git a/src/Azure.Functions.PowerShell.Worker/worker.config.json b/src/worker.config.json
similarity index 100%
rename from src/Azure.Functions.PowerShell.Worker/worker.config.json
rename to src/worker.config.json
diff --git a/test/Azure.Functions.PowerShell.Worker.Test/Azure.Functions.PowerShell.Worker.Test.csproj b/test/Azure.Functions.PowerShell.Worker.Test.csproj
similarity index 83%
rename from test/Azure.Functions.PowerShell.Worker.Test/Azure.Functions.PowerShell.Worker.Test.csproj
rename to test/Azure.Functions.PowerShell.Worker.Test.csproj
index 79079dd5..2167776e 100644
--- a/test/Azure.Functions.PowerShell.Worker.Test/Azure.Functions.PowerShell.Worker.Test.csproj
+++ b/test/Azure.Functions.PowerShell.Worker.Test.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/test/Azure.Functions.PowerShell.Worker.Test/Function/FunctionLoaderTests.cs b/test/Function/FunctionLoaderTests.cs
similarity index 100%
rename from test/Azure.Functions.PowerShell.Worker.Test/Function/FunctionLoaderTests.cs
rename to test/Function/FunctionLoaderTests.cs
diff --git a/test/Azure.Functions.PowerShell.Worker.Test/Requests/HandleWorkerInitRequestTests.cs b/test/Requests/HandleWorkerInitRequestTests.cs
similarity index 80%
rename from test/Azure.Functions.PowerShell.Worker.Test/Requests/HandleWorkerInitRequestTests.cs
rename to test/Requests/HandleWorkerInitRequestTests.cs
index afd51f8c..36fd8873 100644
--- a/test/Azure.Functions.PowerShell.Worker.Test/Requests/HandleWorkerInitRequestTests.cs
+++ b/test/Requests/HandleWorkerInitRequestTests.cs
@@ -3,14 +3,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
-using Microsoft.Azure.Functions.PowerShellWorker.Requests;
+using Microsoft.Azure.Functions.PowerShellWorker;
using Microsoft.Azure.Functions.PowerShellWorker.Utility;
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
using Xunit;
namespace Azure.Functions.PowerShell.Worker.Test
{
- public class HandleWorkerInitRequestTests
+ public class ProcessWorkerInitRequestTests
{
[Fact]
public void HandleWorkerInitRequestSuccess()
@@ -29,14 +29,12 @@ public void HandleWorkerInitRequestSuccess()
}
};
- StreamingMessage result = HandleWorkerInitRequest.Invoke(
- null,
- null,
+ var requestProcessor = new RequestProcessor(null);
+ StreamingMessage result = requestProcessor.ProcessWorkerInitRequest(
new StreamingMessage()
{
RequestId = requestId
- },
- new RpcLogger(null)
+ }
);
Assert.Equal(requestId, result.RequestId);
diff --git a/test/Azure.Functions.PowerShell.Worker.Test/Utility/TypeExtensionsTests.cs b/test/Utility/TypeExtensionsTests.cs
similarity index 100%
rename from test/Azure.Functions.PowerShell.Worker.Test/Utility/TypeExtensionsTests.cs
rename to test/Utility/TypeExtensionsTests.cs