Upgrade Nuget
大石头 authored at 2024-11-20 14:03:58
2.84 KiB
NewLife.Remoting
using NewLife;
using NewLife.Log;
using NewLife.Remoting.Extensions.Models;
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 ITokenSetting _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, ITokenSetting 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) return;

        using var span = _tracer?.NewSpan(nameof(CheckOnline));

        var rs = NodeOnline.ClearExpire(TimeSpan.FromSeconds(_setting.SessionTimeout));
        if (rs == null) return;

        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
}