Skip to content
Open
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 AppServiceProxy.Tests/ProxiesJsonReaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using AppServiceProxy.Configuration;
using AppServiceProxy.Configuration.Proxies;

using Xunit;

Expand Down
2 changes: 1 addition & 1 deletion AppServiceProxy.Tests/ProxiesJsonTransformTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;

using AppServiceProxy.Configuration;
using AppServiceProxy.Configuration.Proxies;

using Xunit;

Expand Down
39 changes: 39 additions & 0 deletions AppServiceProxy.Tests/YarpJsonReaderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using AppServiceProxy.Configuration.Yarp;

using Xunit;

namespace AppServiceProxy.Tests;

public class YarpJsonReaderTests
{
[Fact]
public void Basic()
{
var json = @"
{
""Routes"": {
""route1"": {
""ClusterId"": ""cluster1"",
""Match"": {
""Path"": ""{**catch-all}""
}
}
},
""Clusters"": {
""cluster1"": {
""Destinations"": {
""cluster1/destination1"": {
""Address"": ""https://shibayan.jp/""
}
}
}
}
}
";

var yarp = YarpJsonReader.ParseJson(json);

Assert.Single(yarp.Routes);
Assert.Single(yarp.Clusters);
}
}
77 changes: 77 additions & 0 deletions AppServiceProxy/Configuration/FileBaseProxyConfigProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Diagnostics.CodeAnalysis;

using AppServiceProxy.Configuration.Yarp;

using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;

using Yarp.ReverseProxy.Configuration;

namespace AppServiceProxy.Configuration;

internal class FileBaseProxyConfigProvider : IProxyConfigProvider
{
public FileBaseProxyConfigProvider(IEnumerable<IConfigFileLoader> configFileLoaders)
{
_configFileLoaders = configFileLoaders;

var json = System.Text.Json.JsonSerializer.Deserialize<YarpJson>(File.ReadAllText(@"C:\Users\shibayan\Documents\yarp.json"));

_fileProvider = new PhysicalFileProvider(s_wwwroot)
{
UseActivePolling = true,
UsePollingFileWatcher = true
};
}

private readonly IEnumerable<IConfigFileLoader> _configFileLoaders;
private readonly PhysicalFileProvider _fileProvider;

private static readonly string s_wwwroot = Environment.ExpandEnvironmentVariables(@"%HOME%\site\wwwroot");

public IProxyConfig GetConfig()
{
if (TryGetConfigFileLoader(out var configFileLoader))
{
var contents = File.ReadAllText(Path.Combine(s_wwwroot, configFileLoader.ConfigFileName));

var (routes, clusters) = configFileLoader.LoadConfig(contents);

var changeToken = _fileProvider.Watch(configFileLoader.ConfigFileName);

return new FileBaseProxyConfig
{
Routes = routes,
Clusters = clusters,
ChangeToken = changeToken
};
}
else
{
var changeToken = _fileProvider.Watch("*.*");

return new FileBaseProxyConfig
{
Routes = Array.Empty<RouteConfig>(),
Clusters = Array.Empty<ClusterConfig>(),
ChangeToken = changeToken
};
}
}

private bool TryGetConfigFileLoader([NotNullWhen(true)] out IConfigFileLoader? configFileLoader)
{
configFileLoader = _configFileLoaders.FirstOrDefault(x => File.Exists(Path.Combine(s_wwwroot, x.ConfigFileName)));

return configFileLoader is not null;
}

private class FileBaseProxyConfig : IProxyConfig
{
public IReadOnlyList<RouteConfig> Routes { get; init; } = null!;

public IReadOnlyList<ClusterConfig> Clusters { get; init; } = null!;

public IChangeToken ChangeToken { get; init; } = null!;
}
}
10 changes: 10 additions & 0 deletions AppServiceProxy/Configuration/IConfigFileLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Yarp.ReverseProxy.Configuration;

namespace AppServiceProxy.Configuration;

