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

Improve handling of rule configuration errors #371

Merged
merged 10 commits into from
Feb 2, 2025
5 changes: 0 additions & 5 deletions fluxzy.core.sln
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__global", "__global", "{00
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{30657256-C907-42C2-B7B2-DA4FD8D0E412}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Scripts", "Scripts", "{F5C5DD67-8A16-4561-8545-2EF0441A2015}"
ProjectSection(SolutionItems) = preProject
tools\scripts\NameAndCompress.csx = tools\scripts\NameAndCompress.csx
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxzy.Core", "src\Fluxzy.Core\Fluxzy.Core.csproj", "{C79EDDB1-E4FA-4AB3-BAE4-B60D4D4E0B5E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "fluxzy", "src\Fluxzy\fluxzy.csproj", "{7826F811-8525-456B-99AC-03FBB8D37484}"
Expand Down
88 changes: 80 additions & 8 deletions src/Fluxzy.Core/Core/ConnectionErrorHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@
using System.Security.Authentication;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Fluxzy.Clients;
using Fluxzy.Clients.H2;
using Fluxzy.Misc.ResizableBuffers;
using Fluxzy.Rules;
using Fluxzy.Writers;

namespace Fluxzy.Core
{
internal static class ConnectionErrorHandler
{
private static readonly JsonSerializerOptions PrettyJsonOptions = new JsonSerializerOptions { WriteIndented = true };

public static bool RequalifyOnResponseSendError(
Exception ex,
Exchange exchange, ITimingProvider timingProvider)
Expand Down Expand Up @@ -82,6 +89,10 @@ public static bool RequalifyOnResponseSendError(
if (ex.TryGetException<ClientErrorException>(out var clientErrorException)) {
exchange.ClientErrors.Add(clientErrorException.ClientError);
}

if (ex.TryGetException<RuleExecutionFailureException>(out var ruleExecutionFailureException)) {
exchange.ClientErrors.Add(new ClientError(999, ruleExecutionFailureException.Message));
}

if (!exchange.ClientErrors.Any()) {
exchange.ClientErrors.Add(new ClientError(0, "A generic error has occured") {
Expand All @@ -93,6 +104,7 @@ public static bool RequalifyOnResponseSendError(
ex is IOException ||
ex is H2Exception ||
ex is ClientErrorException ||
ex is RuleExecutionFailureException ||
ex is AuthenticationException) {
if (DebugContext.EnableDumpStackTraceOn502) {
var message = "Fluxzy close connection due to server connection errors.\r\n\r\n";
Expand All @@ -107,11 +119,7 @@ ex is ClientErrorException ||

if (DebugContext.EnableDumpStackTraceOn502) {
exchange.Metrics.ErrorInstant = DateTime.Now;

message += "\r\n" + "\r\n" + JsonSerializer.Serialize(exchange.Metrics,
new JsonSerializerOptions {
WriteIndented = true
});
message += "\r\n" + "\r\n" + JsonSerializer.Serialize(exchange.Metrics,PrettyJsonOptions);
}

var messageBinary = Encoding.UTF8.GetBytes(message);
Expand All @@ -123,9 +131,6 @@ ex is ClientErrorException ||
header.AsMemory(),
exchange.Authority.Secure, true);

//if (DebugContext.EnableDumpStackTraceOn502)
// Console.WriteLine(message);

exchange.Response.Body = new MemoryStream(messageBinary);

if (!exchange.ExchangeCompletionSource.Task.IsCompleted) {
Expand Down Expand Up @@ -156,5 +161,72 @@ ex is ClientErrorException ||

return false;
}

public static async Task<bool> HandleGenericException(Exception ex,
ExchangeSourceInitResult? exchangeInitResult,
Exchange? exchange,
RsBuffer buffer,
RealtimeArchiveWriter? archiveWriter,
ITimingProvider timingProvider, CancellationToken token)
{
if (exchange?.Connection == null || exchangeInitResult?.WriteStream == null)
return false;

var message = "A configuration error has occured.\r\n";

if (ex is RuleExecutionFailureException ruleException) {
message =
"A rule execution failure has occured.\r\n\r\n" + ruleException.Message;
}

if (DebugContext.EnableDumpStackTraceOn502)
{
message += $"\r\n" +
$"Stacktrace:\r\n{ex}";
}

var (header, body) = ConnectionErrorPageHelper.GetSimplePlainTextResponse(
exchange.Authority,
message, ex.GetType().Name);

exchange.ClientErrors.Add(new ClientError(9999, message));

exchange.Response.Header = new ResponseHeader(
header.AsMemory(),
exchange.Authority.Secure, true);

exchange.Response.Body = new MemoryStream(body);

var responseHeaderLength = exchange.Response.Header!
.WriteHttp11(false, buffer, true, true,
true);

exchange.Metrics.ResponseHeaderStart = timingProvider.Instant();

await exchangeInitResult.WriteStream
.WriteAsync(buffer.Buffer, 0, responseHeaderLength, token)
.ConfigureAwait(false);

exchange.Metrics.ResponseHeaderEnd = timingProvider.Instant();
exchange.Metrics.ResponseBodyStart = timingProvider.Instant();

await exchange.Response.Body.CopyToAsync(exchangeInitResult.WriteStream, token)
.ConfigureAwait(false);

if (exchange.Metrics.ResponseBodyEnd == default)
{
exchange.Metrics.ResponseBodyEnd = timingProvider.Instant();
}

if (!exchange.ExchangeCompletionSource.Task.IsCompleted)
{
exchange.ExchangeCompletionSource.TrySetResult(true);
}

archiveWriter?.Update(exchange, ArchiveUpdateType.AfterResponse, token);


return true;
}
}
}
23 changes: 20 additions & 3 deletions src/Fluxzy.Core/Core/ConnectionErrorPageHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@ namespace Fluxzy.Core
{
internal static class ConnectionErrorPageHelper
{
private static readonly string ErrorHeader =
private static readonly string ErrorHeaderHtml =
"HTTP/1.1 {0}\r\n" +
"x-fluxzy: Fluxzy error\r\n" +
"Content-length: {1}\r\n" +
"Content-type: text/html\r\n" +
"Content-type: text/html; charset: utf-8\r\n" +
"Connection : close\r\n\r\n";

private static readonly string ErrorHeaderText =
"HTTP/1.1 {0}\r\n" +
"x-fluxzy: Fluxzy error\r\n" +
"x-fluxzy-error-type: {2}\r\n" +
"Content-length: {1}\r\n" +
"Content-type: text/plain; charset: utf-8\r\n" +
"Connection : close\r\n\r\n";

private static string BodyTemplate { get; }
Expand Down Expand Up @@ -60,7 +68,16 @@ public static (string FlatHeader, byte[] BodyContent) GetPrettyErrorPage(
bodyTemplate = bodyTemplate.Replace("@@error-message@@", errorMessage);

var body = Encoding.UTF8.GetBytes(bodyTemplate);
var header = string.Format(ErrorHeader, headerStatus, body.Length);
var header = string.Format(ErrorHeaderHtml, headerStatus, body.Length);
return (header, body);
}

public static (string FlatHeader, byte[] BodyContent) GetSimplePlainTextResponse(
Authority authority, string messageText, string errorTypeText)
{
var statusLine = "502 Fluxzy Configuration Error";
var header = string.Format(ErrorHeaderText, statusLine, messageText.Length, errorTypeText);
var body = Encoding.UTF8.GetBytes(messageText);
return (header, body);
}
}
Expand Down
Loading
Loading