CSharp.Template/YuanXuan.IM.Api/Proxy/NacosProxyConfigProvider.cs

270 lines
9.6 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Nacos.V2;
using Newtonsoft.Json;
using System.Threading.Tasks;
using Yarp.ReverseProxy.Configuration;
namespace YuanXuan.IM.Api.Proxy
{
/// <summary>
/// Nacos代理配置提供者
/// </summary>
public class NacosProxyConfigProvider : IProxyConfigProvider
{
private readonly INacosNamingService _nacosNamingService;
private readonly IConfiguration _configuration;
private volatile IProxyConfig _config;
private CancellationTokenSource _cts;
public NacosProxyConfigProvider(INacosNamingService nacosNamingService, IConfiguration configuration)
{
_nacosNamingService = nacosNamingService;
_configuration = configuration;
// 立即从Nacos获取服务实例
_config = CreateConfig();
// 通知YARP配置已变更
ProxyConfig.SignalChange();
_cts = new CancellationTokenSource();
// 启动后台任务定期从Nacos更新服务实例
Task.Run(async () => await UpdateConfigPeriodically(), _cts.Token);
}
/// <summary>
/// 创建配置
/// </summary>
/// <returns></returns>
private IProxyConfig CreateConfig()
{
var routes = new List<RouteConfig>
{
new RouteConfig
{
RouteId = "api_route",
ClusterId = "api_cluster",
Match = new RouteMatch
{
Path = "/api/{**catch-all}"
}
},
new RouteConfig
{
RouteId = "user_route",
ClusterId = "user_cluster",
Match = new RouteMatch
{
Path = "/user/{**catch-all}"
}
},
new RouteConfig
{
RouteId = "testdemo1",
ClusterId = "test_cluster",
Match = new RouteMatch
{
Path = "/test/{**catch-all}"
}
}
};
var clusters = new List<ClusterConfig>();
try
{
// 从Nacos获取YuanXuan.Api服务实例指定分组为qx-im
var apiServiceInstances = _nacosNamingService.GetAllInstances("YuanXuan.Api", "qx-im").Result;
if (apiServiceInstances.Any())
{
// 创建api_cluster集群配置
var apiDestinations = new Dictionary<string, DestinationConfig>();
foreach (var instance in apiServiceInstances)
{
if (instance.Healthy)
{
var destinationId = $"{instance.Ip}:{instance.Port}";
apiDestinations.Add(destinationId, new DestinationConfig
{
Address = $"http://{instance.Ip}:{instance.Port}"
});
}
}
clusters.Add(new ClusterConfig
{
ClusterId = "api_cluster",
Destinations = apiDestinations
});
}
// 从Nacos获取User.Service服务实例指定分组为qx-im
try
{
var userServiceInstances = _nacosNamingService.GetAllInstances("User.Service", "qx-im").Result;
if (userServiceInstances.Any())
{
// 创建user_cluster集群配置
var userDestinations = new Dictionary<string, DestinationConfig>();
foreach (var instance in userServiceInstances)
{
if (instance.Healthy)
{
var destinationId = $"{instance.Ip}:{instance.Port}";
userDestinations.Add(destinationId, new DestinationConfig
{
Address = $"http://{instance.Ip}:{instance.Port}"
});
}
}
clusters.Add(new ClusterConfig
{
ClusterId = "user_cluster",
Destinations = userDestinations
});
}
}
catch (Exception ex)
{
Console.WriteLine($"从Nacos获取User.Service服务实例失败: {ex.Message}");
}
// 从Nacos获取Test.Service服务实例指定分组为qx-im
try
{
var testServiceInstances = _nacosNamingService.GetAllInstances("Test.Service", "qx-im").Result;
if (testServiceInstances.Any())
{
// 创建test_cluster集群配置
var testDestinations = new Dictionary<string, DestinationConfig>();
foreach (var instance in testServiceInstances)
{
if (instance.Healthy)
{
var destinationId = $"{instance.Ip}:{instance.Port}";
testDestinations.Add(destinationId, new DestinationConfig
{
Address = $"http://{instance.Ip}:{instance.Port}"
});
}
}
clusters.Add(new ClusterConfig
{
ClusterId = "test_cluster",
Destinations = testDestinations
});
}
}
catch (Exception ex)
{
Console.WriteLine($"从Nacos获取Test.Service服务实例失败: {ex.Message}");
}
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}" + JsonConvert.SerializeObject(clusters));
}
catch (Exception ex)
{
Console.WriteLine($"从Nacos获取服务实例失败: {ex.Message}");
}
// 如果没有从Nacos获取到api_cluster集群使用默认配置
if (!clusters.Any(c => c.ClusterId == "api_cluster"))
{
clusters.Add(new ClusterConfig
{
ClusterId = "api_cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{
"default", new DestinationConfig { Address = "http://localhost:5001" }
}
}
});
}
// 如果没有从Nacos获取到user_cluster集群使用默认配置
if (!clusters.Any(c => c.ClusterId == "user_cluster"))
{
clusters.Add(new ClusterConfig
{
ClusterId = "user_cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{
"default", new DestinationConfig { Address = "http://localhost:5181" }
}
}
});
}
// 如果没有从Nacos获取到test_cluster集群使用默认配置
if (!clusters.Any(c => c.ClusterId == "test_cluster"))
{
clusters.Add(new ClusterConfig
{
ClusterId = "test_cluster",
Destinations = new Dictionary<string, DestinationConfig>
{
{
"default", new DestinationConfig { Address = "http://localhost:5252" }
}
}
});
}
return new ProxyConfig(routes, clusters, DateTime.UtcNow);
}
/// <summary>
/// 获取代理配置
/// </summary>
/// <returns></returns>
public IProxyConfig GetConfig() => _config;
/// <summary>
/// 定期更新配置
/// </summary>
/// <returns></returns>
private async Task UpdateConfigPeriodically()
{
while (!_cts.Token.IsCancellationRequested)
{
try
{
await Task.Delay(TimeSpan.FromSeconds(30), _cts.Token); // 每30秒更新一次
await UpdateConfig();
}
catch (TaskCanceledException)
{
// 任务被取消,退出循环
break;
}
catch (Exception ex)
{
Console.WriteLine($"更新Nacos代理配置失败: {ex.Message}");
}
}
}
/// <summary>
/// 更新配置
/// </summary>
/// <returns></returns>
private async Task UpdateConfig()
{
// 重新从Nacos获取服务实例并更新配置
_config = CreateConfig();
// 通知YARP配置已变更
ProxyConfig.SignalChange();
}
}
}