Skip to content

Service discovery adds Nacos #2268

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

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
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
72 changes: 72 additions & 0 deletions Ocelot.Provider.Nacos/Nacos.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using Nacos.V2;
using Nacos.V2.Exceptions;
using Nacos.V2.Naming.Dtos;
using Ocelot.Configuration;
using Ocelot.Logging;
using Ocelot.ServiceDiscovery.Providers;
using Ocelot.Values;
using System.Net;
using Service = Ocelot.Values.Service;

namespace Ocelot.Provider.Nacos
{
public class Nacos : IServiceDiscoveryProvider
{
private readonly INacosNamingService _client;
private readonly string _serviceName;

public Nacos(string serviceName,INacosNamingService client)
{
_client = client;
_serviceName = serviceName;
}

public async Task<List<Service>> GetAsync()
{
try
{
var instances = await _client.GetAllInstances(_serviceName)
.ConfigureAwait(false);

return instances?
.Where(i => i.Healthy && i.Enabled && i.Weight > 0) // 健康检查过滤
.Select(TransformInstance)
.ToList() ?? new List<Service>();
}
catch (NacosException ex)
{
throw ex;
}
}

private Service TransformInstance(Instance instance)
{
var metadata = instance.Metadata ?? new Dictionary<string, string>();

return new Service(
id: instance.InstanceId,
hostAndPort: new ServiceHostAndPort(instance.Ip, instance.Port),
name: instance.ServiceName,
version: metadata.GetValueOrDefault("version", "default"),
tags: ProcessMetadataTags(metadata)
);
}

private List<string> ProcessMetadataTags(IDictionary<string, string> metadata)
{
return metadata
.Where(kv => !_reservedKeys.Contains(kv.Key))
.Select(kv => FormatTag(kv))
.ToList();
}

private string FormatTag(KeyValuePair<string, string> kv)
{
var encodedKey = WebUtility.UrlEncode(kv.Key);
var encodedValue = WebUtility.UrlEncode(kv.Value);
return $"{encodedKey}={encodedValue}";
}

private static readonly string[] _reservedKeys = { "version", "group", "cluster", "namespace", "weight" };
}
}
30 changes: 30 additions & 0 deletions Ocelot.Provider.Nacos/NacosMiddlewareConfigurationProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Ocelot.Configuration;
using Ocelot.Configuration.Repository;
using Ocelot.Middleware;

namespace Ocelot.Provider.Nacos;

public class NacosMiddlewareConfigurationProvider
{
public static OcelotMiddlewareConfigurationDelegate Get { get; } = builder =>
{
var internalConfigRepo = builder.ApplicationServices.GetService<IInternalConfigurationRepository>();
var log =builder.ApplicationServices.GetService<ILogger<NacosMiddlewareConfigurationProvider>>();
var config = internalConfigRepo.Get();

if (UsingNacosServiceDiscoveryProvider(config.Data))
{
log.LogInformation("Using Nacos service discovery provider.");
}

return Task.CompletedTask;
};

private static bool UsingNacosServiceDiscoveryProvider(IInternalConfiguration configuration)
{
return configuration?.ServiceProviderConfiguration != null
&& configuration.ServiceProviderConfiguration.Type?.ToLower() == "nacos";
}
}
30 changes: 30 additions & 0 deletions Ocelot.Provider.Nacos/NacosProviderFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.Extensions.DependencyInjection;
using Ocelot.Configuration;
using Ocelot.ServiceDiscovery.Providers;
using Nacos.V2;
using Ocelot.ServiceDiscovery;

namespace Ocelot.Provider.Nacos;

public static class NacosProviderFactory
{
/// <summary>
/// String constant used for provider type definition.
/// </summary>
public const string Nacos = nameof(Provider.Nacos.Nacos);

public static ServiceDiscoveryFinderDelegate Get { get; } = CreateProvider;

private static IServiceDiscoveryProvider CreateProvider(IServiceProvider provider, ServiceProviderConfiguration config, DownstreamRoute route)
{
var client = provider.GetService<INacosNamingService>();
if (client == null)
{
throw new NullReferenceException($"Cannot get an {nameof(INacosNamingService)} service during {nameof(CreateProvider)} operation to instantiate the {nameof(Nacos)} provider!");
}

return Nacos.Equals(config.Type, StringComparison.OrdinalIgnoreCase)
? new Nacos(route.ServiceName, client)
: null;
}
}
11 changes: 11 additions & 0 deletions Ocelot.Provider.Nacos/NacosProviderOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Ocelot.Provider.Nacos
{
public class NacosProviderOptions
{
public string ServerAddresses { get; set; } = "http://localhost:8848";
public string Namespace { get; set; } = "public";
public int ListenInterval { get; set; } = 1000;
public string UserName { get; set; }
public string Password { get; set; }
}
}
18 changes: 18 additions & 0 deletions Ocelot.Provider.Nacos/Ocelot.Provider.Nacos.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="nacos-sdk-csharp" Version="1.3.10" />
<PackageReference Include="nacos-sdk-csharp.AspNetCore" Version="1.3.10" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\src\Ocelot\Ocelot.csproj" />
</ItemGroup>

</Project>
19 changes: 19 additions & 0 deletions Ocelot.Provider.Nacos/OcelotBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Ocelot.DependencyInjection;
using Nacos.AspNetCore.V2;

namespace Ocelot.Provider.Nacos
{
public static class OcelotBuilderExtensions
{
public static IOcelotBuilder AddNacos(this IOcelotBuilder builder, string section = "nacos")
{
builder.Services
.AddNacosAspNet(builder.Configuration,section)
.AddSingleton(NacosProviderFactory.Get)
.AddSingleton(NacosMiddlewareConfigurationProvider.Get);
return builder;
}
}
}
7 changes: 7 additions & 0 deletions Ocelot.sln
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Tracing.Butterfly",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ocelot.Tracing.OpenTracing", "src\Ocelot.Tracing.OpenTracing\Ocelot.Tracing.OpenTracing.csproj", "{11C622AD-8C0A-4CF4-811B-3DBB76550797}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ocelot.Provider.Nacos", "Ocelot.Provider.Nacos\Ocelot.Provider.Nacos.csproj", "{79FC3719-1F5A-4F22-9DE4-91424E401E5C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -118,6 +120,10 @@ Global
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11C622AD-8C0A-4CF4-811B-3DBB76550797}.Release|Any CPU.Build.0 = Release|Any CPU
{79FC3719-1F5A-4F22-9DE4-91424E401E5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79FC3719-1F5A-4F22-9DE4-91424E401E5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79FC3719-1F5A-4F22-9DE4-91424E401E5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79FC3719-1F5A-4F22-9DE4-91424E401E5C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -138,6 +144,7 @@ Global
{1F6E5DCF-8A2E-4E24-A25D-064362DE8D0E} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
{6045E23D-669C-4F27-AF8E-8EEE6DB3557F} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
{11C622AD-8C0A-4CF4-811B-3DBB76550797} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
{79FC3719-1F5A-4F22-9DE4-91424E401E5C} = {5CFB79B7-C9DC-45A4-9A75-625D92471702}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {21476EFF-778A-4F97-8A56-D1AF1CEC0C48}
Expand Down
Loading