完成第二个例程,节点管理
大石头 authored at 2024-06-30 00:30:55
2.94 KiB
NewLife.Remoting
using NewLife;
using NewLife.Log;
using NewLife.Remoting.Extensions.Services;
using NewLife.Threading;
using Zero.Data.Nodes;

namespace ZeroServer.Services;

/// <summary>节点在线服务</summary>
public class NodeOnlineService : IHostedService
{
    #region 属性
    private TimerX _timer;
    private readonly IDeviceService _nodeService;
    private readonly IoTSetting _setting;
    private readonly ITracer _tracer;
    #endregion

    #region 构造
    /// <summary>
    /// 实例化节点在线服务
    /// </summary>
    /// <param name="nodeService"></param>
    /// <param name="setting"></param>
    /// <param name="tracer"></param>
    public NodeOnlineService(IDeviceService nodeService, IoTSetting setting, ITracer tracer)
    {
        _nodeService = nodeService;
        _setting = setting;
        _tracer = tracer;
    }
    #endregion

    #region 方法
    /// <summary>
    /// 开始服务
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new TimerX(CheckOnline, null, 5_000, 30_000) { Async = true };

        return Task.CompletedTask;
    }

    /// <summary>
    /// 停止服务
    /// </summary>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer.TryDispose();

        return Task.CompletedTask;
    }

    private void CheckOnline(Object state)
    {
        // 节点超时
        if (_setting.SessionTimeout > 0)
        {
            using var span = _tracer?.NewSpan(nameof(CheckOnline));

            var rs = NodeOnline.ClearExpire(TimeSpan.FromSeconds(_setting.SessionTimeout));
            if (rs != null)
                foreach (var olt in rs)
                {
                    var node = olt?.Node;
                    var msg = $"[{node}]登录于{olt.CreateTime.ToFullString()},最后活跃于{olt.UpdateTime.ToFullString()}";
                    _nodeService.WriteHistory(node, "超时下线", true, msg, olt.CreateIP);

                    if (_nodeService is NodeService ds)
                        ds.RemoveOnline(olt.NodeId, olt.CreateIP);

                    if (node != null)
                    {
                        // 计算在线时长
                        if (olt.CreateTime.Year > 2000 && olt.UpdateTime.Year > 2000)
                        {
                            node.OnlineTime += (Int32)(olt.UpdateTime - olt.CreateTime).TotalSeconds;
                            node.Update();
                        }

                        CheckOffline(node, "超时下线");
                    }
                }
        }
    }

    /// <summary>
    /// 检查离线
    /// </summary>
    /// <param name="node"></param>
    /// <param name="reason"></param>
    public static void CheckOffline(Node node, String reason)
    {
        //todo 下线告警
    }
    #endregion
}