コード例 #1
0
ファイル: ClientDataSet.cs プロジェクト: sky365365/NtMiner
        public ClientDataSet(IMinerRedis minerRedis, ISpeedDataRedis speedDataRedis, IMinerClientMqSender mqSender) : base(isPull: false, getDatas: callback => {
            var getMinersTask = minerRedis.GetAllAsync();
            var getSpeedsTask = speedDataRedis.GetAllAsync();
            Task.WhenAll(getMinersTask, getSpeedsTask).ContinueWith(t => {
                NTMinerConsole.UserInfo($"从redis加载了 {getMinersTask.Result.Count} 条MinerData,和 {getSpeedsTask.Result.Count} 条SpeedData");
                var speedDatas = getSpeedsTask.Result;
                List <ClientData> clientDatas = new List <ClientData>();
                DateTime speedOn = DateTime.Now.AddMinutes(-3);
                foreach (var minerData in getMinersTask.Result)
                {
                    var clientData = ClientData.Create(minerData);
                    // 该属性没有持久化而只在内存中,启动时将该属性值视为当前日期的前一天的零时加上CreatedOn的时间,别处有个周期清理7天不活跃矿机的任务
                    clientData.MinerActiveOn = DateTime.Today.AddDays(-1) + minerData.CreatedOn.TimeOfDay;
                    clientDatas.Add(clientData);
                    var speedData = speedDatas.FirstOrDefault(a => a.ClientId == minerData.ClientId);
                    if (speedData != null && speedData.SpeedOn > speedOn)
                    {
                        clientData.Update(speedData, out bool _);
                    }
                }
                callback?.Invoke(clientDatas);
            });
        }) {
            _minerRedis     = minerRedis;
            _speedDataRedis = speedDataRedis;
            _mqSender       = mqSender;
            VirtualRoot.BuildEventPath <Per1MinuteEvent>("周期清理Redis中不活跃的来自挖矿端上报的算力记录", LogEnum.DevConsole, path: message => {
                DateTime time     = message.BornOn.AddSeconds(-130);
                var toRemoveSpeed = _dicByClientId.Where(a => a.Value.MinerActiveOn != DateTime.MinValue && a.Value.MinerActiveOn <= time).ToArray();
                _speedDataRedis.DeleteByClientIdsAsync(toRemoveSpeed.Select(a => a.Key).ToArray());

                // 删除一周没有活跃过的客户端
                time = message.BornOn.AddDays(-7);
                var toRemoveClient = _dicByObjectId.Where(a => a.Value.MinerActiveOn <= time).ToArray();
                foreach (var kv in toRemoveClient)
                {
                    base.RemoveByObjectId(kv.Key);
                }
            }, this.GetType());
            // 收到Mq消息之前一定已经初始化完成,因为Mq消费者在ClientSetInitedEvent事件之后才会创建
            VirtualRoot.BuildEventPath <SpeedDataMqMessage>("收到SpeedDataMq消息后更新ClientData内存", LogEnum.None, path: message => {
                if (message.AppId == ServerRoot.HostConfig.ThisServerAddress)
                {
                    return;
                }
                if (message.ClientId == Guid.Empty)
                {
                    return;
                }
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(_safeIgnoreMessage);
                    return;
                }
                speedDataRedis.GetByClientIdAsync(message.ClientId).ContinueWith(t => {
                    ReportSpeed(t.Result.SpeedDto, message.MinerIp, isFromWsServerNode: true);
                });
            }, this.GetType());
            VirtualRoot.BuildEventPath <MinerClientWsOpenedMqMessage>("收到MinerClientWsOpenedMq消息后更新NetActiveOn和IsOnline", LogEnum.None, path: message => {
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(_safeIgnoreMessage);
                    return;
                }
                if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
                {
                    clientData.NetActiveOn = message.Timestamp;
                    clientData.IsOnline    = true;
                }
            }, this.GetType());
            VirtualRoot.BuildEventPath <MinerClientWsClosedMqMessage>("收到MinerClientWsClosedMq消息后更新NetActiveOn和IsOnline", LogEnum.None, path: message => {
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(_safeIgnoreMessage);
                    return;
                }
                if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
                {
                    clientData.NetActiveOn = message.Timestamp;
                    clientData.IsOnline    = false;
                }
            }, this.GetType());
            VirtualRoot.BuildEventPath <MinerClientWsBreathedMqMessage>("收到MinerClientWsBreathedMq消息后更新NetActiveOn", LogEnum.None, path: message => {
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(_safeIgnoreMessage);
                    return;
                }
                if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
                {
                    clientData.NetActiveOn = message.Timestamp;
                    clientData.IsOnline    = true;
                }
            }, this.GetType());
            VirtualRoot.BuildCmdPath <ChangeMinerSignMqMessage>(path: message => {
                if (_dicByObjectId.TryGetValue(message.Data.Id, out ClientData clientData))
                {
                    clientData.Update(message.Data, out bool isChanged);
                    if (isChanged)
                    {
                        var minerData = MinerData.Create(clientData);
                        _minerRedis.SetAsync(minerData).ContinueWith(t => {
                            _mqSender.SendMinerSignChanged(minerData.Id);
                        });
                    }
                }
                else
                {
                    // 此时该矿机是第一次在服务端出现
                    NTMinerConsole.UserWarn("该矿机首次出现于WsServer:" + VirtualRoot.JsonSerializer.Serialize(message.Data));
                    clientData                    = ClientData.Create(MinerData.Create(message.Data));
                    clientData.NetActiveOn        = DateTime.Now;
                    clientData.IsOnline           = true;
                    clientData.IsOuterUserEnabled = true;
                    Add(clientData);
                }
            }, this.GetType(), LogEnum.None);
        }
