270 lines
9.6 KiB
C#
270 lines
9.6 KiB
C#
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();
|
||
}
|
||
|
||
}
|
||
|
||
}
|