mirror of
https://github.com/dotnetcore/AgileConfig.git
synced 2026-10-19 05:22:02 +08:00
335 lines
12 KiB
C#
335 lines
12 KiB
C#
using Agile.Config.Protocol;
|
|
using AgileConfig.Server.Common;
|
|
using AgileConfig.Server.Data.Entity;
|
|
using AgileConfig.Server.Data.Freesql;
|
|
using AgileConfig.Server.IService;
|
|
using AgileHttp;
|
|
using AgileHttp.serialize;
|
|
using Microsoft.Extensions.Logging;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Serialization;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace AgileConfig.Server.Service
|
|
{
|
|
public class RemoteServerNodeProxy : IRemoteServerNodeProxy
|
|
{
|
|
internal class SerializeProvider : ISerializeProvider
|
|
{
|
|
public T Deserialize<T>(string content)
|
|
{
|
|
return JsonConvert.DeserializeObject<T>(content, new JsonSerializerSettings
|
|
{
|
|
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
|
});
|
|
}
|
|
|
|
public string Serialize(object obj)
|
|
{
|
|
return JsonConvert.SerializeObject(obj);
|
|
}
|
|
}
|
|
|
|
private IServerNodeService GetServerNodeService()
|
|
{
|
|
return new ServerNodeService(new FreeSqlContext(FreeSQL.Instance));
|
|
}
|
|
|
|
private ILogger _logger;
|
|
|
|
private ISysLogService GetSysLogService()
|
|
{
|
|
return new SysLogService(new FreeSqlContext(FreeSQL.Instance));
|
|
}
|
|
|
|
private static ConcurrentDictionary<string, ClientInfos> _serverNodeClientReports =
|
|
new ConcurrentDictionary<string, ClientInfos>();
|
|
|
|
public RemoteServerNodeProxy(ILoggerFactory loggerFactory)
|
|
{
|
|
_logger = loggerFactory.CreateLogger<RemoteServerNodeProxy>();
|
|
}
|
|
|
|
public async Task<bool> AllClientsDoActionAsync(string address, WebsocketAction action)
|
|
{
|
|
var result = await FunctionUtil.TRYAsync(async () =>
|
|
{
|
|
using (var resp = await (address + "/RemoteOP/AllClientsDoAction")
|
|
.AsHttp("POST", action)
|
|
.Config(new RequestOptions { ContentType = "application/json" })
|
|
.SendAsync())
|
|
{
|
|
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
|
|
{
|
|
var result = resp.Deserialize<dynamic>();
|
|
|
|
if ((bool)result.success)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}, 5);
|
|
|
|
using (var service = GetSysLogService())
|
|
{
|
|
var module = "";
|
|
if (action.Module == "r")
|
|
{
|
|
module = "注册中心";
|
|
}
|
|
if (action.Module == "c")
|
|
{
|
|
module = "配置中心";
|
|
}
|
|
await service.AddSysLogAsync(new SysLog
|
|
{
|
|
LogTime = DateTime.Now,
|
|
LogType = result ? SysLogType.Normal : SysLogType.Warn,
|
|
LogText = $"通知节点【{address}】所有客户端:【{module}】【{action.Action}】 响应:{(result ? "成功" : "失败")}"
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<bool> AppClientsDoActionAsync(string address, string appId, string env, WebsocketAction action)
|
|
{
|
|
var result = await FunctionUtil.TRYAsync(async () =>
|
|
{
|
|
using (var resp = await (address + "/RemoteOP/AppClientsDoAction".AppendQueryString("appId", appId).AppendQueryString("env", env))
|
|
.AsHttp("POST", action)
|
|
.Config(new RequestOptions { ContentType = "application/json" })
|
|
.SendAsync())
|
|
{
|
|
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
|
|
{
|
|
var result = resp.Deserialize<dynamic>();
|
|
|
|
if ((bool)result.success)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}, 5);
|
|
|
|
using (var service = GetSysLogService())
|
|
{
|
|
var module = "";
|
|
if (action.Module == "r")
|
|
{
|
|
module = "注册中心";
|
|
}
|
|
if (action.Module == "c")
|
|
{
|
|
module = "配置中心";
|
|
}
|
|
await service.AddSysLogAsync(new SysLog
|
|
{
|
|
LogTime = DateTime.Now,
|
|
LogType = result ? SysLogType.Normal : SysLogType.Warn,
|
|
AppId = appId,
|
|
LogText = $"通知节点【{address}】应用【{appId}】的客户端:【{module}】【{action.Action}】 响应:{(result ? "成功" : "失败")}"
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<bool> OneClientDoActionAsync(string address, string clientId, WebsocketAction action)
|
|
{
|
|
var result = await FunctionUtil.TRYAsync(async () =>
|
|
{
|
|
using (var resp = await (address + "/RemoteOP/OneClientDoAction?clientId=" + clientId)
|
|
.AsHttp("POST", action)
|
|
.Config(new RequestOptions { ContentType = "application/json" })
|
|
.SendAsync())
|
|
{
|
|
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
|
|
{
|
|
var result = resp.Deserialize<dynamic>();
|
|
|
|
if ((bool)result.success)
|
|
{
|
|
if (action.Action == ActionConst.Offline)
|
|
{
|
|
if (_serverNodeClientReports.ContainsKey(address))
|
|
{
|
|
if (_serverNodeClientReports[address].Infos != null)
|
|
{
|
|
var report = _serverNodeClientReports[address];
|
|
report.Infos.RemoveAll(c => c.Id == clientId);
|
|
report.ClientCount = report.Infos.Count;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}, 5);
|
|
|
|
using (var service = GetSysLogService())
|
|
{
|
|
var module = "";
|
|
if (action.Module == "r")
|
|
{
|
|
module = "注册中心";
|
|
}
|
|
if (action.Module == "c")
|
|
{
|
|
module = "配置中心";
|
|
}
|
|
await service.AddSysLogAsync(new SysLog
|
|
{
|
|
LogTime = DateTime.Now,
|
|
LogType = result ? SysLogType.Normal : SysLogType.Warn,
|
|
LogText = $"通知节点【{address}】的客户端【{clientId}】:【{module}】【{action.Action}】 响应:{(result ? "成功" : "失败")}"
|
|
});
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<ClientInfos> GetClientsReportAsync(string address)
|
|
{
|
|
if (string.IsNullOrEmpty(address))
|
|
{
|
|
return new ClientInfos()
|
|
{
|
|
ClientCount = 0,
|
|
Infos = new List<ClientInfo>()
|
|
};
|
|
}
|
|
|
|
try
|
|
{
|
|
using (var resp = await (address + "/report/Clients").AsHttp()
|
|
.Config(new RequestOptions(new SerializeProvider())).SendAsync())
|
|
{
|
|
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
|
|
{
|
|
var clients = resp.Deserialize<ClientInfos>();
|
|
if (clients != null)
|
|
{
|
|
clients.Infos?.ForEach(i => { i.Address = address; });
|
|
return clients;
|
|
}
|
|
}
|
|
|
|
return new ClientInfos()
|
|
{
|
|
ClientCount = 0,
|
|
Infos = new List<ClientInfo>()
|
|
};
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger?.LogError($"Try to get client infos from node {address} occur ERROR . ", ex);
|
|
}
|
|
|
|
return new ClientInfos()
|
|
{
|
|
ClientCount = 0,
|
|
Infos = new List<ClientInfo>()
|
|
};
|
|
}
|
|
|
|
public async Task TestEchoAsync(string address)
|
|
{
|
|
using var service = GetServerNodeService();
|
|
var node = await service.GetAsync(address);
|
|
try
|
|
{
|
|
using var resp = await (node.Address + "/home/echo").AsHttp().SendAsync();
|
|
if (resp.StatusCode == System.Net.HttpStatusCode.OK && (await resp.GetResponseContentAsync()) == "ok")
|
|
{
|
|
node.LastEchoTime = DateTime.Now;
|
|
node.Status = NodeStatus.Online;
|
|
}
|
|
else
|
|
{
|
|
node.Status = NodeStatus.Offline;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
node.Status = NodeStatus.Offline;
|
|
_logger.LogInformation(e, "Try test node {0} echo , but fail .", node.Address);
|
|
}
|
|
|
|
if (node.Status == NodeStatus.Offline)
|
|
{
|
|
DateTime? time = node.LastEchoTime;
|
|
if (!time.HasValue)
|
|
{
|
|
time = node.CreateTime;
|
|
}
|
|
if (time.HasValue && (DateTime.Now - time.Value).TotalMinutes >= 30)
|
|
{
|
|
// 超过 30 分钟没有回应,则移除节点
|
|
await service.DeleteAsync(address);
|
|
return;
|
|
}
|
|
}
|
|
|
|
await service.UpdateAsync(node);
|
|
}
|
|
|
|
public Task TestEchoAsync()
|
|
{
|
|
return Task.Run(async () =>
|
|
{
|
|
while (true)
|
|
{
|
|
using var service = GetServerNodeService();
|
|
var nodes = await service.GetAllNodesAsync();
|
|
|
|
foreach (var node in nodes)
|
|
{
|
|
await TestEchoAsync(node.Address);
|
|
}
|
|
|
|
await Task.Delay(5000 * 1);
|
|
}
|
|
});
|
|
}
|
|
|
|
public async Task ClearConfigServiceCache(string address)
|
|
{
|
|
try
|
|
{
|
|
await (address + "/RemoteOP/ClearConfigServiceCache").AsHttp("POST").SendAsync();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.LogError(e, "Try to clear node {0}'s config cache , but fail .", address);
|
|
}
|
|
}
|
|
|
|
public async Task ClearServiceInfoCache(string address)
|
|
{
|
|
try
|
|
{
|
|
await (address + "/RemoteOP/ClearServiceInfoCache").AsHttp("POST").SendAsync();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.LogError(e, "Try to clear node {0}'s servicesinfo cache , but fail .", address);
|
|
}
|
|
}
|
|
}
|
|
} |