Skip to content

Commit

Permalink
Support app codes optimizing for runtime expenses
Browse files Browse the repository at this point in the history
I saw apps spending a lot of time on encoding the `Bytes.Bytes` value to base64 when building HTTP responses. As a quick way to optimize runtimes expenses, offer a base64 string directly so that apps can avoid the roundtrip to and from `Bytes.Bytes`. This should become obsolete with a better engine running the Elm code: These values could be cached, but the current engine does not do that.
  • Loading branch information
Viir committed Jun 7, 2020
1 parent b57cd69 commit 7b6d84a
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,16 @@ static public string WithImportsAdded(

var firstImportMatch = Regex.Match(originalElmModuleText, @"^import\s", RegexOptions.Multiline);

return originalElmModuleText.Insert(firstImportMatch.Index, importsText + "\n");
var moduleSyntaxMatch = Regex.Match(originalElmModuleText, @"^module\s[\d\w\.\s\(\)_]+$", RegexOptions.Multiline);

var insertLocation =
firstImportMatch.Success
?
firstImportMatch.Index
:
(moduleSyntaxMatch.Index + moduleSyntaxMatch.Length);

return originalElmModuleText.Insert(insertLocation, "\n" + importsText + "\n");
}

static public string WithFunctionAdded(
Expand Down
43 changes: 31 additions & 12 deletions implement/PersistentProcess/PersistentProcess.Common/ElmApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,26 +156,45 @@ byte[] BuildFrontendWebHtml(string elmMakeCommandAppendix)
return Encoding.UTF8.GetBytes(frontendWebHtml);
}

var elmMakeCommandFromFunctionName =
ImmutableDictionary.Create<string, string>()
.SetItem("elm_make_frontendWeb_html", null)
.SetItem("elm_make_frontendWeb_html_debug", "--debug");
string fileExpression(string elmMakeCommandAppendix, bool encodingBase64)
{
var htmlFile = BuildFrontendWebHtml(elmMakeCommandAppendix: elmMakeCommandAppendix);

var fileAsBase64 = Convert.ToBase64String(htmlFile);

var base64Expression = "\"" + fileAsBase64 + "\"";

if (encodingBase64)
return base64Expression;

return
base64Expression +
@"|> Base64.toBytes |> Maybe.withDefault (""Failed to convert from base64"" |> Bytes.Encode.string |> Bytes.Encode.encode)";
}

/*
2020-06-07
I saw apps spending a lot of time on encoding the `Bytes.Bytes` value to base64 when building HTTP responses.
As a quick way to optimize runtimes expenses, offer a base64 string directly so that apps can avoid the roundtrip to and from `Bytes.Bytes`.
This should become obsolete with a better engine running the Elm code: These values could be cached, but the current engine does not do that.
*/

var fileExpressionFromFunctionName =
ImmutableDictionary.Create<string, Func<string>>()
.SetItem("elm_make_frontendWeb_html", () => fileExpression(elmMakeCommandAppendix: null, encodingBase64: false))
.SetItem("elm_make_frontendWeb_html_debug", () => fileExpression(elmMakeCommandAppendix: "--debug", encodingBase64: false))
.SetItem("elm_make_frontendWeb_html_base64", () => fileExpression(elmMakeCommandAppendix: null, encodingBase64: true))
.SetItem("elm_make_frontendWeb_html_debug_base64", () => fileExpression(elmMakeCommandAppendix: "--debug", encodingBase64: true));

IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> replaceFunction(
IImmutableDictionary<IImmutableList<string>, IImmutableList<byte>> previousAppFiles,
string functionName,
string originalFunctionText)
{
if (!elmMakeCommandFromFunctionName.TryGetValue(functionName, out var elmMakeCommandAppendix))
if (!fileExpressionFromFunctionName.TryGetValue(functionName, out var getFileExpression))
return previousAppFiles;

var htmlFile = BuildFrontendWebHtml(elmMakeCommandAppendix: elmMakeCommandAppendix);

var fileAsBase64 = Convert.ToBase64String(htmlFile);

var fileExpression = "\"" + fileAsBase64 + @"""|> Base64.toBytes |> Maybe.withDefault (""Failed to convert from base64"" |> Bytes.Encode.string |> Bytes.Encode.encode)";

var newFunctionBody = CompileElmValueSerializer.IndentElmCodeLines(1, fileExpression);
var newFunctionBody = CompileElmValueSerializer.IndentElmCodeLines(1, getFileExpression());

var originalFunctionTextLines =
originalFunctionText.Replace("\r", "").Split("\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,22 @@ void processEventAndResultingRequests(InterfaceToHost.Event interfaceEvent)
if (headerContentType != null)
context.Response.ContentType = headerContentType;

var contentAsByteArray =
httpResponse?.bodyAsBase64 == null
?
null
:
Convert.FromBase64String(httpResponse.bodyAsBase64);
byte[] contentAsByteArray = null;

if (httpResponse?.bodyAsBase64 != null)
{
var buffer = new byte[httpResponse.bodyAsBase64.Length * 3 / 4];

if (!Convert.TryFromBase64String(httpResponse.bodyAsBase64, buffer, out var bytesWritten))
{
throw new FormatException(
"Failed to convert from base64. bytesWritten=" + bytesWritten +
", input.length=" + httpResponse.bodyAsBase64.Length + ", input:\n" +
httpResponse.bodyAsBase64);
}

contentAsByteArray = buffer.AsSpan(0, bytesWritten).ToArray();
}

context.Response.ContentLength = contentAsByteArray?.Length ?? 0;

Expand Down

0 comments on commit 7b6d84a

Please sign in to comment.