internal interface IConfigFileLoader
{
string ConfigFileName { get; }

(IReadOnlyList<RouteConfig>, IReadOnlyList<ClusterConfig>) LoadConfig(string contents);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AppServiceProxy.Configuration;
namespace AppServiceProxy.Configuration.Proxies;

internal class ProxiesJson
{
Expand Down Expand Up @@ -27,14 +27,18 @@ internal class MatchConditionConfig
internal class RequestOverridesConfig
{
public string? Method { get; init; }

public IReadOnlyDictionary<string, string> QueryString { get; init; } = null!;

public IReadOnlyDictionary<string, string> Headers { get; init; } = null!;
}

internal class ResponseOverridesConfig
{
public int? StatusCode { get; init; }

public string? StatusReason { get; init; }

public IReadOnlyDictionary<string, string> Headers { get; init; } = null!;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

using Yarp.ReverseProxy.Configuration;

namespace AppServiceProxy.Configuration.Proxies;

internal class ProxiesJsonConfigFileLoader : IConfigFileLoader
{
public string ConfigFileName => "proxies.json";

public (IReadOnlyList<RouteConfig>, IReadOnlyList<ClusterConfig>) LoadConfig(string contents)
{
try
{
var proxies = ProxiesJsonReader.ParseJson(contents);
var (routes, clusters) = ProxiesJsonTransform.Apply(proxies);

return (routes, clusters);
}
catch
{
return (Array.Empty<RouteConfig>(), Array.Empty<ClusterConfig>());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Text.Json;

using static AppServiceProxy.Configuration.ProxiesJson;
using static AppServiceProxy.Configuration.Proxies.ProxiesJson;

namespace AppServiceProxy.Configuration;
namespace AppServiceProxy.Configuration.Proxies;

internal class ProxiesJsonReader
{
Expand Down Expand Up @@ -57,8 +57,8 @@ private static ProxyConfig ParseProxyConfig(JsonProperty proxy)
var requestOverridesConfig = new RequestOverridesConfig
{
Method = requestOverrides.TryGetProperty("method", out var method) ? method.GetString() : null,
QueryString = requestOverrides.EnumerateObject().Where(x => x.Name.StartsWith("backend.request.querystring.")).ToDictionary(x => x.Name.Substring(28), x => x.Value.GetString()!),
Headers = requestOverrides.EnumerateObject().Where(x => x.Name.StartsWith("backend.request.headers.")).ToDictionary(x => x.Name.Substring(24), x => x.Value.GetString()!)
QueryString = requestOverrides.EnumerateObject().Where(x => x.Name.StartsWith("backend.request.querystring.")).ToDictionary(x => x.Name[28..], x => x.Value.GetString()!),
Headers = requestOverrides.EnumerateObject().Where(x => x.Name.StartsWith("backend.request.headers.")).ToDictionary(x => x.Name[24..], x => x.Value.GetString()!)
};

return requestOverridesConfig;
Expand All @@ -75,7 +75,7 @@ private static ProxyConfig ParseProxyConfig(JsonProperty proxy)
{
StatusCode = responseOverrides.TryGetProperty("response.statusCode", out var statusCode) ? statusCode.GetInt32() : null,
StatusReason = responseOverrides.TryGetProperty("response.statusReason", out var statusReason) ? statusReason.GetString() : null,
Headers = responseOverrides.EnumerateObject().Where(x => x.Name.StartsWith("response.headers.")).ToDictionary(x => x.Name.Substring(17), x => x.Value.GetString()!)
Headers = responseOverrides.EnumerateObject().Where(x => x.Name.StartsWith("response.headers.")).ToDictionary(x => x.Name[17..], x => x.Value.GetString()!)
};

return responseOverridesConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

using Yarp.ReverseProxy.Configuration;

using static AppServiceProxy.Configuration.ProxiesJson;
using static AppServiceProxy.Configuration.Proxies.ProxiesJson;

namespace AppServiceProxy.Configuration;
namespace AppServiceProxy.Configuration.Proxies;

internal static class ProxiesJsonTransform
internal static partial class ProxiesJsonTransform
{
private static readonly Regex s_templateRegex = new(@"\{([^\{\}]+)\}", RegexOptions.Compiled);
private static readonly Regex s_templateRegex = TemplateRegex();

public static (IReadOnlyList<RouteConfig>, IReadOnlyList<ClusterConfig>) Apply(IReadOnlyList<ProxyConfig> proxies)
{
Expand Down Expand Up @@ -126,4 +126,7 @@ private static (string, string?) SplitBackendUri(string backendUri)

return (destinationAddress, absolutePath);
}

[GeneratedRegex(@"\{([^\{\}]+)\}", RegexOptions.Compiled)]
private static partial Regex TemplateRegex();
}
59 changes: 0 additions & 59 deletions AppServiceProxy/Configuration/ProxiesJsonFileConfigProvider.cs

This file was deleted.

11 changes: 11 additions & 0 deletions AppServiceProxy/Configuration/Yarp/YarpJson.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

using Yarp.ReverseProxy.Configuration;

namespace AppServiceProxy.Configuration.Yarp;

internal class YarpJson
{
public IReadOnlyList<RouteConfig> Routes { get; set; } = null!;

public IReadOnlyList<ClusterConfig> Clusters { get; set; } = null!;
}
23 changes: 23 additions & 0 deletions AppServiceProxy/Configuration/Yarp/YarpJsonConfigFileLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

using Yarp.ReverseProxy.Configuration;

namespace AppServiceProxy.Configuration.Yarp;

internal class YarpJsonConfigFileLoader : IConfigFileLoader
{
public string ConfigFileName => "yarp.json";

public (IReadOnlyList<RouteConfig>, IReadOnlyList<ClusterConfig>) LoadConfig(string contents)
{
try
{
var yarp = YarpJsonReader.ParseJson(contents);

return (yarp.Routes, yarp.Clusters);
}
catch
{
return (Array.Empty<RouteConfig>(), Array.Empty<ClusterConfig>());
}
}
}
53 changes: 53 additions & 0 deletions AppServiceProxy/Configuration/Yarp/YarpJsonReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Text.Json;

using Yarp.ReverseProxy.Configuration;

namespace AppServiceProxy.Configuration.Yarp;

internal class YarpJsonReader
{
public static YarpJson ParseJson(string json)
{
var document = JsonDocument.Parse(json);

var routes = document.RootElement.GetProperty("Routes");
var clusters = document.RootElement.GetProperty("Clusters");

return new YarpJson { };
}

private static RouteConfig ParseRouteConfig(JsonProperty route)
{
return new RouteConfig
{
RouteId = route.Name,
Order = route.Value.TryGetProperty(nameof(RouteConfig.Order), out var order) ? order.GetInt32() : null,
ClusterId = route.Value.TryGetProperty(nameof(RouteConfig.ClusterId), out var clusterId) ? clusterId.GetString() : null,
AuthorizationPolicy = route.Value.TryGetProperty(nameof(RouteConfig.AuthorizationPolicy), out var authorizationPolicy) ? authorizationPolicy.GetString() : null,
CorsPolicy = route.Value.TryGetProperty(nameof(RouteConfig.CorsPolicy), out var corsPolicy) ? corsPolicy.GetString() : null,
Metadata = route.Value.TryGetProperty(nameof(RouteConfig.Metadata), out var metadata) ? metadata.Deserialize<Dictionary<string, string>>() : null,
Transforms = route.Value.TryGetProperty(nameof(RouteConfig.Transforms), out var transforms) ? ParseTransforms(transforms) : null
};
}

private static ClusterConfig ParseClusterConfig(JsonProperty cluster)
{
return new ClusterConfig
{
ClusterId = cluster.Name,
LoadBalancingPolicy = cluster.Value.TryGetProperty(nameof(ClusterConfig.LoadBalancingPolicy), out var loadBalancingPolicy) ? loadBalancingPolicy.GetString() : null,
};
}

private static IReadOnlyList<IReadOnlyDictionary<string, string>>? ParseTransforms(JsonElement transforms)
{
if (transforms.GetArrayLength() == 0)
{
return null;
}

return transforms.EnumerateArray()
.Select(x => x.EnumerateObject().ToDictionary(xs => xs.Name, xs => xs.Value.GetString()!, StringComparer.OrdinalIgnoreCase))
.ToList();
}
}
Loading