コード例 #2
0
 public ClientDataSet(IMinerRedis minerRedis, ISpeedDataRedis speedDataRedis, IMinerClientMqSender mqSender) : base(isPull: false, getDatas: callback => {
     var getMinersTask = minerRedis.GetAllAsync();
     var getSpeedsTask = speedDataRedis.GetAllAsync();
     Task.WhenAll(getMinersTask, getSpeedsTask).ContinueWith(t => {
         var speedDatas = getSpeedsTask.Result;
         List <ClientData> clientDatas = new List <ClientData>();
         foreach (var minerData in getMinersTask.Result)
         {
             var clientData = ClientData.Create(minerData);
             clientDatas.Add(clientData);
             var speedData = speedDatas.FirstOrDefault(a => a.ClientId == minerData.ClientId);
             if (speedData != null)
             {
                 clientData.Update(speedData);
             }
         }
         callback?.Invoke(clientDatas);
     });
 }) {
     _minerRedis     = minerRedis;
     _speedDataRedis = speedDataRedis;
     _mqSender       = mqSender;
     // 收到Mq消息之前一定已经初始化完成,因为Mq消费者在ClientSetInitedEvent事件之后才会创建
     VirtualRoot.AddEventPath <SpeedDataMqMessage>("收到SpeedDataMq消息后更新ClientData内存", LogEnum.None, action: message => {
         if (message.AppId == ServerRoot.HostConfig.ThisServerAddress)
         {
             return;
         }
         if (message.ClientId == Guid.Empty)
         {
             return;
         }
         if (IsOldMqMessage(message.Timestamp))
         {
             Write.UserOk(_safeIgnoreMessage);
             return;
         }
         speedDataRedis.GetByClientIdAsync(message.ClientId).ContinueWith(t => {
             ReportSpeed(t.Result, message.MinerIp, isFromWsServerNode: true);
         });
     }, this.GetType());
     VirtualRoot.AddEventPath <MinerClientWsOpenedMqMessage>("收到MinerClientWsOpenedMq消息后更新NetActiveOn和IsOnline", LogEnum.None, action: message => {
         if (IsOldMqMessage(message.Timestamp))
         {
             Write.UserOk(_safeIgnoreMessage);
             return;
         }
         if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
         {
             clientData.NetActiveOn = message.Timestamp;
             clientData.IsOnline    = true;
         }
     }, this.GetType());
     VirtualRoot.AddEventPath <MinerClientWsClosedMqMessage>("收到MinerClientWsClosedMq消息后更新NetActiveOn和IsOnline", LogEnum.None, action: message => {
         if (IsOldMqMessage(message.Timestamp))
         {
             Write.UserOk(_safeIgnoreMessage);
             return;
         }
         if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
         {
             clientData.NetActiveOn = message.Timestamp;
             clientData.IsOnline    = false;
         }
     }, this.GetType());
     VirtualRoot.AddEventPath <MinerClientWsBreathedMqMessage>("收到MinerClientWsBreathedMq消息后更新NetActiveOn", LogEnum.None, action: message => {
         if (IsOldMqMessage(message.Timestamp))
         {
             Write.UserOk(_safeIgnoreMessage);
             return;
         }
         if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
         {
             clientData.NetActiveOn = message.Timestamp;
             clientData.IsOnline    = true;
         }
     }, this.GetType());
     VirtualRoot.AddCmdPath <ChangeMinerSignMqMessage>(action: message => {
         if (_dicByObjectId.TryGetValue(message.Data.Id, out ClientData clientData))
         {
             clientData.Update(message.Data, out bool isChanged);
             if (isChanged)
             {
                 var minerData = MinerData.Create(clientData);
                 _minerRedis.SetAsync(minerData).ContinueWith(t => {
                     _mqSender.SendMinerSignChanged(minerData.Id);
                 });
             }
         }
         else
         {
             Add(ClientData.Create(MinerData.Create(message.Data)));
         }
     }, this.GetType(), LogEnum.DevConsole);
 }
