using Nacos.V2;
using Newtonsoft.Json;
using System.Threading.Tasks;
using Yarp.ReverseProxy.Configuration;
namespace YuanXuan.IM.Api.Proxy
{
///
/// Nacos代理配置提供者
///
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);
}
///
/// 创建配置
///
///
private IProxyConfig CreateConfig()
{
var routes = new List
{
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();
try
{
// 从Nacos获取YuanXuan.Api服务实例,指定分组为qx-im
var apiServiceInstances = _nacosNamingService.GetAllInstances("YuanXuan.Api", "qx-im").Result;
if (apiServiceInstances.Any())
{
// 创建api_cluster集群配置
var apiDestinations = new Dictionary();
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();
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();
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
{
{
"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
{
{
"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
{
{
"default", new DestinationConfig { Address = "http://localhost:5252" }
}
}
});
}
return new ProxyConfig(routes, clusters, DateTime.UtcNow);
}
///
/// 获取代理配置
///
///
public IProxyConfig GetConfig() => _config;
///
/// 定期更新配置
///
///
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}");
}
}
}
///
/// 更新配置
///
///
private async Task UpdateConfig()
{
// 重新从Nacos获取服务实例并更新配置
_config = CreateConfig();
// 通知YARP配置已变更
ProxyConfig.SignalChange();
}
}
}