Skip to content
Draft
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: 2 additions & 0 deletions InertiaCore/Models/InertiaOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public class InertiaOptions

public bool SsrEnabled { get; set; } = false;
public string SsrUrl { get; set; } = "http://127.0.0.1:13714/render";
public bool SsrEnsureBundleExists { get; set; } = true;
public string? SsrBundlePath { get; set; }
public bool EncryptHistory { get; set; } = false;
}
4 changes: 2 additions & 2 deletions InertiaCore/ResponseFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public Response Render(string component, object? props = null)

public async Task<IHtmlContent> Head(dynamic model)
{
if (!_options.Value.SsrEnabled) return new HtmlString("");
if (!_options.Value.SsrEnabled || !_gateway.ShouldDispatch()) return new HtmlString("");

var context = _contextAccessor.HttpContext!;

Expand All @@ -74,7 +74,7 @@ public async Task<IHtmlContent> Head(dynamic model)

public async Task<IHtmlContent> Html(dynamic model)
{
if (_options.Value.SsrEnabled)
if (_options.Value.SsrEnabled && _gateway.ShouldDispatch())
{
var context = _contextAccessor.HttpContext!;

Expand Down
81 changes: 79 additions & 2 deletions InertiaCore/Ssr/Gateway.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,26 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using InertiaCore.Models;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Hosting;

namespace InertiaCore.Ssr;

internal interface IGateway
internal interface IGateway : IHasHealthCheck
{
public Task<SsrResponse?> Dispatch(object model, string url);
public bool ShouldDispatch();
}

internal class Gateway : IGateway
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IOptions<InertiaOptions> _options;
private readonly IWebHostEnvironment _environment;

public Gateway(IHttpClientFactory httpClientFactory) => _httpClientFactory = httpClientFactory;
public Gateway(IHttpClientFactory httpClientFactory, IOptions<InertiaOptions> options, IWebHostEnvironment environment) =>
(_httpClientFactory, _options, _environment) = (httpClientFactory, options, environment);

public async Task<SsrResponse?> Dispatch(dynamic model, string url)
{
Expand All @@ -30,4 +37,74 @@ internal class Gateway : IGateway
var response = await client.PostAsync(url, content);
return await response.Content.ReadFromJsonAsync<SsrResponse>();
}

public bool ShouldDispatch()
{
return !_options.Value.SsrEnsureBundleExists || BundleExists();
}

private bool BundleExists()
{
var overridePath = _options.Value.SsrBundlePath;
if (!string.IsNullOrEmpty(overridePath))
{
var resolvedOverride = ResolvePath(overridePath);
if (!string.IsNullOrEmpty(resolvedOverride) && File.Exists(resolvedOverride))
{
return true;
}
}

var commonBundlePaths = new[]
{
"~/public/js/ssr.js",
"~/public/build/ssr.js",
"~/wwwroot/js/ssr.js",
"~/wwwroot/build/ssr.js",
"~/dist/ssr.js",
"~/build/ssr.js"
};

foreach (var path in commonBundlePaths)
{
var resolvedPath = ResolvePath(path);
if (!string.IsNullOrEmpty(resolvedPath) && File.Exists(resolvedPath))
{
return true;
}
}

return false;
}

private string? ResolvePath(string path)
{
if (path.StartsWith("~/"))
{
return Path.Combine(_environment.ContentRootPath, path[2..]);
}
return Path.IsPathRooted(path) ? path : Path.Combine(_environment.ContentRootPath, path);
}

public async Task<bool> IsHealthy()
{
try
{
var healthUrl = GetUrl("/health");
var client = _httpClientFactory.CreateClient();

using var response = await client.GetAsync(healthUrl);
return response.IsSuccessStatusCode;
}
catch
{
return false;
}
}

private string GetUrl(string endpoint)
{
var baseUrl = _options.Value.SsrUrl.TrimEnd('/');
return $"{baseUrl}{endpoint}";
}
}
6 changes: 6 additions & 0 deletions InertiaCore/Ssr/IHasHealthCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace InertiaCore.Ssr;

internal interface IHasHealthCheck
{
public Task<bool> IsHealthy();
}
6 changes: 5 additions & 1 deletion InertiaCoreTests/Setup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
using Microsoft.AspNetCore.Hosting;
using Moq;

namespace InertiaCoreTests;
Expand All @@ -21,11 +22,14 @@ public void Setup()
{
var contextAccessor = new Mock<IHttpContextAccessor>();
var httpClientFactory = new Mock<IHttpClientFactory>();
var environment = new Mock<IWebHostEnvironment>();
environment.SetupGet(x => x.ContentRootPath).Returns(Path.GetTempPath());

var gateway = new Gateway(httpClientFactory.Object);
var options = new Mock<IOptions<InertiaOptions>>();
options.SetupGet(x => x.Value).Returns(new InertiaOptions());

var gateway = new Gateway(httpClientFactory.Object, options.Object, environment.Object);

_factory = new ResponseFactory(contextAccessor.Object, gateway, options.Object);
}

Expand Down
Loading
Loading