コード例 #3
0
        public ClientDataSet(IMinerRedis minerRedis, ISpeedDataRedis speedDataRedis, IMinerClientMqSender mqSender) : base(isPull: false, getDatas: callback => {
            var getMinersTask = minerRedis.GetAllAsync();
            var getSpeedsTask = speedDataRedis.GetAllAsync();
            Task.WhenAll(getMinersTask, getSpeedsTask).ContinueWith(t => {
                NTMinerConsole.UserInfo($"从redis加载了 {getMinersTask.Result.Count} 条MinerData,和 {getSpeedsTask.Result.Count} 条SpeedData");
                var speedDatas = getSpeedsTask.Result;
                List <ClientData> clientDatas = new List <ClientData>();
                DateTime speedOn = DateTime.Now.AddMinutes(-3);
                foreach (var minerData in getMinersTask.Result)
                {
                    var clientData = ClientData.Create(minerData);
                    // 该属性没有持久化而只在内存中,启动时将该属性值视为当前日期的前一天的零时加上CreatedOn
                    // 的时间从而将数据分散开来从而滑动清理,后面有个周期清理7天不活跃矿机的任务。WebApiServer启动后第6天才会进行第一次清理。
                    clientData.MinerActiveOn = DateTime.Today.AddDays(-1) + minerData.CreatedOn.TimeOfDay;
                    clientDatas.Add(clientData);
                    var speedData = speedDatas.FirstOrDefault(a => a.ClientId == minerData.ClientId);
                    if (speedData != null && speedData.SpeedOn > speedOn)
                    {
                        clientData.Update(speedData, out bool _);
                    }
                }
                callback?.Invoke(clientDatas);
            });
        }) {
            _minerRedis     = minerRedis;
            _speedDataRedis = speedDataRedis;
            _mqSender       = mqSender;
            VirtualRoot.BuildEventPath <Per1MinuteEvent>("周期清理Redis中不活跃的来自挖矿端上报的算力记录", LogEnum.DevConsole, path: message => {
                DateTime time     = message.BornOn.AddSeconds(-130);
                var toRemoveSpeed = _dicByClientId.Where(a => a.Value.MinerActiveOn != DateTime.MinValue && a.Value.MinerActiveOn <= time).ToArray();
                _speedDataRedis.DeleteByClientIdsAsync(toRemoveSpeed.Select(a => a.Key).ToArray());

                // 删除一段时间没有活跃过的客户端
                const int nDay       = 7;
                DateTime netActiveOn = message.BornOn.AddSeconds(-30);
                time = message.BornOn.AddDays(-nDay);
                var toRemoveClient = _dicByObjectId.Where(a => a.Value.MinerActiveOn <= time && a.Value.NetActiveOn <= netActiveOn).ToArray();
                if (toRemoveClient.Length > 0)
                {
                    NTMinerConsole.UserOk($"{toRemoveClient.Length.ToString()} 台矿机因 {nDay.ToString()} 天没有活跃,删除对应记录");
                    foreach (var kv in toRemoveClient)
                    {
                        base.RemoveByObjectId(kv.Key);
                    }
                }
            }, this.GetType());
            // 收到Mq消息之前一定已经初始化完成,因为Mq消费者在ClientSetInitedEvent事件之后才会创建
            VirtualRoot.BuildEventPath <SpeedDataMqMessage>("收到SpeedDataMq消息后更新ClientData内存", LogEnum.None, path: message => {
                if (message.AppId == ServerRoot.HostConfig.ThisServerAddress)
                {
                    return;
                }
                if (message.ClientId == Guid.Empty)
                {
                    return;
                }
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(nameof(SpeedDataMqMessage) + ":" + MqKeyword.SafeIgnoreMessage);
                    return;
                }
                speedDataRedis.GetByClientIdAsync(message.ClientId).ContinueWith(t => {
                    ReportSpeed(t.Result.SpeedDto, message.MinerIp, isFromWsServerNode: true);
                });
            }, this.GetType());
            VirtualRoot.BuildEventPath <MinerClientWsOpenedMqMessage>("收到MinerClientWsOpenedMq消息后更新NetActiveOn和IsOnline", LogEnum.None, path: message => {
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(nameof(MinerClientWsOpenedMqMessage) + ":" + MqKeyword.SafeIgnoreMessage);
                    return;
                }
                if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
                {
                    clientData.NetActiveOn = message.Timestamp;
                    clientData.IsOnline    = true;
                }
            }, this.GetType());
            VirtualRoot.BuildEventPath <MinerClientWsClosedMqMessage>("收到MinerClientWsClosedMq消息后更新NetActiveOn和IsOnline", LogEnum.None, path: message => {
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(nameof(MinerClientWsClosedMqMessage) + ":" + MqKeyword.SafeIgnoreMessage);
                    return;
                }
                if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
                {
                    clientData.NetActiveOn = message.Timestamp;
                    clientData.IsOnline    = false;
                }
            }, this.GetType());
            VirtualRoot.BuildEventPath <MinerClientWsBreathedMqMessage>("收到MinerClientWsBreathedMq消息后更新NetActiveOn", LogEnum.None, path: message => {
                if (IsOldMqMessage(message.Timestamp))
                {
                    NTMinerConsole.UserOk(nameof(MinerClientWsBreathedMqMessage) + ":" + MqKeyword.SafeIgnoreMessage);
                    return;
                }
                if (_dicByClientId.TryGetValue(message.ClientId, out ClientData clientData))
                {
                    clientData.NetActiveOn = message.Timestamp;
                    clientData.IsOnline    = true;
                }
            }, this.GetType());
            VirtualRoot.BuildCmdPath <ChangeMinerSignMqMessage>(path: message => {
                if (_dicByObjectId.TryGetValue(message.Data.Id, out ClientData clientData))
                {
                    clientData.Update(message.Data, out bool isChanged);
                    if (isChanged)
                    {
                        var minerData = MinerData.Create(clientData);
                        _minerRedis.SetAsync(minerData).ContinueWith(t => {
                            _mqSender.SendMinerSignChanged(minerData.Id);
                        });
                    }
                }
                else
                {
                    clientData = ClientData.Create(MinerData.Create(message.Data));
                    Add(clientData);
                }
                clientData.NetActiveOn        = DateTime.Now;
                clientData.IsOnline           = true;
                clientData.IsOuterUserEnabled = true;
            }, this.GetType(), LogEnum.None);
            VirtualRoot.BuildCmdPath <QueryClientsForWsMqMessage>(path: message => {
                QueryClientsResponse response = AppRoot.QueryClientsForWs(message.Query);
                _mqSender.SendResponseClientsForWs(message.AppId, message.LoginName, message.SessionId, response);
            }, this.GetType(), LogEnum.None);
        }