Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maple fixes #259

Merged
merged 8 commits into from
Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build_maple.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 5.0.x
dotnet-version: 6.0.x
- name: Restore dependencies
run: dotnet restore Source/Meadow.Foundation.Libraries_and_Frameworks/Web.Maple/Maple.sln
- name: Build
Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/maple-binaries.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Build Maple Latest Binaries

on:
workflow_dispatch:
push:
branches: [ maple ]
tags:
- "maple*"
jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
- name: Build for F7
run: dotnet publish Source/Meadow.Foundation.Libraries_and_Frameworks/Web.Maple/Driver/Web.Maple.Server/Meadow.Foundation.Web.Maple.Server.csproj --framework netstandard2.1
- name: Create assets
uses: softprops/action-gh-release@v1
with:
files: "Maple.Server.dll"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ namespace Meadow.Foundation.Web.Maple.Server
{
public class ServerErrorResult : ObjectResult
{
public ServerErrorResult()
: base(null)
{
}

public ServerErrorResult(Exception ex)
: base(ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ public class ConsoleLogger : ILogger
{
public Loglevel Loglevel { get; set; } = Loglevel.Error;

public void Debug(string message)
{
Log(Loglevel.Debug, message);
}

public void DebugIf(bool condition, string message)
{
if (condition) Log(Loglevel.Debug, message);
}

public void Info(string message)
{
Log(Loglevel.Info, message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ public interface ILogger
{
Loglevel Loglevel { get; set; }
void Log(Loglevel level, string message);
void Debug(string message);
void DebugIf(bool condition, string message);
void Info(string message);
void InfoIf(bool condition, string message);
void Warn(string message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
public enum Loglevel
{
None,
Debug,
Info,
Warning,
Error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public MapleServer(
RequestProcessMode processMode = RequestProcessMode.Serial,
ILogger logger = null)
{
Logger = logger ?? new ConsoleLogger();
Logger = logger ?? new ConsoleLogger();
MethodCache = new RequestMethodCache(Logger);
ErrorPageGenerator = new ErrorPageGenerator();

Expand Down Expand Up @@ -135,7 +135,7 @@ protected void Initialize()
/// <summary>
/// Starts listening to requests, and optionally advertises on UDP.
/// </summary>
public async void Start()
public void Start()
{
try
{
Expand All @@ -156,8 +156,7 @@ public async void Start()
{
StartUdpAdvertisement();
}
await StartListeningToIncomingRequests();
_httpListener.Close();
StartListeningToIncomingRequests();
}

/// <summary>
Expand Down Expand Up @@ -237,57 +236,65 @@ protected void LoadRequestHandlers()
/// rather than in parallel.
/// </summary>
/// <returns></returns>
protected async Task StartListeningToIncomingRequests()
protected void StartListeningToIncomingRequests()
{
if (Running)
{
Logger.Error("Already running.");
return;
}

new Thread(RequestListenerProc).Start();
}

private async void RequestListenerProc()
{
Running = true;

await Task.Run(async () =>
Logger?.Info("Starting up Maple HTTP Request listener.");

while (Running)
{
Logger?.Info("starting up listener.");
HttpListenerContext context = null;

while (Running)
try
{
HttpListenerContext context = null;

try
{
// wait for a request to come in
context = await _httpListener.GetContextAsync();
Logger?.Info($"Request received from {context.Request.RemoteEndPoint}");

// depending on our processing mode, process either
// synchronously, or spin off a thread and immediately
// process the next request (as it comes in)
switch (ThreadingMode)
{
case RequestProcessMode.Serial:
ProcessRequest(context).Wait();
break;
case RequestProcessMode.Parallel:
_ = ProcessRequest(context);
break;
}
}
catch (SocketException e)
{
Logger?.Error("Socket Exception: " + e.ToString());
}
catch (Exception ex)
{
Logger?.Error(ex.ToString());
}
finally
// wait for a request to come in
context = await _httpListener.GetContextAsync();
Logger?.Info($"Request received from {context.Request.RemoteEndPoint}");

// depending on our processing mode, process either
// synchronously, or spin off a thread and immediately
// process the next request (as it comes in)
switch (ThreadingMode)
{
context?.Response.Close();
case RequestProcessMode.Serial:
ProcessRequest(context).Wait();
break;
case RequestProcessMode.Parallel:
_ = Task.Run(async () =>
{
await ProcessRequest(context);
});
break;
}
}
});
catch (SocketException e)
{
Logger?.Error("Socket Exception: " + e.ToString());
}
catch (Exception ex)
{
Logger?.Error(ex.ToString());
}
finally
{
context?.Response.Close();
}
}

Logger?.Info("Maple HTTP Request listener stopped.");
_httpListener.Close();
}

private IRequestHandler GetHandlerInstance(Type handlerType, out bool shouldDispose)
Expand Down Expand Up @@ -318,66 +325,73 @@ private IRequestHandler GetHandlerInstance(Type handlerType, out bool shouldDisp
return target;
}

protected Task ProcessRequest(HttpListenerContext context)
protected async Task ProcessRequest(HttpListenerContext context)
{
return Task.Run(async () =>
{
string[] urlQuery = context.Request.RawUrl.Substring(1).Split('?');
string[] urlParams = urlQuery[0].Split('/');
string requestedMethodName = urlParams[0].ToLower();
string[] urlQuery = context.Request.RawUrl.Substring(1).Split('?');
string[] urlParams = urlQuery[0].Split('/');
string requestedMethodName = urlParams[0].ToLower();

Logger?.Info("Received " + context.Request.HttpMethod + " " + context.Request.RawUrl + " - Invoking " + requestedMethodName);
Logger?.Info("Received " + context.Request.HttpMethod + " " + context.Request.RawUrl + " - Invoking " + requestedMethodName);

var handlerInfo = MethodCache.Match(context.Request.HttpMethod, context.Request.RawUrl, out object param);
if (handlerInfo == null)
var handlerInfo = MethodCache.Match(context.Request.HttpMethod, context.Request.RawUrl, out object param);
if (handlerInfo == null)
{
Logger?.Info("No handler found");
await ErrorPageGenerator.SendErrorPage(context, 404, "Not Found");
return;
}
else
{
var handlerInstance = GetHandlerInstance(handlerInfo.HandlerType, out bool shouldDispose);

if (handlerInstance == null)
{
Logger?.Info("No handler found");
Logger?.Info("Unable to get a handler instance");
await ErrorPageGenerator.SendErrorPage(context, 404, "Not Found");
return;
}
else
{
var handlerInstance = GetHandlerInstance(handlerInfo.HandlerType, out bool shouldDispose);

handlerInstance.Context = context;
handlerInstance.Context = context;

object[] paramObjects = null;
object[] paramObjects = null;

if (handlerInfo.Parameter != null)
if (handlerInfo.Parameter != null)
{
paramObjects = new object[]
{
paramObjects = new object[]
{
param
};
}
};
}

try
try
{
if (typeof(IActionResult).IsAssignableFrom(handlerInfo.Method.ReturnType))
{
if (typeof(IActionResult).IsAssignableFrom(handlerInfo.Method.ReturnType))
{
var result = handlerInfo.Method.Invoke(handlerInstance, paramObjects) as IActionResult;
await result.ExecuteResultAsync(context);
}
else
{
handlerInfo.Method.Invoke(handlerInstance, paramObjects);
}

context.Response.Close();
var result = handlerInfo.Method.Invoke(handlerInstance, paramObjects) as IActionResult;
await result.ExecuteResultAsync(context);
}
catch (Exception ex)
else
{
Logger?.Error(ex.Message);
await ErrorPageGenerator.SendErrorPage(context, 500, ex);
handlerInfo.Method.Invoke(handlerInstance, paramObjects);
}

// if the handler is not reusable, clean up
if (shouldDispose)
{
handlerInstance.Dispose();
}
context.Response.Close();
}
});
catch (Exception ex)
{
Logger?.Error(ex.Message);
await ErrorPageGenerator.SendErrorPage(context, 500, ex);
}

// if the handler is not reusable, clean up
if (shouldDispose)
{
Logger?.Debug("Disposing handler instance");
handlerInstance.Dispose();
}

Logger?.Debug("ProcessRequest complete");
}
}
}
}
Loading