using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
using NewLife;
using NewLife.Data;
using NewLife.Log;
using NewLife.Remoting.Models;
using NewLife.Serialization;
using Stardust.Models;
using XCode;
using XCode.Membership;
namespace Stardust.Data.Nodes;
/// <summary>节点在线</summary>
public partial class NodeOnline : Entity<NodeOnline>, IOnlineModel2
{
#region 对象操作
static NodeOnline()
{
var df = Meta.Factory.AdditionalFields;
df.Add(__.PingCount);
Meta.Interceptors.Add<TimeInterceptor>();
Meta.Interceptors.Add<IPInterceptor>();
Meta.Interceptors.Add<TraceInterceptor>();
var sc = Meta.SingleCache;
sc.FindSlaveKeyMethod = k => Find(_.SessionID == k);
sc.GetSlaveKeyMethod = e => e.SessionID;
}
/// <summary>校验数据</summary>
/// <param name="isNew"></param>
public override void Valid(Boolean isNew)
{
// 截取部分进程字段,避免过长无法保存
this.TrimExtraLong(__.Processes, __.MACs, __.DriveInfo);
if (!Dirtys[nameof(MemoryUsed)] && Node != null) MemoryUsed = Node.Memory - (FreeMemory > 0 ? FreeMemory : AvailableMemory);
if (!Dirtys[nameof(SpaceUsed)] && Node != null) SpaceUsed = Node.TotalSize - AvailableFreeSpace;
base.Valid(isNew);
}
#endregion
#region 扩展属性
/// <summary>节点</summary>
[XmlIgnore, ScriptIgnore]
public Node Node => Extends.Get(nameof(Node), k => Node.FindByID(NodeID));
/// <summary>节点</summary>
[Map(__.NodeID)]
public String NodeName => Node + "";
/// <summary>省份</summary>
[XmlIgnore, IgnoreDataMember]
public Area Province => Extends.Get(nameof(Province), k => Area.FindByID(ProvinceID));
/// <summary>省份名</summary>
[Map(__.ProvinceID)]
public String ProvinceName => Province + "";
/// <summary>城市</summary>
[XmlIgnore, IgnoreDataMember]
public Area City => Extends.Get(nameof(City), k => Area.FindByID(CityID));
/// <summary>城市名</summary>
[Map(__.CityID)]
public String CityName => City?.Path ?? Province?.Path;
String IOnlineModel.SessionId { get => SessionID; set => SessionID = value; }
#endregion
#region 扩展查询
/// <summary>根据id查找</summary>
/// <param name="id">会话</param>
/// <returns></returns>
public static NodeOnline FindById(Int32 id) => Find(__.ID, id);
/// <summary>根据会话查找</summary>
/// <param name="nodeId">会话</param>
/// <returns></returns>
public static NodeOnline FindByNodeId(Int32 nodeId) => Find(__.NodeID, nodeId);
/// <summary>根据会话查找</summary>
/// <param name="sessionId">会话</param>
/// <param name="cache">是否走缓存</param>
/// <returns></returns>
public static NodeOnline FindBySessionId(String sessionId, Boolean cache)
{
if (sessionId.IsNullOrEmpty()) return null;
if (!cache) return Find(_.SessionID == sessionId);
return Meta.SingleCache.GetItemWithSlaveKey(sessionId) as NodeOnline;
}
/// <summary>根据节点查找所有在线记录</summary>
/// <param name="nodeId"></param>
/// <returns></returns>
public static IList<NodeOnline> FindAllByNodeId(Int32 nodeId) => FindAll(_.NodeID == nodeId);
/// <summary>根据令牌查找</summary>
/// <param name="token">令牌</param>
/// <returns>实体列表</returns>
public static IList<NodeOnline> FindAllByToken(String token)
{
if (token.IsNullOrEmpty()) return new List<NodeOnline>();
// 实体缓存
if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.Token.EqualIgnoreCase(token));
return FindAll(_.Token == token);
}
/// <summary>根据省份、城市查找</summary>
/// <param name="provinceId">省份</param>
/// <param name="cityId">城市</param>
/// <returns>实体列表</returns>
public static IList<NodeOnline> FindAllByProvinceIDAndCityID(Int32 provinceId, Int32 cityId)
{
// 实体缓存
if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.ProvinceID == provinceId && e.CityID == cityId);
return FindAll(_.ProvinceID == provinceId & _.CityID == cityId);
}
/// <summary>根据项目查找</summary>
/// <param name="projectId">项目</param>
/// <returns>实体列表</returns>
public static IList<NodeOnline> FindAllByProjectId(Int32 projectId)
{
if (projectId <= 0) return new List<NodeOnline>();
// 实体缓存
if (Meta.Session.Count < 1000) return Meta.Cache.FindAll(e => e.ProjectId == projectId);
return FindAll(_.ProjectId == projectId);
}
#endregion
#region 高级查询
/// <summary>查询满足条件的记录集,分页、排序</summary>
/// <param name="nodeId">节点</param>
/// <param name="provinceId">省份</param>
/// <param name="cityId">城市</param>
/// <param name="category">类别</param>
/// <param name="start">开始时间</param>
/// <param name="end">结束时间</param>
/// <param name="key">关键字</param>
/// <param name="page">分页排序参数,同时返回满足条件的总记录数</param>
/// <returns>实体集</returns>
public static IList<NodeOnline> Search(Int32 projectId, Int32 nodeId, Int32 provinceId, Int32 cityId, String category, DateTime start, DateTime end, String key, PageParameter page)
{
var exp = new WhereExpression();
if (projectId >= 0) exp &= _.ProjectId == projectId;
if (nodeId >= 0) exp &= _.NodeID == nodeId;
if (provinceId >= 0) exp &= _.ProvinceID == provinceId;
if (cityId >= 0) exp &= _.CityID == cityId;
if (!category.IsNullOrEmpty()) exp &= _.Category == category;
exp &= _.CreateTime.Between(start, end);
if (!key.IsNullOrEmpty()) exp &= _.Name.Contains(key) | _.Data.Contains(key) | _.SessionID.Contains(key);
return FindAll(exp, page);
}
/// <summary>根据产品,分组统计在线数</summary>
/// <returns></returns>
public static IDictionary<Int32, Int32> SearchGroupByProvince()
{
var list = FindAll(_.ProvinceID.GroupBy(), null, _.ID.Count() & _.ProvinceID);
return list.ToDictionary(e => e.ProvinceID, e => e.ID);
}
#endregion
#region 业务操作
/// <summary>根据编码查询或添加</summary>
/// <param name="sessionId"></param>
/// <returns></returns>
public static NodeOnline GetOrAdd(String sessionId) => GetOrAdd(sessionId, FindBySessionId, k => new NodeOnline { SessionID = k });
/// <summary>删除过期,指定过期时间</summary>
/// <param name="expire">超时时间,秒</param>
/// <returns></returns>
public static IList<NodeOnline> ClearExpire(TimeSpan expire)
{
if (Meta.Count == 0) return null;
// 10分钟不活跃将会被删除
var exp = _.UpdateTime < DateTime.Now.Subtract(expire);
var list = FindAll(exp, null, null, 0, 0);
list.Delete();
return list;
}
///// <summary>更新并保存在线状态</summary>
///// <param name="di"></param>
///// <param name="pi"></param>
///// <param name="token"></param>
///// <param name="ip"></param>
//public void Save(NodeInfo di, PingInfo pi, String token, String ip)
//{
// var olt = this;
// if (di != null)
// {
// olt.Fill(di);
// olt.LocalTime = di.Time.ToLocalTime();
// olt.MACs = di.Macs;
// //olt.COMs = di.COMs;
// }
// else
// {
// olt.Fill(pi);
// olt.CreateData(pi, ip);
// }
// olt.Token = token;
// olt.PingCount++;
// olt.UpdateIP = ip;
// olt.TraceId = DefaultSpan.Current?.TraceId;
// // 5秒内直接保存
// if (olt.CreateTime.AddSeconds(5) > DateTime.Now)
// olt.Save();
// else
// olt.SaveAsync();
//}
/// <summary>填充节点信息</summary>
/// <param name="inf"></param>
public void Fill(NodeInfo inf)
{
var online = this;
online.LocalTime = inf.Time.ToLocalTime();
online.MACs = inf.Macs;
//online.COMs = di.COMs;
online.IP = inf.IP;
online.Gateway = inf.Gateway;
online.Dns = inf.Dns;
if (inf.AvailableMemory > 0) online.AvailableMemory = (Int32)(inf.AvailableMemory / 1024 / 1024);
if (inf.FreeMemory > 0) online.FreeMemory = (Int32)(inf.FreeMemory / 1024 / 1024);
MemoryUsed = online.Memory - (online.FreeMemory > 0 ? online.FreeMemory : online.AvailableMemory);
if (inf.AvailableFreeSpace > 0) online.AvailableFreeSpace = (Int32)(inf.AvailableFreeSpace / 1024 / 1024);
if (!online.DriveInfo.IsNullOrEmpty()) online.DriveInfo = online.DriveInfo;
}
/// <summary>填充在线节点信息</summary>
/// <param name="inf"></param>
private void Fill(PingInfo inf)
{
var online = this;
if (inf.AvailableMemory > 0) online.AvailableMemory = (Int32)(inf.AvailableMemory / 1024 / 1024);
if (inf.FreeMemory > 0) online.FreeMemory = (Int32)(inf.FreeMemory / 1024 / 1024);
MemoryUsed = online.Memory - (online.FreeMemory > 0 ? online.FreeMemory : online.AvailableMemory);
if (inf.AvailableFreeSpace > 0) online.AvailableFreeSpace = (Int32)(inf.AvailableFreeSpace / 1024 / 1024);
if (!inf.DriveInfo.IsNullOrEmpty()) online.DriveInfo = inf.DriveInfo;
if (inf.CpuRate > 0) online.CpuRate = inf.CpuRate;
if (inf.Temperature > 0) online.Temperature = inf.Temperature;
if (inf.Battery > 0) online.Battery = inf.Battery;
/*if (inf.Signal > 0)*/
online.Signal = inf.Signal;
if (inf.UplinkSpeed > 0) online.UplinkSpeed = (Int64)inf.UplinkSpeed;
if (inf.DownlinkSpeed > 0) online.DownlinkSpeed = (Int64)inf.DownlinkSpeed;
if (inf.SystemLoad > 0) online.SystemLoad = inf.SystemLoad;
if (inf.DiskIOPS > 0) online.DiskIOPS = inf.DiskIOPS;
if (inf.DiskActiveTime > 0) online.DiskActiveTime = inf.DiskActiveTime;
if (inf.ProcessCount > 0) online.ProcessCount = inf.ProcessCount;
if (inf.TcpConnections > 0) online.TcpConnections = inf.TcpConnections;
if (inf.TcpTimeWait > 0) online.TcpTimeWait = inf.TcpTimeWait;
if (inf.TcpCloseWait > 0) online.TcpCloseWait = inf.TcpCloseWait;
if (inf.IntranetScore > 0) online.IntranetScore = inf.IntranetScore;
if (inf.InternetScore > 0) online.InternetScore = inf.InternetScore;
if (inf.GatewayLatency > 0) online.GatewayLatency = inf.GatewayLatency;
if (inf.GatewayLossRate > 0) online.GatewayLossRate = inf.GatewayLossRate;
if (inf.DnsLatency > 0) online.DnsLatency = inf.DnsLatency;
if (inf.DnsLossRate > 0) online.DnsLossRate = inf.DnsLossRate;
if (inf.ServerLatency > 0) online.ServerLatency = inf.ServerLatency;
if (inf.ServerLossRate > 0) online.ServerLossRate = inf.ServerLossRate;
if (inf.Uptime > 0) online.Uptime = inf.Uptime;
if (inf.Delay > 0) online.Delay = inf.Delay;
var dt = inf.Time.ToDateTime().ToLocalTime();
if (dt.Year > 2000)
{
online.LocalTime = dt;
//olt.Offset = (Int32)Math.Round((dt - DateTime.Now).TotalSeconds);
online.Offset = (Int32)(inf.Time + (Delay / 2) - DateTime.UtcNow.ToLong());
}
if (!inf.Processes.IsNullOrEmpty()) online.Processes = inf.Processes;
if (!inf.Macs.IsNullOrEmpty()) online.MACs = inf.Macs;
//if (!inf.COMs.IsNullOrEmpty()) olt.COMs = inf.COMs;
if (!inf.IP.IsNullOrEmpty()) online.IP = inf.IP;
if (!inf.Gateway.IsNullOrEmpty()) online.Gateway = inf.Gateway;
//olt.Data = inf.ToJson();
var dic = inf.ToDictionary();
dic.Remove("Processes");
online.Data = dic.ToJson();
}
private void CreateData(PingInfo inf, String ip)
{
var olt = this;
var dt = inf.Time.ToDateTime().ToLocalTime();
// 插入节点数据
var data = new NodeData
{
NodeID = olt.NodeID,
Name = olt.Name,
AvailableMemory = olt.AvailableMemory,
FreeMemory = olt.FreeMemory,
AvailableFreeSpace = olt.AvailableFreeSpace,
CpuRate = inf.CpuRate,
SystemLoad = inf.SystemLoad,
Temperature = inf.Temperature,
Battery = inf.Battery,
Signal = inf.Signal,
UplinkSpeed = (Int64)inf.UplinkSpeed,
DownlinkSpeed = (Int64)inf.DownlinkSpeed,
DiskIOPS = inf.DiskIOPS,
DiskActiveTime = inf.DiskActiveTime,
ProcessCount = inf.ProcessCount,
TcpConnections = inf.TcpConnections,
TcpTimeWait = inf.TcpTimeWait,
TcpCloseWait = inf.TcpCloseWait,
IntranetScore = inf.IntranetScore,
InternetScore = inf.InternetScore,
GatewayLatency = inf.GatewayLatency,
GatewayLossRate = inf.GatewayLossRate,
DnsLatency = inf.DnsLatency,
DnsLossRate = inf.DnsLossRate,
ServerLatency = inf.ServerLatency,
ServerLossRate = inf.ServerLossRate,
Uptime = inf.Uptime,
Delay = inf.Delay,
LocalTime = dt,
Offset = olt.Offset,
TraceId = DefaultSpan.Current?.TraceId,
CreateIP = ip,
Creator = Environment.MachineName,
};
//data.SaveAsync();
data.Insert();
}
public Int32 Save(IPingRequest request, Object context)
{
if (context is DeviceContext ctx)
{
Token = ctx.Token;
UpdateIP = ctx.UserHost;
if (ctx.Device is Node node)
{
Name = node.Name;
Category = node.Category;
Version = node.Version;
CompileTime = node.CompileTime;
OSKind = node.OSKind;
//Save(null, inf, context.Token, ip);
}
if (request is PingInfo ping)
{
Fill(ping);
CreateData(ping, ctx.UserHost);
}
}
PingCount++;
//return SaveAsync() ? 1 : 0;
return Save();
}
#endregion
}
|