优化本地星尘探测,屏蔽超时异常信息
This commit is contained in:
parent
7d4e01cb2a
commit
dd6b0c7eb7
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0;net461</TargetFrameworks>
|
||||
<AssemblyTitle>星尘代理</AssemblyTitle>
|
||||
<Description>星尘,分布式资源调度,部署于每一个节点,连接服务端,支持节点监控、远程发布。</Description>
|
||||
<Company>新生命开发团队</Company>
|
||||
|
|
|
@ -11,424 +11,434 @@ using NewLife.Remoting;
|
|||
using Stardust.Managers;
|
||||
using Stardust.Models;
|
||||
|
||||
namespace Stardust
|
||||
namespace Stardust;
|
||||
|
||||
/// <summary>本地星尘客户端。连接本机星尘代理StarAgent</summary>
|
||||
public class LocalStarClient
|
||||
{
|
||||
/// <summary>本地星尘客户端。连接本机星尘代理StarAgent</summary>
|
||||
public class LocalStarClient
|
||||
#region 属性
|
||||
/// <summary>代理信息</summary>
|
||||
public AgentInfo Info { get; private set; }
|
||||
|
||||
/// <summary>本地服务端地址</summary>
|
||||
public String Server { get => _local?.Server; set => _local.Server = value; }
|
||||
|
||||
private readonly AgentInfo _local;
|
||||
private ApiClient _client;
|
||||
#endregion
|
||||
|
||||
#region 构造
|
||||
/// <summary>实例化</summary>
|
||||
public LocalStarClient()
|
||||
{
|
||||
#region 属性
|
||||
/// <summary>代理信息</summary>
|
||||
public AgentInfo Info { get; private set; }
|
||||
_local = AgentInfo.GetLocal();
|
||||
_local.Server = StarSetting.Current.Server;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>本地服务端地址</summary>
|
||||
public String Server { get => _local?.Server; set => _local.Server = value; }
|
||||
#region 方法
|
||||
private void Init()
|
||||
{
|
||||
if (_client != null) return;
|
||||
|
||||
private readonly AgentInfo _local;
|
||||
private ApiClient _client;
|
||||
#endregion
|
||||
|
||||
#region 构造
|
||||
/// <summary>实例化</summary>
|
||||
public LocalStarClient()
|
||||
_client = new ApiClient("udp://127.0.0.1:5500")
|
||||
{
|
||||
_local = AgentInfo.GetLocal();
|
||||
_local.Server = StarSetting.Current.Server;
|
||||
}
|
||||
#endregion
|
||||
Timeout = 3_000,
|
||||
Log = Log,
|
||||
};
|
||||
|
||||
#region 方法
|
||||
private void Init()
|
||||
var set = StarSetting.Current;
|
||||
if (set.Debug) _client.EncoderLog = Log;
|
||||
}
|
||||
|
||||
/// <summary>获取信息</summary>
|
||||
/// <returns></returns>
|
||||
public AgentInfo GetInfo()
|
||||
{
|
||||
var task = GetInfoAsync();
|
||||
return task.Wait(500) ? task.Result : null;
|
||||
}
|
||||
|
||||
/// <summary>获取信息</summary>
|
||||
/// <returns></returns>
|
||||
public async Task<AgentInfo> GetInfoAsync()
|
||||
{
|
||||
Init();
|
||||
|
||||
try
|
||||
{
|
||||
if (_client != null) return;
|
||||
|
||||
_client = new ApiClient("udp://127.0.0.1:5500")
|
||||
{
|
||||
Timeout = 3_000,
|
||||
Log = Log,
|
||||
};
|
||||
|
||||
var set = StarSetting.Current;
|
||||
if (set.Debug) _client.EncoderLog = Log;
|
||||
}
|
||||
|
||||
/// <summary>获取信息</summary>
|
||||
/// <returns></returns>
|
||||
public AgentInfo GetInfo()
|
||||
{
|
||||
var task = GetInfoAsync().ContinueWith(t => t.IsCompleted ? t.Result : null);
|
||||
return task.Wait(500) ? task.Result : null;
|
||||
}
|
||||
|
||||
/// <summary>获取信息</summary>
|
||||
/// <returns></returns>
|
||||
public async Task<AgentInfo> GetInfoAsync()
|
||||
{
|
||||
Init();
|
||||
|
||||
return Info = await _client.InvokeAsync<AgentInfo>("Info", _local);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 进程控制
|
||||
/// <summary>自杀并重启</summary>
|
||||
/// <returns></returns>
|
||||
public Boolean KillAndRestartMySelf()
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Init();
|
||||
|
||||
var p = Process.GetCurrentProcess();
|
||||
var fileName = p.MainModule.FileName;
|
||||
var args = Environment.CommandLine.TrimStart(Path.ChangeExtension(fileName, ".dll")).Trim();
|
||||
|
||||
// 发起命令
|
||||
var rs = _client.Invoke<String>("KillAndStart", new
|
||||
{
|
||||
processId = p.Id,
|
||||
delay = 3,
|
||||
fileName,
|
||||
arguments = args,
|
||||
workingDirectory = Environment.CurrentDirectory,
|
||||
});
|
||||
|
||||
// 本进程退出
|
||||
//p.Kill();
|
||||
|
||||
return !rs.IsNullOrEmpty();
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 安装星尘代理
|
||||
/// <summary>探测并安装星尘代理</summary>
|
||||
/// <param name="url">zip包下载源</param>
|
||||
/// <param name="version">版本号</param>
|
||||
/// <param name="target">目标目录</param>
|
||||
public Boolean ProbeAndInstall(String url = null, String version = null, String target = null)
|
||||
catch
|
||||
{
|
||||
//if (url.IsNullOrEmpty()) throw new ArgumentNullException(nameof(url));
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
var set = NewLife.Setting.Current;
|
||||
url = set.PluginServer.EnsureEnd("/");
|
||||
url += "star/";
|
||||
if (Environment.Version.Major >= 6)
|
||||
url += "staragent60.zip";
|
||||
else if (Environment.Version.Major >= 5)
|
||||
url += "staragent50.zip";
|
||||
else if (Environment.Version.Major >= 4)
|
||||
url += "staragent45.zip";
|
||||
else
|
||||
url += "staragent31.zip";
|
||||
}
|
||||
|
||||
// 尝试连接,获取版本
|
||||
try
|
||||
{
|
||||
var info = GetInfo();
|
||||
if (info != null)
|
||||
{
|
||||
// 比目标版本高,不需要安装
|
||||
if (String.Compare(info.Version, version) >= 0) return true;
|
||||
|
||||
if (!info.FileName.IsNullOrEmpty()) info.FileName = info.FileName.TrimEnd(" (deleted)");
|
||||
if (target.IsNullOrEmpty()) target = Path.GetDirectoryName(info.FileName);
|
||||
|
||||
WriteLog("StarAgent在用版本 v{0},低于目标版本 v{1}", info.Version, version);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteLog("没有探测到StarAgent,{0}", ex.GetTrue().Message);
|
||||
}
|
||||
|
||||
if (target.IsNullOrEmpty())
|
||||
{
|
||||
// 在进程中查找
|
||||
var p = Process.GetProcesses().FirstOrDefault(e => e.ProcessName == "StarAgent");
|
||||
if (p != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
target = Path.GetDirectoryName(p.MainModule.FileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
target = Path.GetDirectoryName(p.MainWindowTitle);
|
||||
}
|
||||
|
||||
WriteLog("发现进程StarAgent,ProcessId={0},target={1}", p.Id, target);
|
||||
}
|
||||
}
|
||||
|
||||
// 准备安装,甭管是否能够成功重启,先覆盖了文件再说
|
||||
{
|
||||
if (target.IsNullOrEmpty()) target = "..\\staragent";
|
||||
target = target.GetFullPath();
|
||||
target.EnsureDirectory(false);
|
||||
|
||||
WriteLog("目标:{0}", target);
|
||||
|
||||
var ug = new Upgrade
|
||||
{
|
||||
SourceFile = Path.GetFileName(url).GetFullPath(),
|
||||
DestinationPath = target,
|
||||
|
||||
Log = XTrace.Log,
|
||||
};
|
||||
|
||||
WriteLog("下载:{0}", url);
|
||||
|
||||
var client = new HttpClient();
|
||||
client.DownloadFileAsync(url, ug.SourceFile).Wait();
|
||||
|
||||
ug.Update();
|
||||
|
||||
File.Delete(ug.SourceFile);
|
||||
}
|
||||
|
||||
{
|
||||
// 在进程中查找
|
||||
var info = Info;
|
||||
var inService = info?.Arguments == "-s";
|
||||
var p = info != null && info.ProcessId > 0 ?
|
||||
Process.GetProcessById(info.ProcessId) :
|
||||
Process.GetProcesses().FirstOrDefault(e => e.ProcessName == "StarAgent");
|
||||
|
||||
// 重启目标
|
||||
if (p != null && !inService)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.Kill();
|
||||
}
|
||||
catch (Win32Exception) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
XTrace.WriteException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
var fileName = info?.FileName;
|
||||
if (!fileName.IsNullOrEmpty() && Path.GetFullPath(fileName).EqualIgnoreCase("dotnet.exe")) fileName = info.Arguments;
|
||||
|
||||
var rs = false;
|
||||
if (Runtime.Windows)
|
||||
rs = RunAgentOnWindows(fileName, target, inService);
|
||||
else if (Runtime.Linux)
|
||||
rs = RunAgentOnLinux(fileName, target, inService);
|
||||
if (!rs)
|
||||
rs = RunAgentOnDotnet(fileName, target, inService);
|
||||
}
|
||||
|
||||
return true;
|
||||
throw;
|
||||
}
|
||||
|
||||
private Boolean RunAgentOnWindows(String fileName, String target, Boolean inService)
|
||||
{
|
||||
if (!fileName.IsNullOrEmpty() && Path.GetExtension(fileName) == ".dll") return false;
|
||||
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent.exe").GetFullPath();
|
||||
if (!File.Exists(fileName)) return false;
|
||||
|
||||
WriteLog("RunAgentOnWindows fileName={0}, inService={1}", fileName, inService);
|
||||
|
||||
if (inService)
|
||||
{
|
||||
Process.Start(fileName, "-stop");
|
||||
Process.Start(fileName, "-start");
|
||||
|
||||
WriteLog("启动服务成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = new ProcessStartInfo(fileName, "-run")
|
||||
{
|
||||
WorkingDirectory = Path.GetDirectoryName(fileName),
|
||||
UseShellExecute = true
|
||||
};
|
||||
var p = Process.Start(si);
|
||||
|
||||
WriteLog("启动进程成功 pid={0}", p.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean RunAgentOnLinux(String fileName, String target, Boolean inService)
|
||||
{
|
||||
if (!fileName.IsNullOrEmpty() && Path.GetExtension(fileName) == ".dll") return false;
|
||||
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent").GetFullPath();
|
||||
if (!File.Exists(fileName)) return false;
|
||||
|
||||
WriteLog("RunAgentOnLinux fileName={0}, inService={1}", fileName, inService);
|
||||
|
||||
// 在Linux中设置执行权限
|
||||
Process.Start("chmod", $"+x {fileName}");
|
||||
|
||||
if (inService)
|
||||
{
|
||||
Process.Start(fileName, "-stop");
|
||||
Process.Start(fileName, "-start");
|
||||
|
||||
WriteLog("启动服务成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = new ProcessStartInfo(fileName, "-run")
|
||||
{
|
||||
WorkingDirectory = Path.GetDirectoryName(fileName),
|
||||
UseShellExecute = true
|
||||
};
|
||||
var p = Process.Start(si);
|
||||
|
||||
WriteLog("启动进程成功 pid={0}", p.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean RunAgentOnDotnet(String fileName, String target, Boolean inService)
|
||||
{
|
||||
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent.dll").GetFullPath();
|
||||
if (!File.Exists(fileName)) return false;
|
||||
|
||||
WriteLog("RunAgentOnDotnet fileName={0}, inService={1}", fileName, inService);
|
||||
|
||||
if (inService)
|
||||
{
|
||||
Process.Start("dotnet", $"{fileName} -stop");
|
||||
Process.Start("dotnet", $"{fileName} -start");
|
||||
|
||||
WriteLog("启动服务成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = new ProcessStartInfo("dotnet", $"{fileName} -run")
|
||||
{
|
||||
WorkingDirectory = Path.GetDirectoryName(fileName),
|
||||
UseShellExecute = true
|
||||
};
|
||||
var p = Process.Start(si);
|
||||
|
||||
WriteLog("启动进程成功 pid={0}", p.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>探测并安装星尘代理</summary>
|
||||
/// <param name="url">zip包下载源</param>
|
||||
/// <param name="version">版本号</param>
|
||||
/// <param name="target">目标目录</param>
|
||||
public static Task ProbeAsync(String url = null, String version = null, String target = null)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var client = new LocalStarClient();
|
||||
client.ProbeAndInstall(url, version, target);
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 安装卸载应用服务
|
||||
/// <summary>安装应用服务(星尘代理守护)</summary>
|
||||
/// <param name="service"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ProcessInfo> Install(ServiceInfo service)
|
||||
{
|
||||
Init();
|
||||
|
||||
return await _client.InvokeAsync<ProcessInfo>("Install", service);
|
||||
}
|
||||
|
||||
/// <summary>安装应用服务(星尘代理守护)</summary>
|
||||
/// <param name="name">服务名,唯一标识</param>
|
||||
/// <param name="fileName">文件</param>
|
||||
/// <param name="arguments">参数</param>
|
||||
/// <param name="workingDirectory">工作目录</param>
|
||||
/// <returns></returns>
|
||||
public async Task<ProcessInfo> Install(String name, String fileName, String arguments = null, String workingDirectory = null)
|
||||
{
|
||||
Init();
|
||||
|
||||
return await _client.InvokeAsync<ProcessInfo>("Install", new ServiceInfo
|
||||
{
|
||||
Name = name,
|
||||
FileName = fileName,
|
||||
Arguments = arguments,
|
||||
WorkingDirectory = workingDirectory,
|
||||
AutoStart = true,
|
||||
ReloadOnChange = true,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>卸载应用服务</summary>
|
||||
/// <param name="serviceName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Boolean> Uninstall(String serviceName)
|
||||
{
|
||||
Init();
|
||||
|
||||
return await _client.InvokeAsync<Boolean>("Uninstall", serviceName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 搜索
|
||||
/// <summary>在局域网中广播扫描所有StarAgent</summary>
|
||||
/// <param name="local">本地信息,用于告知对方我是谁</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<AgentInfo> Scan(AgentInfo local = null, Int32 timeout = 15_000)
|
||||
{
|
||||
var encoder = new JsonEncoder { Log = XTrace.Log };
|
||||
// 构造请求消息
|
||||
//var ms = new MemoryStream();
|
||||
//var writer = new BinaryWriter(ms);
|
||||
//writer.Write("Info");
|
||||
//writer.Write(0);
|
||||
|
||||
//var msg = new DefaultMessage
|
||||
//{
|
||||
// Payload = ms.ToArray()
|
||||
//};
|
||||
//var buf = msg.ToPacket().ToArray();
|
||||
|
||||
var buf = encoder.CreateRequest("Info", null).ToPacket().ToArray();
|
||||
|
||||
// 广播消息
|
||||
var udp = new UdpClient();
|
||||
udp.Send(buf, buf.Length, new IPEndPoint(IPAddress.Broadcast, 5500));
|
||||
|
||||
var end = DateTime.Now.AddSeconds(timeout);
|
||||
while (DateTime.Now < end)
|
||||
{
|
||||
var rs = new DefaultMessage();
|
||||
IPEndPoint ep = null;
|
||||
buf = udp.Receive(ref ep);
|
||||
if (buf != null && rs.Read(buf) && encoder.Decode(rs, out var action, out _, out var data))
|
||||
{
|
||||
//ms = rs.Payload.GetStream();
|
||||
//var reader=new BinaryReader(ms);
|
||||
//var name=reader.ReadString();
|
||||
//var code = reader.ReadInt32();
|
||||
//var data=reader
|
||||
|
||||
var js = encoder.DecodeResult(action, data, rs);
|
||||
var info = (AgentInfo)encoder.Convert(js, typeof(AgentInfo));
|
||||
|
||||
yield return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 日志
|
||||
/// <summary>日志</summary>
|
||||
public ILog Log { get; set; }
|
||||
|
||||
/// <summary>写日志</summary>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="args"></param>
|
||||
public void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 进程控制
|
||||
/// <summary>自杀并重启</summary>
|
||||
/// <returns></returns>
|
||||
public Boolean KillAndRestartMySelf()
|
||||
{
|
||||
Init();
|
||||
|
||||
var p = Process.GetCurrentProcess();
|
||||
var fileName = p.MainModule.FileName;
|
||||
var args = Environment.CommandLine.TrimStart(Path.ChangeExtension(fileName, ".dll")).Trim();
|
||||
|
||||
// 发起命令
|
||||
var rs = _client.Invoke<String>("KillAndStart", new
|
||||
{
|
||||
processId = p.Id,
|
||||
delay = 3,
|
||||
fileName,
|
||||
arguments = args,
|
||||
workingDirectory = Environment.CurrentDirectory,
|
||||
});
|
||||
|
||||
// 本进程退出
|
||||
//p.Kill();
|
||||
|
||||
return !rs.IsNullOrEmpty();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 安装星尘代理
|
||||
/// <summary>探测并安装星尘代理</summary>
|
||||
/// <param name="url">zip包下载源</param>
|
||||
/// <param name="version">版本号</param>
|
||||
/// <param name="target">目标目录</param>
|
||||
public Boolean ProbeAndInstall(String url = null, String version = null, String target = null)
|
||||
{
|
||||
//if (url.IsNullOrEmpty()) throw new ArgumentNullException(nameof(url));
|
||||
if (url.IsNullOrEmpty())
|
||||
{
|
||||
var set = NewLife.Setting.Current;
|
||||
url = set.PluginServer.EnsureEnd("/");
|
||||
url += "star/";
|
||||
if (Environment.Version.Major >= 6)
|
||||
url += "staragent60.zip";
|
||||
else if (Environment.Version.Major >= 5)
|
||||
url += "staragent50.zip";
|
||||
else if (Environment.Version.Major >= 4)
|
||||
url += "staragent45.zip";
|
||||
else
|
||||
url += "staragent31.zip";
|
||||
}
|
||||
|
||||
// 尝试连接,获取版本
|
||||
try
|
||||
{
|
||||
var info = GetInfo();
|
||||
if (info != null)
|
||||
{
|
||||
// 比目标版本高,不需要安装
|
||||
if (String.Compare(info.Version, version) >= 0) return true;
|
||||
|
||||
if (!info.FileName.IsNullOrEmpty()) info.FileName = info.FileName.TrimEnd(" (deleted)");
|
||||
if (target.IsNullOrEmpty()) target = Path.GetDirectoryName(info.FileName);
|
||||
|
||||
WriteLog("StarAgent在用版本 v{0},低于目标版本 v{1}", info.Version, version);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
WriteLog("没有探测到StarAgent,{0}", ex.GetTrue().Message);
|
||||
}
|
||||
|
||||
if (target.IsNullOrEmpty())
|
||||
{
|
||||
// 在进程中查找
|
||||
var p = Process.GetProcesses().FirstOrDefault(e => e.ProcessName == "StarAgent");
|
||||
if (p != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
target = Path.GetDirectoryName(p.MainModule.FileName);
|
||||
}
|
||||
catch
|
||||
{
|
||||
target = Path.GetDirectoryName(p.MainWindowTitle);
|
||||
}
|
||||
|
||||
WriteLog("发现进程StarAgent,ProcessId={0},target={1}", p.Id, target);
|
||||
}
|
||||
}
|
||||
|
||||
// 准备安装,甭管是否能够成功重启,先覆盖了文件再说
|
||||
{
|
||||
if (target.IsNullOrEmpty()) target = "..\\staragent";
|
||||
target = target.GetFullPath();
|
||||
target.EnsureDirectory(false);
|
||||
|
||||
WriteLog("目标:{0}", target);
|
||||
|
||||
var ug = new Upgrade
|
||||
{
|
||||
SourceFile = Path.GetFileName(url).GetFullPath(),
|
||||
DestinationPath = target,
|
||||
|
||||
Log = XTrace.Log,
|
||||
};
|
||||
|
||||
WriteLog("下载:{0}", url);
|
||||
|
||||
var client = new HttpClient();
|
||||
client.DownloadFileAsync(url, ug.SourceFile).Wait();
|
||||
|
||||
ug.Update();
|
||||
|
||||
File.Delete(ug.SourceFile);
|
||||
}
|
||||
|
||||
{
|
||||
// 在进程中查找
|
||||
var info = Info;
|
||||
var inService = info?.Arguments == "-s";
|
||||
var p = info != null && info.ProcessId > 0 ?
|
||||
Process.GetProcessById(info.ProcessId) :
|
||||
Process.GetProcesses().FirstOrDefault(e => e.ProcessName == "StarAgent");
|
||||
|
||||
// 重启目标
|
||||
if (p != null && !inService)
|
||||
{
|
||||
try
|
||||
{
|
||||
p.Kill();
|
||||
}
|
||||
catch (Win32Exception) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
XTrace.WriteException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
var fileName = info?.FileName;
|
||||
if (!fileName.IsNullOrEmpty() && Path.GetFullPath(fileName).EqualIgnoreCase("dotnet.exe")) fileName = info.Arguments;
|
||||
|
||||
var rs = false;
|
||||
if (Runtime.Windows)
|
||||
rs = RunAgentOnWindows(fileName, target, inService);
|
||||
else if (Runtime.Linux)
|
||||
rs = RunAgentOnLinux(fileName, target, inService);
|
||||
if (!rs)
|
||||
rs = RunAgentOnDotnet(fileName, target, inService);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean RunAgentOnWindows(String fileName, String target, Boolean inService)
|
||||
{
|
||||
if (!fileName.IsNullOrEmpty() && Path.GetExtension(fileName) == ".dll") return false;
|
||||
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent.exe").GetFullPath();
|
||||
if (!File.Exists(fileName)) return false;
|
||||
|
||||
WriteLog("RunAgentOnWindows fileName={0}, inService={1}", fileName, inService);
|
||||
|
||||
if (inService)
|
||||
{
|
||||
Process.Start(fileName, "-stop");
|
||||
Process.Start(fileName, "-start");
|
||||
|
||||
WriteLog("启动服务成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = new ProcessStartInfo(fileName, "-run")
|
||||
{
|
||||
WorkingDirectory = Path.GetDirectoryName(fileName),
|
||||
UseShellExecute = true
|
||||
};
|
||||
var p = Process.Start(si);
|
||||
|
||||
WriteLog("启动进程成功 pid={0}", p.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean RunAgentOnLinux(String fileName, String target, Boolean inService)
|
||||
{
|
||||
if (!fileName.IsNullOrEmpty() && Path.GetExtension(fileName) == ".dll") return false;
|
||||
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent").GetFullPath();
|
||||
if (!File.Exists(fileName)) return false;
|
||||
|
||||
WriteLog("RunAgentOnLinux fileName={0}, inService={1}", fileName, inService);
|
||||
|
||||
// 在Linux中设置执行权限
|
||||
Process.Start("chmod", $"+x {fileName}");
|
||||
|
||||
if (inService)
|
||||
{
|
||||
Process.Start(fileName, "-stop");
|
||||
Process.Start(fileName, "-start");
|
||||
|
||||
WriteLog("启动服务成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = new ProcessStartInfo(fileName, "-run")
|
||||
{
|
||||
WorkingDirectory = Path.GetDirectoryName(fileName),
|
||||
UseShellExecute = true
|
||||
};
|
||||
var p = Process.Start(si);
|
||||
|
||||
WriteLog("启动进程成功 pid={0}", p.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Boolean RunAgentOnDotnet(String fileName, String target, Boolean inService)
|
||||
{
|
||||
if (fileName.IsNullOrEmpty()) fileName = target.CombinePath("StarAgent.dll").GetFullPath();
|
||||
if (!File.Exists(fileName)) return false;
|
||||
|
||||
WriteLog("RunAgentOnDotnet fileName={0}, inService={1}", fileName, inService);
|
||||
|
||||
if (inService)
|
||||
{
|
||||
Process.Start("dotnet", $"{fileName} -stop");
|
||||
Process.Start("dotnet", $"{fileName} -start");
|
||||
|
||||
WriteLog("启动服务成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
var si = new ProcessStartInfo("dotnet", $"{fileName} -run")
|
||||
{
|
||||
WorkingDirectory = Path.GetDirectoryName(fileName),
|
||||
UseShellExecute = true
|
||||
};
|
||||
var p = Process.Start(si);
|
||||
|
||||
WriteLog("启动进程成功 pid={0}", p.Id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>探测并安装星尘代理</summary>
|
||||
/// <param name="url">zip包下载源</param>
|
||||
/// <param name="version">版本号</param>
|
||||
/// <param name="target">目标目录</param>
|
||||
public static Task ProbeAsync(String url = null, String version = null, String target = null)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var client = new LocalStarClient();
|
||||
client.ProbeAndInstall(url, version, target);
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 安装卸载应用服务
|
||||
/// <summary>安装应用服务(星尘代理守护)</summary>
|
||||
/// <param name="service"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ProcessInfo> Install(ServiceInfo service)
|
||||
{
|
||||
Init();
|
||||
|
||||
return await _client.InvokeAsync<ProcessInfo>("Install", service);
|
||||
}
|
||||
|
||||
/// <summary>安装应用服务(星尘代理守护)</summary>
|
||||
/// <param name="name">服务名,唯一标识</param>
|
||||
/// <param name="fileName">文件</param>
|
||||
/// <param name="arguments">参数</param>
|
||||
/// <param name="workingDirectory">工作目录</param>
|
||||
/// <returns></returns>
|
||||
public async Task<ProcessInfo> Install(String name, String fileName, String arguments = null, String workingDirectory = null)
|
||||
{
|
||||
Init();
|
||||
|
||||
return await _client.InvokeAsync<ProcessInfo>("Install", new ServiceInfo
|
||||
{
|
||||
Name = name,
|
||||
FileName = fileName,
|
||||
Arguments = arguments,
|
||||
WorkingDirectory = workingDirectory,
|
||||
AutoStart = true,
|
||||
ReloadOnChange = true,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>卸载应用服务</summary>
|
||||
/// <param name="serviceName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Boolean> Uninstall(String serviceName)
|
||||
{
|
||||
Init();
|
||||
|
||||
return await _client.InvokeAsync<Boolean>("Uninstall", serviceName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 搜索
|
||||
/// <summary>在局域网中广播扫描所有StarAgent</summary>
|
||||
/// <param name="local">本地信息,用于告知对方我是谁</param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<AgentInfo> Scan(AgentInfo local = null, Int32 timeout = 15_000)
|
||||
{
|
||||
var encoder = new JsonEncoder { Log = XTrace.Log };
|
||||
// 构造请求消息
|
||||
//var ms = new MemoryStream();
|
||||
//var writer = new BinaryWriter(ms);
|
||||
//writer.Write("Info");
|
||||
//writer.Write(0);
|
||||
|
||||
//var msg = new DefaultMessage
|
||||
//{
|
||||
// Payload = ms.ToArray()
|
||||
//};
|
||||
//var buf = msg.ToPacket().ToArray();
|
||||
|
||||
var buf = encoder.CreateRequest("Info", null).ToPacket().ToArray();
|
||||
|
||||
// 广播消息
|
||||
var udp = new UdpClient();
|
||||
udp.Send(buf, buf.Length, new IPEndPoint(IPAddress.Broadcast, 5500));
|
||||
|
||||
var end = DateTime.Now.AddSeconds(timeout);
|
||||
while (DateTime.Now < end)
|
||||
{
|
||||
var rs = new DefaultMessage();
|
||||
IPEndPoint ep = null;
|
||||
buf = udp.Receive(ref ep);
|
||||
if (buf != null && rs.Read(buf) && encoder.Decode(rs, out var action, out _, out var data))
|
||||
{
|
||||
//ms = rs.Payload.GetStream();
|
||||
//var reader=new BinaryReader(ms);
|
||||
//var name=reader.ReadString();
|
||||
//var code = reader.ReadInt32();
|
||||
//var data=reader
|
||||
|
||||
var js = encoder.DecodeResult(action, data, rs);
|
||||
var info = (AgentInfo)encoder.Convert(js, typeof(AgentInfo));
|
||||
|
||||
yield return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 日志
|
||||
/// <summary>日志</summary>
|
||||
public ILog Log { get; set; }
|
||||
|
||||
/// <summary>写日志</summary>
|
||||
/// <param name="format"></param>
|
||||
/// <param name="args"></param>
|
||||
public void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
|
||||
#endregion
|
||||
}
|
|
@ -9,379 +9,383 @@ using NewLife.Model;
|
|||
using NewLife.Reflection;
|
||||
using NewLife.Remoting;
|
||||
using NewLife.Security;
|
||||
using NewLife.Serialization;
|
||||
using Stardust.Configs;
|
||||
using Stardust.Models;
|
||||
using Stardust.Monitors;
|
||||
using Stardust.Registry;
|
||||
|
||||
namespace Stardust
|
||||
namespace Stardust;
|
||||
|
||||
/// <summary>星尘工厂</summary>
|
||||
/// <remarks>
|
||||
/// 星尘代理 https://newlifex.com/blood/staragent_install
|
||||
/// 监控中心 https://newlifex.com/blood/stardust_monitor
|
||||
/// 配置中心 https://newlifex.com/blood/stardust_configcenter
|
||||
/// </remarks>
|
||||
public class StarFactory : DisposeBase
|
||||
{
|
||||
/// <summary>星尘工厂</summary>
|
||||
/// <remarks>
|
||||
/// 星尘代理 https://newlifex.com/blood/staragent_install
|
||||
/// 监控中心 https://newlifex.com/blood/stardust_monitor
|
||||
/// 配置中心 https://newlifex.com/blood/stardust_configcenter
|
||||
/// </remarks>
|
||||
public class StarFactory : DisposeBase
|
||||
#region 属性
|
||||
/// <summary>服务器地址</summary>
|
||||
public String Server { get; set; }
|
||||
|
||||
/// <summary>应用</summary>
|
||||
public String AppId { get; set; }
|
||||
|
||||
/// <summary>应用名</summary>
|
||||
public String AppName { get; set; }
|
||||
|
||||
/// <summary>应用密钥</summary>
|
||||
public String Secret { get; set; }
|
||||
|
||||
/// <summary>实例。应用可能多实例部署,ip@proccessid</summary>
|
||||
public String ClientId { get; set; }
|
||||
|
||||
///// <summary>服务名</summary>
|
||||
//public String ServiceName { get; set; }
|
||||
|
||||
/// <summary>客户端</summary>
|
||||
public IApiClient Client => _client;
|
||||
|
||||
/// <summary>应用客户端</summary>
|
||||
public AppClient App => _client;
|
||||
|
||||
/// <summary>配置信息。从配置中心返回的信息头</summary>
|
||||
public ConfigInfo ConfigInfo => (_config as StarHttpConfigProvider)?.ConfigInfo;
|
||||
|
||||
/// <summary>本地星尘代理</summary>
|
||||
public LocalStarClient Local { get; private set; }
|
||||
|
||||
private AppClient _client;
|
||||
private TokenHttpFilter _tokenFilter;
|
||||
//private AppClient _appClient;
|
||||
#endregion
|
||||
|
||||
#region 构造
|
||||
/// <summary>
|
||||
/// 实例化星尘工厂,先后读取appsettings.json、本地StarAgent、star.config
|
||||
/// </summary>
|
||||
public StarFactory() => Init();
|
||||
|
||||
/// <summary>实例化星尘工厂,指定地址、应用和密钥,创建工厂</summary>
|
||||
/// <param name="server">服务端地址。为空时先后读取appsettings.json、本地StarAgent、star.config,初始值为空,不连接服务端</param>
|
||||
/// <param name="appId">应用标识。为空时读取star.config,初始值为入口程序集名称</param>
|
||||
/// <param name="secret">应用密钥。为空时读取star.config,初始值为空</param>
|
||||
/// <returns></returns>
|
||||
public StarFactory(String server, String appId, String secret)
|
||||
{
|
||||
#region 属性
|
||||
/// <summary>服务器地址</summary>
|
||||
public String Server { get; set; }
|
||||
Server = server;
|
||||
AppId = appId;
|
||||
Secret = secret;
|
||||
|
||||
/// <summary>应用</summary>
|
||||
public String AppId { get; set; }
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>应用名</summary>
|
||||
public String AppName { get; set; }
|
||||
/// <summary>销毁</summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(Boolean disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
/// <summary>应用密钥</summary>
|
||||
public String Secret { get; set; }
|
||||
_tracer.TryDispose();
|
||||
_config.TryDispose();
|
||||
//_appClient.TryDispose();
|
||||
}
|
||||
|
||||
/// <summary>实例。应用可能多实例部署,ip@proccessid</summary>
|
||||
public String ClientId { get; set; }
|
||||
private void Init()
|
||||
{
|
||||
XTrace.WriteLine("正在初始化星尘……");
|
||||
|
||||
///// <summary>服务名</summary>
|
||||
//public String ServiceName { get; set; }
|
||||
Local = new LocalStarClient();
|
||||
|
||||
/// <summary>客户端</summary>
|
||||
public IApiClient Client => _client;
|
||||
// 从环境变量读取星尘地址、应用Id、密钥,方便容器化部署
|
||||
if (Server.IsNullOrEmpty()) Server = Environment.GetEnvironmentVariable("StarServer");
|
||||
if (AppId.IsNullOrEmpty()) AppId = Environment.GetEnvironmentVariable("AppId");
|
||||
if (Secret.IsNullOrEmpty()) Secret = Environment.GetEnvironmentVariable("Secret");
|
||||
|
||||
/// <summary>应用客户端</summary>
|
||||
public AppClient App => _client;
|
||||
|
||||
/// <summary>配置信息。从配置中心返回的信息头</summary>
|
||||
public ConfigInfo ConfigInfo => (_config as StarHttpConfigProvider)?.ConfigInfo;
|
||||
|
||||
/// <summary>本地星尘代理</summary>
|
||||
public LocalStarClient Local { get; private set; }
|
||||
|
||||
private AppClient _client;
|
||||
private TokenHttpFilter _tokenFilter;
|
||||
//private AppClient _appClient;
|
||||
#endregion
|
||||
|
||||
#region 构造
|
||||
/// <summary>
|
||||
/// 实例化星尘工厂,先后读取appsettings.json、本地StarAgent、star.config
|
||||
/// </summary>
|
||||
public StarFactory() => Init();
|
||||
|
||||
/// <summary>实例化星尘工厂,指定地址、应用和密钥,创建工厂</summary>
|
||||
/// <param name="server">服务端地址。为空时先后读取appsettings.json、本地StarAgent、star.config,初始值为空,不连接服务端</param>
|
||||
/// <param name="appId">应用标识。为空时读取star.config,初始值为入口程序集名称</param>
|
||||
/// <param name="secret">应用密钥。为空时读取star.config,初始值为空</param>
|
||||
/// <returns></returns>
|
||||
public StarFactory(String server, String appId, String secret)
|
||||
// 不区分大小写识别环境变量
|
||||
foreach (DictionaryEntry item in Environment.GetEnvironmentVariables())
|
||||
{
|
||||
Server = server;
|
||||
AppId = appId;
|
||||
Secret = secret;
|
||||
|
||||
Init();
|
||||
var key = item.Key + "";
|
||||
if (Server.IsNullOrEmpty() && key.EqualIgnoreCase("StarServer"))
|
||||
Server = item.Value + "";
|
||||
else if (AppId.IsNullOrEmpty() && key.EqualIgnoreCase("AppId"))
|
||||
AppId = item.Value + "";
|
||||
else if (Secret.IsNullOrEmpty() && key.EqualIgnoreCase("Secret"))
|
||||
Secret = item.Value + "";
|
||||
}
|
||||
|
||||
/// <summary>销毁</summary>
|
||||
/// <param name="disposing"></param>
|
||||
protected override void Dispose(Boolean disposing)
|
||||
// 读取本地appsetting
|
||||
if (Server.IsNullOrEmpty() && File.Exists("appsettings.Development.json".GetFullPath()))
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
using var json = new JsonConfigProvider { FileName = "appsettings.Development.json" };
|
||||
json.LoadAll();
|
||||
|
||||
_tracer.TryDispose();
|
||||
_config.TryDispose();
|
||||
//_appClient.TryDispose();
|
||||
Server = json["StarServer"];
|
||||
}
|
||||
if (Server.IsNullOrEmpty() && File.Exists("appsettings.json".GetFullPath()))
|
||||
{
|
||||
using var json = new JsonConfigProvider { FileName = "appsettings.json" };
|
||||
json.LoadAll();
|
||||
|
||||
Server = json["StarServer"];
|
||||
}
|
||||
|
||||
private void Init()
|
||||
if (!Server.IsNullOrEmpty() && Local.Server.IsNullOrEmpty()) Local.Server = Server;
|
||||
|
||||
//if (AppId != "StarAgent")
|
||||
//{
|
||||
// 借助本地StarAgent获取服务器地址
|
||||
try
|
||||
{
|
||||
XTrace.WriteLine("正在初始化星尘……");
|
||||
|
||||
Local = new LocalStarClient();
|
||||
|
||||
// 从环境变量读取星尘地址、应用Id、密钥,方便容器化部署
|
||||
if (Server.IsNullOrEmpty()) Server = Environment.GetEnvironmentVariable("StarServer");
|
||||
if (AppId.IsNullOrEmpty()) AppId = Environment.GetEnvironmentVariable("AppId");
|
||||
if (Secret.IsNullOrEmpty()) Secret = Environment.GetEnvironmentVariable("Secret");
|
||||
// 不区分大小写识别环境变量
|
||||
foreach (DictionaryEntry item in Environment.GetEnvironmentVariables())
|
||||
var inf = Local.GetInfo();
|
||||
var server = inf?.Server;
|
||||
if (!server.IsNullOrEmpty())
|
||||
{
|
||||
var key = item.Key + "";
|
||||
if (Server.IsNullOrEmpty() && key.EqualIgnoreCase("StarServer"))
|
||||
Server = item.Value + "";
|
||||
else if (AppId.IsNullOrEmpty() && key.EqualIgnoreCase("AppId"))
|
||||
AppId = item.Value + "";
|
||||
else if (Secret.IsNullOrEmpty() && key.EqualIgnoreCase("Secret"))
|
||||
Secret = item.Value + "";
|
||||
if (Server.IsNullOrEmpty()) Server = server;
|
||||
XTrace.WriteLine("星尘探测:{0}", server);
|
||||
}
|
||||
else
|
||||
XTrace.WriteLine("星尘探测:StarAgent Not Found");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
XTrace.Log.Error("星尘探测失败!{0}", ex.Message);
|
||||
}
|
||||
//}
|
||||
|
||||
// 如果探测不到本地应用,则使用配置
|
||||
var set = StarSetting.Current;
|
||||
if (Server.IsNullOrEmpty()) Server = set.Server;
|
||||
if (AppId.IsNullOrEmpty()) AppId = set.AppKey;
|
||||
if (Secret.IsNullOrEmpty()) Secret = set.Secret;
|
||||
|
||||
// 生成ClientId,用于唯一标识当前实例,默认IP@pid
|
||||
try
|
||||
{
|
||||
var executing = AssemblyX.Create(Assembly.GetExecutingAssembly());
|
||||
var asm = AssemblyX.Entry ?? executing;
|
||||
if (asm != null)
|
||||
{
|
||||
if (AppId.IsNullOrEmpty()) AppId = asm.Name;
|
||||
if (AppName.IsNullOrEmpty()) AppName = asm.Title;
|
||||
}
|
||||
|
||||
// 读取本地appsetting
|
||||
if (Server.IsNullOrEmpty() && File.Exists("appsettings.Development.json".GetFullPath()))
|
||||
{
|
||||
using var json = new JsonConfigProvider { FileName = "appsettings.Development.json" };
|
||||
json.LoadAll();
|
||||
|
||||
Server = json["StarServer"];
|
||||
}
|
||||
if (Server.IsNullOrEmpty() && File.Exists("appsettings.json".GetFullPath()))
|
||||
{
|
||||
using var json = new JsonConfigProvider { FileName = "appsettings.json" };
|
||||
json.LoadAll();
|
||||
|
||||
Server = json["StarServer"];
|
||||
}
|
||||
|
||||
if (!Server.IsNullOrEmpty() && Local.Server.IsNullOrEmpty()) Local.Server = Server;
|
||||
|
||||
// 借助本地StarAgent获取服务器地址
|
||||
try
|
||||
{
|
||||
var inf = Local.GetInfo();
|
||||
var server = inf?.Server;
|
||||
if (!server.IsNullOrEmpty())
|
||||
{
|
||||
if (Server.IsNullOrEmpty()) Server = server;
|
||||
XTrace.WriteLine("星尘探测:{0}", server);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
XTrace.Log.Error("星尘探测失败!{0}", ex.Message);
|
||||
}
|
||||
|
||||
// 如果探测不到本地应用,则使用配置
|
||||
var set = StarSetting.Current;
|
||||
if (Server.IsNullOrEmpty()) Server = set.Server;
|
||||
if (AppId.IsNullOrEmpty()) AppId = set.AppKey;
|
||||
if (Secret.IsNullOrEmpty()) Secret = set.Secret;
|
||||
|
||||
// 生成ClientId,用于唯一标识当前实例,默认IP@pid
|
||||
try
|
||||
{
|
||||
var executing = AssemblyX.Create(Assembly.GetExecutingAssembly());
|
||||
var asm = AssemblyX.Entry ?? executing;
|
||||
if (asm != null)
|
||||
{
|
||||
if (AppId.IsNullOrEmpty()) AppId = asm.Name;
|
||||
if (AppName.IsNullOrEmpty()) AppName = asm.Title;
|
||||
}
|
||||
|
||||
ClientId = $"{NetHelper.MyIP()}@{Process.GetCurrentProcess().Id}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
ClientId = Rand.NextString(8);
|
||||
}
|
||||
|
||||
XTrace.WriteLine("星尘分布式服务 Server={0} AppId={1} ClientId={2}", Server, AppId, ClientId);
|
||||
|
||||
Valid();
|
||||
|
||||
var ioc = ObjectContainer.Current;
|
||||
ioc.AddSingleton(this);
|
||||
ioc.AddSingleton(p => Tracer);
|
||||
ioc.AddSingleton(p => Config);
|
||||
ioc.AddSingleton(p => Service);
|
||||
ClientId = $"{NetHelper.MyIP()}@{Process.GetCurrentProcess().Id}";
|
||||
}
|
||||
catch
|
||||
{
|
||||
ClientId = Rand.NextString(8);
|
||||
}
|
||||
|
||||
private Boolean Valid()
|
||||
XTrace.WriteLine("星尘分布式服务 Server={0} AppId={1} ClientId={2}", Server, AppId, ClientId);
|
||||
|
||||
Valid();
|
||||
|
||||
var ioc = ObjectContainer.Current;
|
||||
ioc.AddSingleton(this);
|
||||
ioc.AddSingleton(p => Tracer);
|
||||
ioc.AddSingleton(p => Config);
|
||||
ioc.AddSingleton(p => Service);
|
||||
}
|
||||
|
||||
private Boolean Valid()
|
||||
{
|
||||
//if (Server.IsNullOrEmpty()) throw new ArgumentNullException(nameof(Server));
|
||||
//if (AppId.IsNullOrEmpty()) throw new ArgumentNullException(nameof(AppId));
|
||||
|
||||
if (Server.IsNullOrEmpty() || AppId.IsNullOrEmpty()) return false;
|
||||
|
||||
if (_client == null)
|
||||
{
|
||||
//if (Server.IsNullOrEmpty()) throw new ArgumentNullException(nameof(Server));
|
||||
//if (AppId.IsNullOrEmpty()) throw new ArgumentNullException(nameof(AppId));
|
||||
|
||||
if (Server.IsNullOrEmpty() || AppId.IsNullOrEmpty()) return false;
|
||||
|
||||
if (_client == null)
|
||||
if (!AppId.IsNullOrEmpty()) _tokenFilter = new TokenHttpFilter
|
||||
{
|
||||
if (!AppId.IsNullOrEmpty()) _tokenFilter = new TokenHttpFilter
|
||||
{
|
||||
UserName = AppId,
|
||||
Password = Secret,
|
||||
ClientId = ClientId,
|
||||
};
|
||||
UserName = AppId,
|
||||
Password = Secret,
|
||||
ClientId = ClientId,
|
||||
};
|
||||
|
||||
var client = new AppClient(Server)
|
||||
{
|
||||
AppId = AppId,
|
||||
AppName = AppName,
|
||||
ClientId = ClientId,
|
||||
NodeCode = Local?.Info?.Code,
|
||||
Filter = _tokenFilter,
|
||||
UseWebSocket = true,
|
||||
|
||||
Log = Log,
|
||||
};
|
||||
|
||||
//var set = StarSetting.Current;
|
||||
//if (set.Debug) client.Log = XTrace.Log;
|
||||
|
||||
_client = client;
|
||||
|
||||
InitTracer();
|
||||
|
||||
client.Tracer = _tracer;
|
||||
client.Start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 监控中心
|
||||
private StarTracer _tracer;
|
||||
/// <summary>监控中心</summary>
|
||||
public ITracer Tracer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tracer == null)
|
||||
{
|
||||
if (!Valid()) return null;
|
||||
|
||||
InitTracer();
|
||||
}
|
||||
|
||||
return _tracer;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitTracer()
|
||||
{
|
||||
XTrace.WriteLine("初始化星尘监控中心,采样并定期上报应用性能埋点数据,包括Api接口、Http请求、数据库操作、Redis操作等。可用于监控系统健康状态,分析分布式系统的性能瓶颈。");
|
||||
|
||||
var tracer = new StarTracer(Server)
|
||||
var client = new AppClient(Server)
|
||||
{
|
||||
AppId = AppId,
|
||||
AppName = AppName,
|
||||
//Secret = Secret,
|
||||
ClientId = ClientId,
|
||||
Client = _client,
|
||||
NodeCode = Local?.Info?.Code,
|
||||
Filter = _tokenFilter,
|
||||
UseWebSocket = true,
|
||||
|
||||
Log = Log
|
||||
Log = Log,
|
||||
};
|
||||
|
||||
tracer.AttachGlobal();
|
||||
_tracer = tracer;
|
||||
}
|
||||
#endregion
|
||||
//var set = StarSetting.Current;
|
||||
//if (set.Debug) client.Log = XTrace.Log;
|
||||
|
||||
#region 配置中心
|
||||
private HttpConfigProvider _config;
|
||||
/// <summary>配置中心。务必在数据库操作和生成雪花Id之前使用激活</summary>
|
||||
/// <remarks>
|
||||
/// 文档 https://newlifex.com/blood/stardust_configcenter
|
||||
/// </remarks>
|
||||
public IConfigProvider Config
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
if (!Valid()) return null;
|
||||
_client = client;
|
||||
|
||||
XTrace.WriteLine("初始化星尘配置中心,提供集中配置管理能力,自动从配置中心加载配置数据,包括XCode数据库连接。配置中心同时支持分配应用实例的唯一WorkerId,确保Snowflake算法能够生成绝对唯一的雪花Id");
|
||||
InitTracer();
|
||||
|
||||
var config = new StarHttpConfigProvider
|
||||
{
|
||||
Server = Server,
|
||||
AppId = AppId,
|
||||
//Secret = Secret,
|
||||
ClientId = ClientId,
|
||||
Client = _client,
|
||||
};
|
||||
//if (!ClientId.IsNullOrEmpty()) config.ClientId = ClientId;
|
||||
config.Attach(_client);
|
||||
|
||||
//!! 不需要默认加载,直到首次使用配置数据时才加载。因为有可能应用并不使用配置中心,仅仅是获取这个对象。避免网络不通时的报错日志
|
||||
//config.LoadAll();
|
||||
|
||||
_config = config;
|
||||
}
|
||||
|
||||
return _config;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 注册中心
|
||||
private Boolean _initService;
|
||||
/// <summary>注册中心,服务注册与发现</summary>
|
||||
public IRegistry Service
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_initService)
|
||||
{
|
||||
if (!Valid()) return null;
|
||||
|
||||
_initService = true;
|
||||
//_appClient = _client as AppClient;
|
||||
|
||||
XTrace.WriteLine("初始化星尘注册中心,提供服务注册与发布能力");
|
||||
}
|
||||
|
||||
return _client;
|
||||
}
|
||||
client.Tracer = _tracer;
|
||||
client.Start();
|
||||
}
|
||||
|
||||
/// <summary>为指定服务创建客户端,从星尘注册中心获取服务地址。单例,应避免频繁创建客户端</summary>
|
||||
/// <param name="serviceName"></param>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
public IApiClient CreateForService(String serviceName, String tag = null) => Task.Run(() => CreateForServiceAsync(serviceName, tag)).Result;
|
||||
|
||||
/// <summary>为指定服务创建客户端,从星尘注册中心获取服务地址。单例,应避免频繁创建客户端</summary>
|
||||
/// <param name="serviceName"></param>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
public Task<IApiClient> CreateForServiceAsync(String serviceName, String tag = null) => Service.CreateForServiceAsync(serviceName, tag);
|
||||
|
||||
/// <summary>发布服务</summary>
|
||||
/// <param name="serviceName">服务名</param>
|
||||
/// <param name="address">服务地址</param>
|
||||
/// <param name="tag">特性标签</param>
|
||||
/// <param name="health">健康监测接口地址</param>
|
||||
/// <returns></returns>
|
||||
public Task<PublishServiceInfo> RegisterAsync(String serviceName, String address, String tag = null, String health = null) => Service.RegisterAsync(serviceName, address, tag, health);
|
||||
|
||||
/// <summary>消费得到服务地址信息</summary>
|
||||
/// <param name="serviceName">服务名</param>
|
||||
/// <param name="minVersion">最小版本</param>
|
||||
/// <param name="tag">特性标签。只要包含该特性的服务提供者</param>
|
||||
/// <returns></returns>
|
||||
public Task<String[]> ResolveAddressAsync(String serviceName, String minVersion = null, String tag = null) => Service.ResolveAddressAsync(serviceName, minVersion, tag);
|
||||
#endregion
|
||||
|
||||
#region 其它
|
||||
/// <summary>发送节点命令</summary>
|
||||
/// <param name="nodeCode"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="argument"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Int32> SendNodeCommand(String nodeCode, String command, String argument = null, Int32 expire = 3600)
|
||||
{
|
||||
if (!Valid()) return -1;
|
||||
|
||||
return await _client.PostAsync<Int32>("Node/SendCommand", new { Code = nodeCode, command, argument, expire });
|
||||
}
|
||||
|
||||
/// <summary>发送应用命令</summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="argument"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Int32> SendAppCommand(String appId, String command, String argument = null, Int32 expire = 3600)
|
||||
{
|
||||
if (!Valid()) return -1;
|
||||
|
||||
return await _client.PostAsync<Int32>("App/SendCommand", new { Code = appId, command, argument, expire });
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 日志
|
||||
/// <summary>日志。默认 XTrace.Log</summary>
|
||||
public ILog Log { get; set; } = XTrace.Log;
|
||||
#endregion
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 监控中心
|
||||
private StarTracer _tracer;
|
||||
/// <summary>监控中心</summary>
|
||||
public ITracer Tracer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_tracer == null)
|
||||
{
|
||||
if (!Valid()) return null;
|
||||
|
||||
InitTracer();
|
||||
}
|
||||
|
||||
return _tracer;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitTracer()
|
||||
{
|
||||
XTrace.WriteLine("初始化星尘监控中心,采样并定期上报应用性能埋点数据,包括Api接口、Http请求、数据库操作、Redis操作等。可用于监控系统健康状态,分析分布式系统的性能瓶颈。");
|
||||
|
||||
var tracer = new StarTracer(Server)
|
||||
{
|
||||
AppId = AppId,
|
||||
AppName = AppName,
|
||||
//Secret = Secret,
|
||||
ClientId = ClientId,
|
||||
Client = _client,
|
||||
|
||||
Log = Log
|
||||
};
|
||||
|
||||
tracer.AttachGlobal();
|
||||
_tracer = tracer;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 配置中心
|
||||
private HttpConfigProvider _config;
|
||||
/// <summary>配置中心。务必在数据库操作和生成雪花Id之前使用激活</summary>
|
||||
/// <remarks>
|
||||
/// 文档 https://newlifex.com/blood/stardust_configcenter
|
||||
/// </remarks>
|
||||
public IConfigProvider Config
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_config == null)
|
||||
{
|
||||
if (!Valid()) return null;
|
||||
|
||||
XTrace.WriteLine("初始化星尘配置中心,提供集中配置管理能力,自动从配置中心加载配置数据,包括XCode数据库连接。配置中心同时支持分配应用实例的唯一WorkerId,确保Snowflake算法能够生成绝对唯一的雪花Id");
|
||||
|
||||
var config = new StarHttpConfigProvider
|
||||
{
|
||||
Server = Server,
|
||||
AppId = AppId,
|
||||
//Secret = Secret,
|
||||
ClientId = ClientId,
|
||||
Client = _client,
|
||||
};
|
||||
//if (!ClientId.IsNullOrEmpty()) config.ClientId = ClientId;
|
||||
config.Attach(_client);
|
||||
|
||||
//!! 不需要默认加载,直到首次使用配置数据时才加载。因为有可能应用并不使用配置中心,仅仅是获取这个对象。避免网络不通时的报错日志
|
||||
//config.LoadAll();
|
||||
|
||||
_config = config;
|
||||
}
|
||||
|
||||
return _config;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 注册中心
|
||||
private Boolean _initService;
|
||||
/// <summary>注册中心,服务注册与发现</summary>
|
||||
public IRegistry Service
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_initService)
|
||||
{
|
||||
if (!Valid()) return null;
|
||||
|
||||
_initService = true;
|
||||
//_appClient = _client as AppClient;
|
||||
|
||||
XTrace.WriteLine("初始化星尘注册中心,提供服务注册与发布能力");
|
||||
}
|
||||
|
||||
return _client;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>为指定服务创建客户端,从星尘注册中心获取服务地址。单例,应避免频繁创建客户端</summary>
|
||||
/// <param name="serviceName"></param>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
public IApiClient CreateForService(String serviceName, String tag = null) => Task.Run(() => CreateForServiceAsync(serviceName, tag)).Result;
|
||||
|
||||
/// <summary>为指定服务创建客户端,从星尘注册中心获取服务地址。单例,应避免频繁创建客户端</summary>
|
||||
/// <param name="serviceName"></param>
|
||||
/// <param name="tag"></param>
|
||||
/// <returns></returns>
|
||||
public Task<IApiClient> CreateForServiceAsync(String serviceName, String tag = null) => Service.CreateForServiceAsync(serviceName, tag);
|
||||
|
||||
/// <summary>发布服务</summary>
|
||||
/// <param name="serviceName">服务名</param>
|
||||
/// <param name="address">服务地址</param>
|
||||
/// <param name="tag">特性标签</param>
|
||||
/// <param name="health">健康监测接口地址</param>
|
||||
/// <returns></returns>
|
||||
public Task<PublishServiceInfo> RegisterAsync(String serviceName, String address, String tag = null, String health = null) => Service.RegisterAsync(serviceName, address, tag, health);
|
||||
|
||||
/// <summary>消费得到服务地址信息</summary>
|
||||
/// <param name="serviceName">服务名</param>
|
||||
/// <param name="minVersion">最小版本</param>
|
||||
/// <param name="tag">特性标签。只要包含该特性的服务提供者</param>
|
||||
/// <returns></returns>
|
||||
public Task<String[]> ResolveAddressAsync(String serviceName, String minVersion = null, String tag = null) => Service.ResolveAddressAsync(serviceName, minVersion, tag);
|
||||
#endregion
|
||||
|
||||
#region 其它
|
||||
/// <summary>发送节点命令</summary>
|
||||
/// <param name="nodeCode"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="argument"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Int32> SendNodeCommand(String nodeCode, String command, String argument = null, Int32 expire = 3600)
|
||||
{
|
||||
if (!Valid()) return -1;
|
||||
|
||||
return await _client.PostAsync<Int32>("Node/SendCommand", new { Code = nodeCode, command, argument, expire });
|
||||
}
|
||||
|
||||
/// <summary>发送应用命令</summary>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="argument"></param>
|
||||
/// <param name="expire"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Int32> SendAppCommand(String appId, String command, String argument = null, Int32 expire = 3600)
|
||||
{
|
||||
if (!Valid()) return -1;
|
||||
|
||||
return await _client.PostAsync<Int32>("App/SendCommand", new { Code = appId, command, argument, expire });
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 日志
|
||||
/// <summary>日志。默认 XTrace.Log</summary>
|
||||
public ILog Log { get; set; } = XTrace.Log;
|
||||
#endregion
|
||||
}
|
Loading…
Reference in New Issue