anycmd 4 anos atrás
pai
commit
6a911d4f0e
52 arquivos alterados com 498 adições e 134 exclusões
  1. 2 2
      README.md
  2. 2 0
      src/AppModels/AppModels.csproj
  3. 4 0
      src/AppModels/AppStatic.cs
  4. 5 0
      src/AppModels/MinerStudio/Messages.cs
  5. 58 0
      src/AppModels/MinerStudio/Vms/MqCountViewModel.cs
  6. 71 0
      src/AppModels/MinerStudio/Vms/MqCountsPageViewModel.cs
  7. 5 0
      src/AppViews0/AppViewFactory.cs
  8. 11 0
      src/AppViews0/AppViews0.csproj
  9. 2 0
      src/AppViews0/MinerStudio/Views/Design/MqCountsPageViewModel.xaml
  10. 1 1
      src/AppViews0/MinerStudio/Views/Ucs/CalcConfig.xaml.cs
  11. 1 1
      src/AppViews0/MinerStudio/Views/Ucs/MinerClient.xaml.cs
  12. 90 0
      src/AppViews0/MinerStudio/Views/Ucs/MqCountsPage.xaml
  13. 47 0
      src/AppViews0/MinerStudio/Views/Ucs/MqCountsPage.xaml.cs
  14. 1 1
      src/AppViews0/Views/Ucs/Calc.xaml.cs
  15. 10 0
      src/AppViews0/Views/Ucs/MainMenu.xaml
  16. 1 1
      src/AppViews0/Views/Ucs/MinerProfileDual.xaml.cs
  17. 1 1
      src/AppViews0/Views/Ucs/MinerProfileIndex.xaml.cs
  18. 1 1
      src/AppViews0/Views/Ucs/SpeedCharts.xaml.cs
  19. 1 1
      src/AppViews0/Views/Ucs/StateBar.xaml.cs
  20. 1 1
      src/AppViews0/Views/Ucs/Toolbox.xaml.cs
  21. 0 11
      src/NTMiner.Controllers/IClientDataBinaryController`1.cs
  22. 0 4
      src/NTMiner.Controllers/IClientDataController.cs
  23. 0 1
      src/NTMiner.Controllers/NTMiner.Controllers.csproj
  24. 9 3
      src/NTMinerDataSchemas/Core/MinerServer/QueryClientsForWsRequest.cs
  25. 29 0
      src/NTMinerDataSchemas/Core/MinerServer/QueryClientsResponseEx.cs
  26. 1 0
      src/NTMinerDataSchemas/NTMinerDataSchemas.csproj
  27. 1 0
      src/NTMinerDataSchemas/Ws/WsMessage.cs
  28. 0 1
      src/NTMinerRpcClient/NTMinerRpcClient.csproj
  29. 0 25
      src/NTMinerRpcClient/Services/Official/ClientDataBinaryService.cs
  30. 0 12
      src/NTMinerRpcClient/Services/Official/ClientDataService.cs
  31. 0 1
      src/NTMinerRpcClient/Services/OfficialServices.cs
  32. 16 0
      src/NTMinerServer/Core/Messages.cs
  33. 17 0
      src/NTMinerServer/Core/Mq/MinerClientMqBodyUtil.cs
  34. 1 0
      src/NTMinerServer/Core/Mq/MqMessagePaths/ReadOnlyUserMqMessagePath.cs
  35. 2 0
      src/NTMinerServer/MqKeyword.cs
  36. 1 0
      src/NTMinerWpf/Styles/KbIcons.xaml
  37. 1 1
      src/NTMinerWpf/WindowExtension.cs
  38. 16 0
      src/WebApiServer/AppRoot.cs
  39. 1 1
      src/WebApiServer/CloudFileUrlGenerater/Impl/QiniuCloudKodoFileUrlGenerater.cs
  40. 0 20
      src/WebApiServer/Controllers/ClientDataBinaryController.cs
  41. 0 30
      src/WebApiServer/Controllers/ClientDataController.cs
  42. 9 0
      src/WebApiServer/Core/Impl/ClientDataSet.cs
  43. 1 0
      src/WebApiServer/Core/Impl/UserSet.cs
  44. 8 0
      src/WebApiServer/Core/Mq/MqMessagePaths/MinerClientMqMessagePath.cs
  45. 1 0
      src/WebApiServer/Core/Mq/Senders/IMinerClientMqSender.cs
  46. 14 0
      src/WebApiServer/Core/Mq/Senders/Impl/MinerClientMqSender.cs
  47. 0 1
      src/WebApiServer/WebApiServer.csproj
  48. 13 0
      src/WsServer/Core/Mq/MqMessagePaths/MinerClientMqMessagePath.cs
  49. 2 4
      src/WsServer/Core/Mq/Senders/IMinerClientMqSender.cs
  50. 16 8
      src/WsServer/Core/Mq/Senders/Impl/MinerClientMqSender.cs
  51. 17 0
      src/WsServer/MqBufferRoot.cs
  52. 7 1
      src/WsServer/WsMessageFromMinerStudioHandler.cs

+ 2 - 2
README.md

@@ -1,4 +1,4 @@
-点击加入 [NTMiner官方QQ群](https://jq.qq.com/?_wv=1027&k=UbEWSFc2): 697539304
+点击加入 [NTMiner官方QQ群](https://jq.qq.com/?_wv=1027&k=9hzcGl8W): 697539304
 
 1. 开源矿工内置的所有内核均为原版,开源矿工永远不会额外增加矿工支出;
 2. 开源矿工永远开源;
@@ -34,7 +34,7 @@
 
 类似开源矿工这些同类挖矿辅助工具降低了挖矿门槛帮助矿工管理矿机,获得一点收入是合理的,但是不能偷。
 
-点击加入 [NTMiner官方QQ群](https://jq.qq.com/?_wv=1027&k=UbEWSFc2): 697539304
+点击加入 [NTMiner官方QQ群](https://jq.qq.com/?_wv=1027&k=9hzcGl8W): 697539304
 
 # 授权协议
 The LGPL license。

+ 2 - 0
src/AppModels/AppModels.csproj

@@ -114,6 +114,8 @@
     <Compile Include="MinerStudio\Impl\ServerMinerStudioService.cs" />
     <Compile Include="MinerStudio\IServerMinerStudioService.cs" />
     <Compile Include="MinerStudio\Vms\LocalIpConfigViewModel.cs" />
+    <Compile Include="MinerStudio\Vms\MqCountsPageViewModel.cs" />
+    <Compile Include="MinerStudio\Vms\MqCountViewModel.cs" />
     <Compile Include="MinerStudio\Vms\MqReceivedCountViewModel.cs" />
     <Compile Include="MinerStudio\Vms\MqSendCountViewModel.cs" />
     <Compile Include="MinerStudio\Vms\NTMinerFileSelectViewModel.cs" />

+ 4 - 0
src/AppModels/AppStatic.cs

@@ -589,6 +589,10 @@ namespace NTMiner {
             VirtualRoot.Execute(new ShowActionCountPageCommand());
         });
 
+        public static ICommand ShowMqCountsPage { get; private set; } = new DelegateCommand(() => {
+            VirtualRoot.Execute(new ShowMqCountsPageCommand());
+        });
+
         public static ICommand ShowChangePassword { get; private set; } = new DelegateCommand(() => {
             VirtualRoot.Execute(new ShowChangePassword());
         });

+ 5 - 0
src/AppModels/MinerStudio/Messages.cs

@@ -26,6 +26,11 @@ namespace NTMiner.MinerStudio {
         public ShowActionCountPageCommand() { }
     }
 
+    [MessageType(description: "打开MqCounts页")]
+    public class ShowMqCountsPageCommand : Cmd {
+        public ShowMqCountsPageCommand() { }
+    }
+
     [MessageType(description: "打开密码修改界面")]
     public class ShowChangePassword : Cmd {
         public ShowChangePassword() { }

+ 58 - 0
src/AppModels/MinerStudio/Vms/MqCountViewModel.cs

@@ -0,0 +1,58 @@
+using NTMiner.ServerNode;
+using NTMiner.Vms;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NTMiner.MinerStudio.Vms {
+    public class MqCountViewModel : ViewModelBase {
+        private List<MqReceivedCountViewModel> _receivedCounts;
+        private List<MqSendCountViewModel> _sendCounts;
+
+        public MqCountViewModel(MqCountData data) {
+            this.ReceivedCounts = new List<MqReceivedCountViewModel>();
+            this.SendCounts = new List<MqSendCountViewModel>();
+            foreach (var item in data.ReceivedCounts) {
+                this.ReceivedCounts.Add(new MqReceivedCountViewModel(item));
+            }
+            foreach (var item in data.SendCounts) {
+                this.SendCounts.Add(new MqSendCountViewModel(item));
+            }
+            this.ReceivedCounts.Sort((l, r) => {
+                return (int)r.Count - (int)l.Count;
+            });
+            this.SendCounts.Sort((l, r) => {
+                return (int)r.Count - (int)l.Count;
+            });
+        }
+
+        public string ServerNodeName {
+            get {
+                if (ReceivedCounts == null || ReceivedCounts.Count == 0) {
+                    return string.Empty;
+                }
+                string queue = ReceivedCounts[0].Queue;
+                string[] parts = queue.Split('.');
+                if (parts.Length >= 5) {
+                    return string.Join(".", parts.Take(5));
+                }
+                return string.Empty;
+            }
+        }
+
+        public List<MqReceivedCountViewModel> ReceivedCounts {
+            get => _receivedCounts;
+            set {
+                _receivedCounts = value;
+                OnPropertyChanged(nameof(ReceivedCounts));
+            }
+        }
+
+        public List<MqSendCountViewModel> SendCounts {
+            get => _sendCounts;
+            set {
+                _sendCounts = value;
+                OnPropertyChanged(nameof(SendCounts));
+            }
+        }
+    }
+}

+ 71 - 0
src/AppModels/MinerStudio/Vms/MqCountsPageViewModel.cs

@@ -0,0 +1,71 @@
+using NTMiner.ServerNode;
+using NTMiner.Vms;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace NTMiner.MinerStudio.Vms {
+    public class MqCountsPageViewModel : ViewModelBase {
+        private List<MqCountViewModel> _mqCountVms;
+        private List<string> _serverNodes;
+        private string _selectedServerNode;
+
+        public MqCountsPageViewModel() {
+            this._mqCountVms = new List<MqCountViewModel>();
+            this._serverNodes = new List<string>();
+        }
+
+        public void SetData(MqCountData[] data) {
+            if (data == null || data.Length == 0) {
+                return;
+            }
+            _mqCountVms = data.Select(a => new MqCountViewModel(a)).ToList();
+            this.ServerNodes = _mqCountVms.Select(a => a.ServerNodeName).ToList();
+            if (string.IsNullOrEmpty(this.SelectedServerNode) || !this.ServerNodes.Contains(this.SelectedServerNode)) {
+                this.SelectedServerNode = this.ServerNodes.FirstOrDefault();
+            }
+            else {
+                OnPropertyChanged(nameof(CurrentMqCountVm));
+            }
+        }
+
+        public List<string> ServerNodes {
+            get => _serverNodes;
+            set {
+                if (!IsEquals(_serverNodes, value)) {
+                    _serverNodes = value;
+                    OnPropertyChanged(nameof(ServerNodes));
+                }
+            }
+        }
+
+        public string SelectedServerNode {
+            get => _selectedServerNode;
+            set {
+                if (_selectedServerNode != value) {
+                    _selectedServerNode = value;
+                    OnPropertyChanged(nameof(SelectedServerNode));
+                    OnPropertyChanged(nameof(CurrentMqCountVm));
+                }
+            }
+        }
+
+        public MqCountViewModel CurrentMqCountVm {
+            get {
+                return _mqCountVms.FirstOrDefault(a => a.ServerNodeName == this.SelectedServerNode);
+            }
+        }
+
+        private static bool IsEquals(List<string> left, List<string> right) {
+            if (left == right) {
+                return true;
+            }
+            if (left == null || right == null) {
+                return false;
+            }
+            if (left.Count != right.Count) {
+                return false;
+            }
+            return left.All(a => right.Contains(a));
+        }
+    }
+}

+ 5 - 0
src/AppViews0/AppViewFactory.cs

@@ -291,6 +291,11 @@ namespace NTMiner {
                     MinerStudioUcs.ActionCounts.ShowWindow();
                 });
             });
+            VirtualRoot.BuildCmdPath<ShowMqCountsPageCommand>(location: location, LogEnum.DevConsole, path: message => {
+                UIThread.Execute(() => {
+                    MinerStudioUcs.MqCountsPage.ShowWindow();
+                });
+            });
             VirtualRoot.BuildCmdPath<ShowChangePassword>(location: location, LogEnum.DevConsole, path: message => {
                 UIThread.Execute(() => {
                     MinerStudioUcs.ChangePassword.ShowWindow();

+ 11 - 0
src/AppViews0/AppViews0.csproj

@@ -101,6 +101,9 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AppViewFactory.cs" />
+    <Compile Include="MinerStudio\Views\Ucs\MqCountsPage.xaml.cs">
+      <DependentUpon>MqCountsPage.xaml</DependentUpon>
+    </Compile>
     <Compile Include="MinerStudio\Views\Ucs\ColumnsShowEdit.xaml.cs">
       <DependentUpon>ColumnsShowEdit.xaml</DependentUpon>
     </Compile>
@@ -408,6 +411,10 @@
     <Compile Include="Views\Ucs\CoinPage.xaml.cs">
       <DependentUpon>CoinPage.xaml</DependentUpon>
     </Compile>
+    <Page Include="MinerStudio\Views\Design\MqCountsPageViewModel.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="MinerStudio\Views\Design\QQGroupQrCodeViewModel.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
@@ -448,6 +455,10 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
+    <Page Include="MinerStudio\Views\Ucs\MqCountsPage.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="MinerStudio\Views\Ucs\ColumnsShowEdit.xaml">
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>

+ 2 - 0
src/AppViews0/MinerStudio/Views/Design/MqCountsPageViewModel.xaml

@@ -0,0 +1,2 @@
+<vm:MqCountsPageViewModel xmlns:vm="clr-namespace:NTMiner.MinerStudio.Vms;assembly=AppModels">
+</vm:MqCountsPageViewModel>

+ 1 - 1
src/AppViews0/MinerStudio/Views/Ucs/CalcConfig.xaml.cs

@@ -37,7 +37,7 @@ namespace NTMiner.MinerStudio.Views.Ucs {
             this.Vm = new CalcConfigViewModels();
             this.DataContext = this.Vm;
             InitializeComponent();
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.BuildEventPath<CalcConfigSetInitedEvent>("收益计算器数据集刷新后刷新VM", LogEnum.DevConsole, location: this.GetType(), PathPriority.Normal,
                     path: message => {
                         Vm.Refresh();

+ 1 - 1
src/AppViews0/MinerStudio/Views/Ucs/MinerClient.xaml.cs

@@ -9,7 +9,7 @@ namespace NTMiner.MinerStudio.Views.Ucs {
         public MinerClient() {
             InitializeComponent();
             this.TbDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.BuildEventPath<MinutePartChangedEvent>("整分钟时更新MinerClient上的日期时间计时器", LogEnum.None, location: this.GetType(), PathPriority.Normal,
                     path: message => {
                         this.TbDateTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm");

+ 90 - 0
src/AppViews0/MinerStudio/Views/Ucs/MqCountsPage.xaml

@@ -0,0 +1,90 @@
+<UserControl 
+    x:Class="NTMiner.MinerStudio.Views.Ucs.MqCountsPage"
+	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+	xmlns:sys="clr-namespace:System;assembly=mscorlib"
+	xmlns:controls="clr-namespace:NTMiner.Controls;assembly=NTMinerWpf"
+	xmlns:local="clr-namespace:NTMiner.Views.Ucs"
+	xmlns:app="clr-namespace:NTMiner;assembly=AppModels"
+	xmlns:vm="clr-namespace:NTMiner.MinerStudio.Vms;assembly=AppModels"
+    Background="White"
+	mc:Ignorable="d" 
+    d:DesignHeight="700" 
+    d:DesignWidth="1400"
+    d:DataContext="{d:DesignData Source=../Design/MqCountsPageViewModel.xaml}">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="3*"></ColumnDefinition>
+            <ColumnDefinition Width="2*"></ColumnDefinition>
+        </Grid.ColumnDefinitions>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto"></RowDefinition>
+            <RowDefinition Height="Auto"></RowDefinition>
+            <RowDefinition Height="*"></RowDefinition>
+        </Grid.RowDefinitions>
+        <ListBox 
+            Grid.ColumnSpan="2"
+			Background="Transparent"				
+			ItemsSource="{Binding ServerNodes}"
+			SelectedItem="{Binding SelectedServerNode}"
+			ScrollViewer.HorizontalScrollBarVisibility="Disabled"
+			ScrollViewer.VerticalScrollBarVisibility="Disabled"
+			ItemContainerStyle="{StaticResource ListBoxBarItem}"
+			BorderThickness="0">
+            <ListBox.Resources>
+                <controls:BindingProxy x:Key="proxy" Data="{Binding}" />
+            </ListBox.Resources>
+            <ListBox.ItemsPanel>
+                <ItemsPanelTemplate>
+                    <WrapPanel>
+                    </WrapPanel>
+                </ItemsPanelTemplate>
+            </ListBox.ItemsPanel>
+            <ListBox.ItemTemplate>
+                <DataTemplate>
+                    <TextBlock FontSize="14" Padding="8 2" Text="{Binding}"></TextBlock>
+                </DataTemplate>
+            </ListBox.ItemTemplate>
+        </ListBox>
+        <TextBlock Grid.Row="1" Grid.Column="0" Padding="4">收到的Mq消息</TextBlock>
+        <TextBlock Grid.Row="1" Grid.Column="1" Padding="4">发送的Mq消息</TextBlock>
+        <DataGrid 
+            Grid.Row="2"
+            Grid.Column="0"
+            EnableColumnVirtualization="True"
+            EnableRowVirtualization="True"
+            ItemsSource="{Binding CurrentMqCountVm.ReceivedCounts}" 
+			BorderThickness="0">
+            <DataGrid.Resources>
+                <controls:BindingProxy x:Key="proxy" Data="{Binding}" />
+            </DataGrid.Resources>
+            <DataGrid.Columns>
+                <DataGridTextColumn Width="250" IsReadOnly="True" Header="Queue" Binding="{Binding Queue}">
+                </DataGridTextColumn>
+                <DataGridTextColumn Width="300" IsReadOnly="True" Header="RoutingKey" Binding="{Binding RoutingKey}">
+                </DataGridTextColumn>
+                <DataGridTextColumn Width="100" IsReadOnly="True" Header="Count" Binding="{Binding Count}">
+                </DataGridTextColumn>
+            </DataGrid.Columns>
+        </DataGrid>
+        <DataGrid 
+            Grid.Row="2"
+            Grid.Column="1"
+            EnableColumnVirtualization="True"
+            EnableRowVirtualization="True"
+            ItemsSource="{Binding CurrentMqCountVm.SendCounts}" 
+			BorderThickness="0">
+            <DataGrid.Resources>
+                <controls:BindingProxy x:Key="proxy" Data="{Binding}" />
+            </DataGrid.Resources>
+            <DataGrid.Columns>
+                <DataGridTextColumn Width="300" IsReadOnly="True" Header="RoutingKey" Binding="{Binding RoutingKey}">
+                </DataGridTextColumn>
+                <DataGridTextColumn Width="100" IsReadOnly="True" Header="Count" Binding="{Binding Count}">
+                </DataGridTextColumn>
+            </DataGrid.Columns>
+        </DataGrid>
+    </Grid>
+</UserControl>

+ 47 - 0
src/AppViews0/MinerStudio/Views/Ucs/MqCountsPage.xaml.cs

@@ -0,0 +1,47 @@
+using NTMiner.MinerStudio.Vms;
+using NTMiner.Views;
+using NTMiner.Vms;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace NTMiner.MinerStudio.Views.Ucs {
+    public partial class MqCountsPage : UserControl {
+        public static void ShowWindow() {
+            ContainerWindow.ShowWindow(new ContainerWindowViewModel {
+                Title = "Mq Counts",
+                IconName = "Icon_RabbitMq",
+                Width = 1400,
+                Height = 700,
+                IsMaskTheParent = false,
+                IsChildWindow = true,
+                CloseVisible = Visibility.Visible,
+                FooterVisible = Visibility.Collapsed
+            }, ucFactory: (window) => new MqCountsPage());
+        }
+
+        public MqCountsPageViewModel Vm { get; private set; }
+
+        public MqCountsPage() {
+            if (WpfUtil.IsInDesignMode) {
+                return;
+            }
+            this.Vm = new MqCountsPageViewModel();
+            this.DataContext = this.Vm;
+            InitializeComponent();
+            this.OnLoaded(window => {
+                this.Load();
+                window.BuildEventPath<Per10SecondEvent>("周期自动刷新", LogEnum.None, this.GetType(), PathPriority.Normal, message => {
+                    this.Load();
+                });
+            });
+        }
+
+        private void Load() {
+            RpcRoot.OfficialServer.AdminService.GetMqCountsAsync((response, e) => {
+                if (response.IsSuccess() && response.Data != null && response.Data.Length != 0) {
+                    this.Vm.SetData(response.Data);
+                }
+            });
+        }
+    }
+}

+ 1 - 1
src/AppViews0/Views/Ucs/Calc.xaml.cs

@@ -32,7 +32,7 @@ namespace NTMiner.Views.Ucs {
             this.Vm = new CalcViewModel();
             this.DataContext = this.Vm;
             InitializeComponent();
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.BuildEventPath<CalcConfigSetInitedEvent>("收益计算器数据集刷新后刷新VM", LogEnum.DevConsole, location: this.GetType(), PathPriority.Normal,
                     path: message => {
                         foreach (var coinVm in Vm.CoinVms.AllCoins) {

+ 10 - 0
src/AppViews0/Views/Ucs/MainMenu.xaml

@@ -452,6 +452,16 @@
 							Stretch="Fill" />
                     </MenuItem.Icon>
                 </MenuItem>
+                <MenuItem Header="MqCounts" Visibility="{Binding IsMinerStudioOuterAdminVisible}" Command="{x:Static app:AppStatic.ShowMqCountsPage}">
+                    <MenuItem.Icon>
+                        <Path
+							Width="16"
+							Height="16"
+							Data="{StaticResource Icon_RabbitMq}"
+							Fill="{StaticResource BtnBackground}"
+							Stretch="Fill" />
+                    </MenuItem.Icon>
+                </MenuItem>
                 <MenuItem Header="外网群控服务器节点" Visibility="{Binding IsMinerStudioOuterAdminVisible}" Command="{x:Static app:AppStatic.ShowWsServerNodes}">
                     <MenuItem.Icon>
                         <Path

+ 1 - 1
src/AppViews0/Views/Ucs/MinerProfileDual.xaml.cs

@@ -13,7 +13,7 @@ namespace NTMiner.Views.Ucs {
         public MinerProfileDual() {
             this.DataContext = MinerProfileViewModel.Instance;
             InitializeComponent();
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.BuildEventPath<LocalContextReInitedEventHandledEvent>("本地上下文视图模型集刷新后刷新界面上的popup", LogEnum.DevConsole, location: this.GetType(), PathPriority.Normal,
                     path: message => {
                         UIThread.Execute(() => {

+ 1 - 1
src/AppViews0/Views/Ucs/MinerProfileIndex.xaml.cs

@@ -17,7 +17,7 @@ namespace NTMiner.Views.Ucs {
             this.Vm = new MinerProfileIndexViewModel();
             this.DataContext = this.Vm;
             InitializeComponent();
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.BuildEventPath<LocalContextReInitedEventHandledEvent>("上下文视图模型集刷新后刷新界面上的popup", LogEnum.DevConsole, location: this.GetType(), PathPriority.Normal,
                     path: message => {
                         UIThread.Execute(() => {

+ 1 - 1
src/AppViews0/Views/Ucs/SpeedCharts.xaml.cs

@@ -46,7 +46,7 @@ namespace NTMiner.Views.Ucs {
                 return;
             }
             Guid mainCoinId = NTMinerContext.Instance.MinerProfile.CoinId;
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.BuildEventPath<GpuSpeedChangedEvent>("显卡算力变更后刷新算力图界面", LogEnum.DevConsole, location: this.GetType(), PathPriority.Normal,
                     path: (message) => {
                         UIThread.Execute(() => {

+ 1 - 1
src/AppViews0/Views/Ucs/StateBar.xaml.cs

@@ -17,7 +17,7 @@ namespace NTMiner.Views.Ucs {
             if (WpfUtil.IsInDesignMode) {
                 return;
             }
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.Activated += (object sender, EventArgs e) => {
                     Vm.OnPropertyChanged(nameof(Vm.IsAutoAdminLogon));
                     Vm.OnPropertyChanged(nameof(Vm.AutoAdminLogonToolTip));

+ 1 - 1
src/AppViews0/Views/Ucs/Toolbox.xaml.cs

@@ -20,7 +20,7 @@ namespace NTMiner.Views.Ucs {
             if (WpfUtil.IsInDesignMode) {
                 return;
             }
-            this.OnLoaded((window) => {
+            this.OnLoaded(window => {
                 window.Activated += (object sender, EventArgs e) => {
                     Vm.OnPropertyChanged(nameof(Vm.IsAutoAdminLogon));
                     Vm.OnPropertyChanged(nameof(Vm.AutoAdminLogonMessage));

+ 0 - 11
src/NTMiner.Controllers/IClientDataBinaryController`1.cs

@@ -1,11 +0,0 @@
-using NTMiner.Core.MinerServer;
-
-namespace NTMiner.Controllers {
-    // 为了解除对HttpResponseMessage所在的程序集的引用所以整了个类型参数T1
-    public interface IClientDataBinaryController<T1> {
-        /// <summary>
-        /// 需签名
-        /// </summary>
-        T1 QueryClients(QueryClientsRequest request);
-    }
-}

+ 0 - 4
src/NTMiner.Controllers/IClientDataController.cs

@@ -5,10 +5,6 @@ namespace NTMiner.Controllers {
     /// 群控客户端的矿机列表接口
     /// </summary>
     public interface IClientDataController {
-        /// <summary>
-        /// 需签名
-        /// </summary>
-        QueryClientsResponse QueryClients(QueryClientsRequest request);
         /// <summary>
         /// 需签名
         /// </summary>

+ 0 - 1
src/NTMiner.Controllers/NTMiner.Controllers.csproj

@@ -41,7 +41,6 @@
     <Compile Include="IAdminController.cs" />
     <Compile Include="ICalcConfigBinaryController`1.cs" />
     <Compile Include="ICaptchaController`1.cs" />
-    <Compile Include="IClientDataBinaryController`1.cs" />
     <Compile Include="IMinerClientController.cs" />
     <Compile Include="INTMinerFileController.cs" />
     <Compile Include="IReportBinaryController.cs" />

+ 9 - 3
src/NTMinerDataSchemas/Core/MinerServer/QueryClientsForWsRequest.cs

@@ -1,6 +1,8 @@
-namespace NTMiner.Core.MinerServer {
+using System;
+
+namespace NTMiner.Core.MinerServer {
     public class QueryClientsForWsRequest : QueryClientsRequest {
-        public static QueryClientsForWsRequest Create(QueryClientsRequest request, string loginName) {
+        public static QueryClientsForWsRequest Create(QueryClientsRequest request, string loginName, Guid studioId, string sessionId) {
             return new QueryClientsForWsRequest {
                 Coin = request.Coin,
                 GpuDriver = request.GpuDriver,
@@ -19,12 +21,16 @@
                 Version = request.Version,
                 Wallet = request.Wallet,
                 WorkId = request.WorkId,
-                LoginName = loginName
+                LoginName = loginName,
+                StudioId = studioId,
+                SessionId = sessionId
             };
         }
 
         public QueryClientsForWsRequest() { }
 
         public string LoginName { get; set; }
+        public Guid StudioId { get; set; }
+        public string SessionId { get; set; }
     }
 }

+ 29 - 0
src/NTMinerDataSchemas/Core/MinerServer/QueryClientsResponseEx.cs

@@ -0,0 +1,29 @@
+using System;
+
+namespace NTMiner.Core.MinerServer {
+    public class QueryClientsResponseEx : QueryClientsResponse {
+        public QueryClientsResponseEx() { }
+
+        public static QueryClientsResponseEx Create(
+            QueryClientsResponse response,
+            string loginName, Guid studioId, string sessionId) {
+            return new QueryClientsResponseEx() {
+                StateCode = response.StateCode,
+                ReasonPhrase = response.ReasonPhrase,
+                Description = response.Description,
+                Data = response.Data,
+                Total = response.Total,
+                LatestSnapshots = response.LatestSnapshots,
+                TotalMiningCount = response.TotalMiningCount,
+                TotalOnlineCount = response.TotalOnlineCount,
+                LoginName = loginName,
+                StudioId = studioId,
+                SessionId = sessionId
+            };
+        }
+
+        public string LoginName { get; set; }
+        public Guid StudioId { get; set; }
+        public string SessionId { get; set; }
+    }
+}

+ 1 - 0
src/NTMinerDataSchemas/NTMinerDataSchemas.csproj

@@ -51,6 +51,7 @@
     <Compile Include="Core\LocalMessages.cs" />
     <Compile Include="Core\MinerServer\NTMinerFilesRequest.cs" />
     <Compile Include="Core\MinerServer\NTMinerFilesResponse.cs" />
+    <Compile Include="Core\MinerServer\QueryClientsResponseEx.cs" />
     <Compile Include="Core\OperationResults.cs" />
     <Compile Include="Core\UserGetSpeedRequest.cs" />
     <Compile Include="Gpus\GpuExtensions.cs" />

+ 1 - 0
src/NTMinerDataSchemas/Ws/WsMessage.cs

@@ -57,6 +57,7 @@ namespace NTMiner.Ws {
         public const string StopMine = "StopMine";                              // MinerStudio->WsServer->Mq->WsServer->MinerClient
 
         public const string QueryClientDatas = "QueryClientDatas";              // MinerStudio->WsServer->Mq->WebApiServer
+        public const string AutoQueryClientDatas = "AutoQueryClientDatas";      // MinerStudio->WsServer->Mq->WebApiServer
 
         public const string ConsoleOutLines = "ConsoleOutLines";                // MinerClient->WsServer->Mq->WsServer->MinerStudio
         public const string LocalMessages = "LocalMessages";                    // MinerClient->WsServer->Mq->WsServer->MinerStudio

+ 0 - 1
src/NTMinerRpcClient/NTMinerRpcClient.csproj

@@ -88,7 +88,6 @@
     <Compile Include="Services\Client\NTMinerDaemonService.cs" />
     <Compile Include="Core\Impl\KernelOutputKeywordSet.cs" />
     <Compile Include="Services\Official\CalcConfigBinaryService.cs" />
-    <Compile Include="Services\Official\ClientDataBinaryService.cs" />
     <Compile Include="Services\Official\FileUrlService.cs" />
     <Compile Include="Services\Official\NTMinerFileService.cs" />
     <Compile Include="Services\Official\NTMinerWalletService.cs" />

+ 0 - 25
src/NTMinerRpcClient/Services/Official/ClientDataBinaryService.cs

@@ -1,25 +0,0 @@
-using NTMiner.Controllers;
-using NTMiner.Core.MinerServer;
-using System;
-using System.Net.Http;
-
-namespace NTMiner.Services.Official {
-    public partial class ClientDataBinaryService {
-        private readonly string _controllerName = ControllerUtil.GetControllerName<IClientDataBinaryController<HttpResponseMessage>>();
-
-        internal ClientDataBinaryService() {
-        }
-
-        #region QueryClientsAsync
-        public void QueryClientsAsync(QueryClientsRequest query, Action<QueryClientsResponse, Exception> callback) {
-            RpcRoot.JsonRequestBinaryResponseRpcHelper.SignPostAsync(
-                RpcRoot.OfficialServerHost, 
-                RpcRoot.OfficialServerPort, 
-                _controllerName, 
-                nameof(IClientDataBinaryController<HttpResponseMessage>.QueryClients), 
-                data: query, 
-                callback);
-        }
-        #endregion
-    }
-}

+ 0 - 12
src/NTMinerRpcClient/Services/Official/ClientDataService.cs

@@ -10,18 +10,6 @@ namespace NTMiner.Services.Official {
         internal ClientDataService() {
         }
 
-        #region QueryClientsAsync
-        public void QueryClientsAsync(QueryClientsRequest query, Action<QueryClientsResponse, Exception> callback) {
-            RpcRoot.JsonRpc.SignPostAsync(
-                RpcRoot.OfficialServerHost, 
-                RpcRoot.OfficialServerPort, 
-                _controllerName, 
-                nameof(IClientDataController.QueryClients), 
-                data: query, 
-                callback);
-        }
-        #endregion
-
         #region UpdateClientAsync
         public void UpdateClientAsync(string objectId, string propertyName, object value, Action<ResponseBase, Exception> callback) {
             UpdateClientRequest request = new UpdateClientRequest {

+ 0 - 1
src/NTMinerRpcClient/Services/OfficialServices.cs

@@ -18,7 +18,6 @@
         public readonly AppSettingService AppSettingService = new AppSettingService();
         public readonly UserAppSettingService UserAppSettingService = new UserAppSettingService();
         public readonly ClientDataService ClientDataService = new ClientDataService();
-        public readonly ClientDataBinaryService ClientDataBinaryService = new ClientDataBinaryService();
         public readonly UserMinerGroupService UserMinerGroupService = new UserMinerGroupService();
         public readonly UserMineWorkService UserMineWorkService = new UserMineWorkService();
         public readonly AdminService AdminService = new AdminService();

+ 16 - 0
src/NTMinerServer/Core/Messages.cs

@@ -247,6 +247,22 @@ namespace NTMiner.Core {
         public QueryClientsForWsRequest Query { get; private set; }
     }
 
+    [MessageType(description: "收到了AutoQueryClientsForWs Mq消息后,该消息是个命令")]
+    public class AutoQueryClientsForWsMqCommand : Cmd {
+        public AutoQueryClientsForWsMqCommand(
+            string appId, string mqMessageId, DateTime timestamp, QueryClientsForWsRequest[] queries) {
+            this.AppId = appId;
+            this.MqMessageId = mqMessageId;
+            this.Timestamp = timestamp;
+            this.Queries = queries;
+        }
+
+        public string AppId { get; private set; }
+        public string MqMessageId { get; private set; }
+        public DateTime Timestamp { get; private set; }
+        public QueryClientsForWsRequest[] Queries { get; private set; }
+    }
+
     [MessageType(description: "收到了QueryClientsForWsResponse Mq消息后,该消息是个命令")]
     public class QueryClientsForWsResponseMqEvent : EventBase {
         public QueryClientsForWsResponseMqEvent(

+ 17 - 0
src/NTMinerServer/Core/Mq/MinerClientMqBodyUtil.cs

@@ -112,6 +112,15 @@ namespace NTMiner.Core.Mq {
             string json = Encoding.UTF8.GetString(body);
             return VirtualRoot.JsonSerializer.Deserialize<QueryClientsForWsRequest>(json);
         }
+
+        public static byte[] GetAutoQueryClientsForWsMqSendBody(QueryClientsForWsRequest[] requests) {
+            return Encoding.UTF8.GetBytes(VirtualRoot.JsonSerializer.Serialize(requests));
+        }
+
+        public static QueryClientsForWsRequest[] GetAutoQueryClientsForWsMqReceiveBody(byte[] body) {
+            string json = Encoding.UTF8.GetString(body);
+            return VirtualRoot.JsonSerializer.Deserialize<QueryClientsForWsRequest[]>(json);
+        }
         #endregion
 
         #region QueryClientsResponse
@@ -122,6 +131,14 @@ namespace NTMiner.Core.Mq {
         public static QueryClientsResponse GetQueryClientsResponseMqReceiveBody(byte[] body) {
             return VirtualRoot.BinarySerializer.Deserialize<QueryClientsResponse>(body);
         }
+
+        public static byte[] GetAutoQueryClientsResponseMqSendBody(QueryClientsResponseEx[] responses) {
+            return VirtualRoot.BinarySerializer.Serialize(responses);
+        }
+
+        public static QueryClientsResponseEx[] GetAutoQueryClientsResponseMqReceiveBody(byte[] body) {
+            return VirtualRoot.BinarySerializer.Deserialize<QueryClientsResponseEx[]>(body);
+        }
         #endregion
     }
 }

+ 1 - 0
src/NTMinerServer/Core/Mq/MqMessagePaths/ReadOnlyUserMqMessagePath.cs

@@ -43,6 +43,7 @@ namespace NTMiner.Core.Mq.MqMessagePaths {
                     string appId = ea.BasicProperties.AppId;
                     VirtualRoot.RaiseEvent(new UserPasswordChangedMqEvent(appId, loginName, ea.GetTimestamp()));
                 },
+                // 该事件通常不会发生,因为用户注册的时候已经生成了RSA公私钥对了,RSA非空时不会更新
                 [MqKeyword.UserRSAKeyUpdatedRoutingKey] = ea => {
                     string loginName = UserMqBodyUtil.GetLoginNameMqReceiveBody(ea.Body);
                     string appId = ea.BasicProperties.AppId;

+ 2 - 0
src/NTMinerServer/MqKeyword.cs

@@ -37,7 +37,9 @@ namespace NTMiner {
         public const string MinerSignsSetedRoutingKey = "MinerSignsSeted";
 
         public const string QueryClientsForWsRoutingKey = "QueryClientsForWs";
+        public const string AutoQueryClientsForWsRoutingKey = "AutoQueryClientsForWs";
         public const string QueryClientsForWsResponseRoutingKey = "QueryClientsForWsResponse{0}";
+        public const string AutoQueryClientsForWsResponseRoutingKey = "AutoQueryClientsForWsResponse{0}";
         public const string SpeedsRoutingKey = WsMessage.Speed + "s";
 
         public const string StartMineRoutingKey = WsMessage.StartMine;

+ 1 - 0
src/NTMinerWpf/Styles/KbIcons.xaml

@@ -136,4 +136,5 @@
     <StreamGeometry x:Key="Icon_NoDevFee">M655.1 350.9h-384c-17.7 0-32-14.3-32-32V179.8c0-17.7 14.3-32 32-32h384.1c17.7 0 32 14.3 32 32v139.1c-0.1 17.7-14.4 32-32.1 32z m-352-64h320.1v-75.1H303.1v75.1zM591.1 798.5c-17.7 0-32-14.3-32-32V606.7c0-17.7 14.3-32 32-32s32 14.3 32 32v159.8c0 17.7-14.3 32-32 32z M335.1 798.5c-17.7 0-32-14.3-32-32V318.9c0-17.7 14.3-32 32-32h256.1c17.7 0 32 14.3 32 32v159.8c0 17.7-14.3 32-32 32s-32-14.3-32-32V350.9H367.1v415.6c0 17.7-14.4 32-32 32z M719.2 638.7h-128c-17.7 0-32-14.3-32-32s14.3-32 32-32h96v-64h-96c-17.7 0-32-14.3-32-32s14.3-32 32-32h128c17.7 0 32 14.3 32 32v128c0 17.7-14.4 32-32 32z M820.1 702.8h-101c-17.7 0-32-14.3-32-32V414.6c0-17.7 14.3-32 32-32H820c17.7 0 32 14.3 32 32v256.2c0.1 17.7-14.3 32-31.9 32z m-69-64H788V446.6h-36.9v192.2z</StreamGeometry>
     <StreamGeometry x:Key="Icon_Cmd">M971.2 245.44a263.68 263.68 0 0 0-192-192 1717.12 1717.12 0 0 0-533.44 0 263.68 263.68 0 0 0-192 192 1717.12 1717.12 0 0 0 0 533.44 263.68 263.68 0 0 0 192 192 1717.12 1717.12 0 0 0 533.44 0 263.68 263.68 0 0 0 192-192 1719.04 1719.04 0 0 0 0-533.44zM492.8 539.52A529.92 529.92 0 0 1 329.6 704a69.76 69.76 0 1 1-71.68-119.68 360 360 0 0 0 89.6-80 409.92 409.92 0 0 0-89.6-79.36 69.76 69.76 0 1 1 71.68-120.32 529.6 529.6 0 0 1 163.2 163.2 69.76 69.76 0 0 1 0 71.68zM742.4 704h-172.8c-32 0-57.6-16.32-57.6-48s25.92-48 57.6-48h172.8c32 0 57.6 16.32 57.6 48s-25.92 48-57.6 48z</StreamGeometry>
     <StreamGeometry x:Key="Icon_Action">M981.38339555 386.17088a511.32643555 511.32643555 0 0 0-108.64412444-162.74773333 509.14190222 509.14190222 0 0 0-162.74773333-108.57130667A500.40376889 500.40376889 0 0 0 512 74.51079111a500.98631111 500.98631111 0 0 0-197.99153778 40.34104889 513.21969778 513.21969778 0 0 0-162.74773333 108.57130667 510.16135111 510.16135111 0 0 0-108.49848889 162.74773333A498.87459555 498.87459555 0 0 0 2.27555555 584.23523555c0 70.56042667 13.68974222 137.33432889 40.9964089 200.2488889a510.81671111 510.81671111 0 0 0 113.81418666 165.00508444H866.98666667a510.08853333 510.08853333 0 0 0 113.81418666-165.00508444 497.85514667 497.85514667 0 0 0 40.92359112-200.2488889 500.25813333 500.25813333 0 0 0-40.3410489-198.06435555zM485.93123555 183.66464h52.28316445v93.35239111h-52.28316445v-93.35239111z m-281.07662222 380.1088l-92.11448888-16.96654222 9.10222222-51.19089778 92.18730666 16.96654222-9.17504 51.19089778z m88.76487112-197.99153778l-60.29312-71.72551111 39.83132444-32.91363556 60.22030222 71.65269334-39.75850666 32.98645333zM588.82275555 681.51978667A77.98784 77.98784 0 0 1 554.08867555 730.45333333c-18.20444445 11.72366222-37.93806222 15.14609778-59.20085333 10.26730667a75.07512889 75.07512889 0 0 1-48.86072889-34.73408 75.73048889 75.73048889 0 0 1-1.16508444-80.68209778L357.26222222 411.29301333l156.99512889 175.19957334c28.10766222 0.80099555 49.73454222 12.96156445 64.88064 36.33607111 11.35957333 18.20444445 14.63637333 37.79242667 9.68476444 58.69112889z m141.70339556-315.73788445l-39.90414222-32.98645333 60.36593778-71.65269334 39.75850666 32.91363556-60.22030222 71.72551111z m88.69205334 197.99153778l-9.02940445-51.19089778 92.11448889-17.11217777 9.10222222 51.19089777-92.18730666 17.11217778z</StreamGeometry>
+    <StreamGeometry x:Key="Icon_RabbitMq">M712.533333 631.466667h-57.6c-21.333333 0-38.4 17.066667-38.4 38.4v57.6c0 21.333333 17.066667 38.4 38.4 38.4h57.6c21.333333 0 38.4-17.066667 38.4-38.4v-57.6c0-21.333333-17.066667-38.4-38.4-38.4z M859.733333 454.4H682.666667c-8.533333 0-14.933333-6.4-14.933334-14.933333V200.533333c0-38.4-32-70.4-70.4-70.4h-72.533333c-38.4 0-70.4 32-70.4 70.4V448c0 2.133333-2.133333 6.4-6.4 6.4h-64c-2.133333 0-6.4-2.133333-6.4-6.4V200.533333c0-38.4-32-70.4-70.4-70.4H234.666667c-32 0-64 32-64 70.4v654.933334c0 38.4 32 70.4 70.4 70.4h618.666666c38.4 0 70.4-32 70.4-70.4V524.8c0-38.4-32-70.4-70.4-70.4z m10.666667 403.2c0 4.266667-4.266667 8.533333-8.533333 8.533333h-618.666667c-4.266667 0-8.533333-4.266667-8.533333-8.533333V200.533333c-4.266667-4.266667 0-8.533333 6.4-8.533333h72.533333c4.266667 0 8.533333 4.266667 8.533333 8.533333V448c0 36.266667 29.866667 66.133333 66.133334 66.133333h64c36.266667 0 66.133333-29.866667 66.133333-66.133333V200.533333c0-4.266667 4.266667-8.533333 8.533333-8.533333h72.533334c4.266667 0 8.533333 4.266667 8.533333 8.533333v238.933334c0 40.533333 34.133333 74.666667 74.666667 74.666666h177.066666c4.266667 0 8.533333 4.266667 8.533334 8.533334v334.933333h2.133333z</StreamGeometry>
 </ResourceDictionary>

+ 1 - 1
src/NTMinerWpf/WindowExtension.cs

@@ -151,7 +151,7 @@ namespace NTMiner {
             messagePathIds.Add(messagePathId);
         }
 
-        public static void BuildOnecePath<TMessage>(this Window window, string description, LogEnum logType, Guid pathId, Type location, PathPriority priority, Action<TMessage> path)
+        private static void BuildOnecePath<TMessage>(this Window window, string description, LogEnum logType, Guid pathId, Type location, PathPriority priority, Action<TMessage> path)
             where TMessage : IMessage {
             if (WpfUtil.IsInDesignMode) {
                 return;

+ 16 - 0
src/WebApiServer/AppRoot.cs

@@ -318,5 +318,21 @@ namespace NTMiner {
             }
             return response;
         }
+
+        public static QueryClientsResponseEx[] QueryClientsForWs(QueryClientsForWsRequest[] requests) {
+            List<QueryClientsResponseEx> responses = new List<QueryClientsResponseEx>();
+            if (requests == null || requests.Length == 0) {
+                responses.Add(ResponseBase.InvalidInput<QueryClientsResponseEx>("参数错误"));
+            }
+            else {
+                foreach (var request in requests) {
+                    responses.Add(
+                        QueryClientsResponseEx.Create(
+                            QueryClientsForWs(request), 
+                            request.LoginName, request.StudioId, request.SessionId));
+                }
+            }
+            return responses.ToArray();
+        }
     }
 }

+ 1 - 1
src/WebApiServer/CloudFileUrlGenerater/Impl/QiniuCloudKodoFileUrlGenerater.cs

@@ -13,7 +13,7 @@ namespace NTMiner.CloudFileUrlGenerater.Impl {
 
         public string GeneratePresignedUrl(string bucketName, string key) {
             // 注意:Qiniu.dll是github上下载源码编译的,因为Qiniu依赖的Newtonsoft.Json版本不对
-            // TODO:等域名备案,七牛kodo需绑定域名
+            // TODO:搁置,需要开发个工具同时往阿里云oss和七牛kodo上传文件
             string kodoDomain = ServerRoot.HostConfig.KodoDomain;
             if (string.IsNullOrEmpty(kodoDomain)) {
                 kodoDomain = "kodo.ntminer.top";

+ 0 - 20
src/WebApiServer/Controllers/ClientDataBinaryController.cs

@@ -1,20 +0,0 @@
-using NTMiner.Core.MinerServer;
-using System.Net;
-using System.Net.Http;
-using System.Web.Http;
-
-namespace NTMiner.Controllers {
-    public class ClientDataBinaryController : ApiControllerBase, IClientDataBinaryController<HttpResponseMessage> {
-        // 留存一长段时间,这个方法最初旧的群控客户端调用了
-        [Role.User]
-        [HttpPost]
-        public HttpResponseMessage QueryClients([FromBody]QueryClientsRequest request) {
-            QueryClientsResponse response = ClientDataController.DoQueryClients(request, User);
-            var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) {
-                Content = new ByteArrayContent(VirtualRoot.BinarySerializer.Serialize(response))
-            };
-            httpResponseMessage.Content.Headers.ContentType = AppRoot.BinaryContentType;
-            return httpResponseMessage;
-        }
-    }
-}

+ 0 - 30
src/WebApiServer/Controllers/ClientDataController.cs

@@ -1,5 +1,4 @@
 using NTMiner.Core.MinerServer;
-using NTMiner.User;
 using System;
 using System.Collections.Generic;
 using System.Web.Http;
@@ -7,35 +6,6 @@ using System.Web.Http;
 namespace NTMiner.Controllers {
     // 注意该控制器不能重命名
     public class ClientDataController : ApiControllerBase, IClientDataController {
-        #region QueryClients
-        [Role.User]
-        [HttpPost]
-        public QueryClientsResponse QueryClients([FromBody]QueryClientsRequest request) {
-            return DoQueryClients(request, User);
-        }
-        #endregion
-
-        internal static QueryClientsResponse DoQueryClients(QueryClientsRequest request, UserData user) {
-            if (request == null) {
-                return ResponseBase.InvalidInput<QueryClientsResponse>("参数错误");
-            }
-            request.PagingTrim();
-            try {
-                var data = AppRoot.ClientDataSet.QueryClients(
-                    user,
-                    request,
-                    out int total,
-                    out CoinSnapshotData[] latestSnapshots,
-                    out int totalOnlineCount,
-                    out int totalMiningCount) ?? new List<ClientData>();
-                return QueryClientsResponse.Ok(data, total, latestSnapshots, totalMiningCount, totalOnlineCount);
-            }
-            catch (Exception e) {
-                Logger.ErrorDebugLine(e);
-                return ResponseBase.ServerError<QueryClientsResponse>(e.Message);
-            }
-        }
-
         #region UpdateClient
         [Role.User]
         [HttpPost]

+ 9 - 0
src/WebApiServer/Core/Impl/ClientDataSet.cs

@@ -186,6 +186,15 @@ namespace NTMiner.Core.Impl {
                 QueryClientsResponse response = AppRoot.QueryClientsForWs(message.Query);
                 _mqSender.SendResponseClientsForWs(message.AppId, message.LoginName, message.StudioId, message.SessionId, message.MqMessageId, response);
             });
+            VirtualRoot.BuildCmdPath<AutoQueryClientsForWsMqCommand>(this.GetType(), LogEnum.None, path: message => {
+                if (message.Queries != null && message.Queries.Length != 0) {
+                    foreach (var query in message.Queries) {
+                        ServerRoot.IfStudioClientTestIdLogElseNothing(query.StudioId, nameof(QueryClientsForWsMqCommand));
+                    }
+                    QueryClientsResponseEx[] responses = AppRoot.QueryClientsForWs(message.Queries);
+                    _mqSender.SendResponseClientsForWs(message.AppId, message.MqMessageId, responses);
+                }
+            });
         }
 
         private void UpdateClientDatasCache(string oldLoginName, string newLoginName, ClientData clientData) {

+ 1 - 0
src/WebApiServer/Core/Impl/UserSet.cs

@@ -14,6 +14,7 @@ namespace NTMiner.Core.Impl {
         public UserSet(IUserDataRedis redis, IUserMqSender mqSender) : base(redis) {
             _redis = redis;
             _mqSender = mqSender;
+            // 收到通常不会收到该命令,因为用户注册的时候已经生成了RSA公私钥对了,RSA非空时不会更新
             VirtualRoot.BuildCmdPath<UpdateUserRSAKeyMqCommand>(this.GetType(), LogEnum.DevConsole, path: message => {
                 if (message.AppId == ServerRoot.HostConfig.ThisServerAddress) {
                     return;

+ 8 - 0
src/WebApiServer/Core/Mq/MqMessagePaths/MinerClientMqMessagePath.cs

@@ -32,6 +32,14 @@ namespace NTMiner.Core.Mq.MqMessagePaths {
                     if (query != null) {
                         VirtualRoot.Execute(new QueryClientsForWsMqCommand(appId, mqMessageId, ea.GetTimestamp(), loginName, studioId, sessionId, query));
                     }
+                },
+                [MqKeyword.AutoQueryClientsForWsRoutingKey] = ea => {
+                    string appId = ea.BasicProperties.AppId;
+                    string mqMessageId = ea.BasicProperties.MessageId;
+                    QueryClientsForWsRequest[] queries = MinerClientMqBodyUtil.GetAutoQueryClientsForWsMqReceiveBody(ea.Body);
+                    if (queries != null && queries.Length != 0) {
+                        VirtualRoot.Execute(new AutoQueryClientsForWsMqCommand(appId, mqMessageId, ea.GetTimestamp(), queries));
+                    }
                 }
             };
         }

+ 1 - 0
src/WebApiServer/Core/Mq/Senders/IMinerClientMqSender.cs

@@ -12,5 +12,6 @@ namespace NTMiner.Core.Mq.Senders {
             string sessionId, 
             string mqCorrelationId, 
             QueryClientsResponse response);
+        void SendResponseClientsForWs(string wsServerIp, string mqCorrelationId, QueryClientsResponseEx[] responses);
     }
 }

+ 14 - 0
src/WebApiServer/Core/Mq/Senders/Impl/MinerClientMqSender.cs

@@ -52,6 +52,20 @@ namespace NTMiner.Core.Mq.Senders.Impl {
                 body: MinerClientMqBodyUtil.GetQueryClientsResponseMqSendBody(response));
         }
 
+        public void SendResponseClientsForWs(string wsServerIp, string mqCorrelationId, QueryClientsResponseEx[] responses) {
+            if (responses == null || responses.Length == 0) {
+                return;
+            }
+            var basicProperties = CreateBasicProperties();
+            if (!string.IsNullOrEmpty(mqCorrelationId)) {
+                basicProperties.CorrelationId = mqCorrelationId;
+            }
+            _mq.BasicPublish(
+                routingKey: string.Format(MqKeyword.AutoQueryClientsForWsResponseRoutingKey, wsServerIp),
+                basicProperties: basicProperties,
+                body: MinerClientMqBodyUtil.GetAutoQueryClientsResponseMqSendBody(responses));
+        }
+
         private IBasicProperties CreateWsBasicProperties(string loginName, Guid studioId, string sessionId) {
             var basicProperties = _mq.CreateBasicProperties();
             basicProperties.Persistent = false;// 非持久化的

+ 0 - 1
src/WebApiServer/WebApiServer.csproj

@@ -99,7 +99,6 @@
     <Compile Include="ActionCountRoot.cs" />
     <Compile Include="Controllers\AdminController.cs" />
     <Compile Include="Controllers\CalcConfigBinaryController.cs" />
-    <Compile Include="Controllers\ClientDataBinaryController.cs" />
     <Compile Include="Controllers\NTMinerFileController.cs" />
     <Compile Include="Controllers\ReportBinaryController.cs" />
     <Compile Include="Controllers\ServerMessageBinaryController.cs" />

+ 13 - 0
src/WsServer/Core/Mq/MqMessagePaths/MinerClientMqMessagePath.cs

@@ -6,6 +6,7 @@ using System.Collections.Generic;
 namespace NTMiner.Core.Mq.MqMessagePaths {
     public class MinerClientMqMessagePath : AbstractMqMessagePath {
         private readonly string _queryClientsForWsResponseRoutingKey;
+        private readonly string _autoQueryClientsForWsResponseRoutingKey;
 
         public override bool IsReadyToBuild {
             get { return true; }
@@ -13,6 +14,7 @@ namespace NTMiner.Core.Mq.MqMessagePaths {
 
         public MinerClientMqMessagePath(string queue, string thisServerAddress) : base(queue) {
             _queryClientsForWsResponseRoutingKey = string.Format(MqKeyword.QueryClientsForWsResponseRoutingKey, thisServerAddress);
+            _autoQueryClientsForWsResponseRoutingKey = string.Format(MqKeyword.AutoQueryClientsForWsResponseRoutingKey, thisServerAddress);
         }
 
         protected override Dictionary<string, Action<BasicDeliverEventArgs>> GetPaths() {
@@ -27,6 +29,17 @@ namespace NTMiner.Core.Mq.MqMessagePaths {
                     if (response != null) {
                         VirtualRoot.RaiseEvent(new QueryClientsForWsResponseMqEvent(appId, mqCorrelationId, ea.GetTimestamp(), loginName, studioId, sessionId, response));
                     }
+                },
+                [_autoQueryClientsForWsResponseRoutingKey] = ea => {
+                    string appId = ea.BasicProperties.AppId;
+                    string mqCorrelationId = ea.BasicProperties.CorrelationId;
+                    QueryClientsResponseEx[] responses = MinerClientMqBodyUtil.GetAutoQueryClientsResponseMqReceiveBody(ea.Body);
+                    if (responses != null && responses.Length != 0) {
+                        var timestamp = ea.GetTimestamp();
+                        foreach (var response in responses) {
+                            VirtualRoot.RaiseEvent(new QueryClientsForWsResponseMqEvent(appId, mqCorrelationId, timestamp, response.LoginName, response.StudioId, response.SessionId, response));
+                        }
+                    }
                 }
             };
         }

+ 2 - 4
src/WsServer/Core/Mq/Senders/IMinerClientMqSender.cs

@@ -7,9 +7,7 @@ namespace NTMiner.Core.Mq.Senders {
         void SendMinerClientWsClosed(Guid clientId);
         void SendMinerClientsWsBreathed(Guid[] clientIds);
         void SendMinerSignsSeted(MinerSign[] minerSigns);
-        void SendQueryClientsForWs(
-            Guid studioId, 
-            string sessionId, 
-            QueryClientsForWsRequest request);
+        void SendQueryClientsForWs(QueryClientsForWsRequest request);
+        void SendAutoQueryClientsForWs(QueryClientsForWsRequest[] requests);
     }
 }

+ 16 - 8
src/WsServer/Core/Mq/Senders/Impl/MinerClientMqSender.cs

@@ -54,20 +54,28 @@ namespace NTMiner.Core.Mq.Senders.Impl {
                 body: MinerClientMqBodyUtil.GetMinerSignsMqSendBody(minerSigns));
         }
 
-        public void SendQueryClientsForWs(
-            Guid studioId, 
-            string sessionId, 
-            QueryClientsForWsRequest request) {
-            if (string.IsNullOrEmpty(sessionId) || request == null || string.IsNullOrEmpty(request.LoginName)) {
+        public void SendQueryClientsForWs(QueryClientsForWsRequest request) {
+            if (request == null || string.IsNullOrEmpty(request.LoginName) || string.IsNullOrEmpty(request.SessionId)) {
                 return;
             }
-            var basicProperties = CreateNonePersistentWsBasicProperties(request.LoginName, studioId, sessionId);
+            var basicProperties = CreateNonePersistentWsBasicProperties(request.LoginName, request.StudioId, request.SessionId);
             _mq.BasicPublish(
                 routingKey: MqKeyword.QueryClientsForWsRoutingKey,
                 basicProperties: basicProperties,
                 body: MinerClientMqBodyUtil.GetQueryClientsForWsMqSendBody(request));
         }
 
+        public void SendAutoQueryClientsForWs(QueryClientsForWsRequest[] requests) {
+            if (requests == null || requests.Length == 0) {
+                return;
+            }
+            var basicProperties = CreateNonePersistentBasicProperties();
+            _mq.BasicPublish(
+                routingKey: MqKeyword.AutoQueryClientsForWsRoutingKey,
+                basicProperties: basicProperties,
+                body: MinerClientMqBodyUtil.GetAutoQueryClientsForWsMqSendBody(requests));
+        }
+
         private IBasicProperties CreateNonePersistentBasicProperties() {
             var basicProperties = _mq.CreateBasicProperties();
             basicProperties.Persistent = false;// 非持久化的
@@ -81,9 +89,9 @@ namespace NTMiner.Core.Mq.Senders.Impl {
             basicProperties.Persistent = false;// 非持久化的
             basicProperties.Expiration = MqKeyword.Expiration36sec;
             basicProperties.Headers = new Dictionary<string, object> {
-                [MqKeyword.LoginNameHeaderName] = loginName,
                 [MqKeyword.StudioIdHeaderName] = studioId.ToString(),
-                [MqKeyword.SessionIdHeaderName] = sessionId
+                [MqKeyword.SessionIdHeaderName] = sessionId,
+                [MqKeyword.LoginNameHeaderName] = loginName
             };
 
             return basicProperties;

+ 17 - 0
src/WsServer/MqBufferRoot.cs

@@ -5,6 +5,7 @@ using System.Collections.Generic;
 using System.Collections.Concurrent;
 using System.Threading.Tasks;
 using System.Linq;
+using NTMiner.Core.MinerServer;
 
 namespace NTMiner {
     public static class MqBufferRoot {
@@ -27,10 +28,13 @@ namespace NTMiner {
         private static readonly object _lockForLocalMessageses = new object();
         private static readonly List<OperationResults> _operationResultses = new List<OperationResults>();
         private static readonly object _lockForOperationResultses = new object();
+        private static readonly List<QueryClientsForWsRequest> _autoQueryClientDatas = new List<QueryClientsForWsRequest>();
+        private static readonly object _lockForAutoQueryClientDatas = new object();
 
         static MqBufferRoot() {
             // 这样做以消减WebApiServer收到的Mq消息的数量,能消减90%以上,降低CPU使用率
             // 还可以继续消减,将这每秒钟6个Mq消息消减到1个,但是感觉没有什么必要了。
+            // WsServer全是2核4G内存的windows
             VirtualRoot.BuildEventPath<Per1SecondEvent>("每1秒钟将暂存的数据发送到Mq", LogEnum.None, typeof(MqBufferRoot), PathPriority.Normal, message => {
                 Task.Factory.StartNew(() => {
                     Guid[] clientIds;
@@ -99,6 +103,13 @@ namespace NTMiner {
                         _operationResultses.Clear();
                     }
                     AppRoot.OperationMqSender.SendOperationResultses(operationResultses);
+
+                    QueryClientsForWsRequest[] queryClientsRequests;
+                    lock (_lockForAutoQueryClientDatas) {
+                        queryClientsRequests = _autoQueryClientDatas.ToArray();
+                        _autoQueryClientDatas.Clear();
+                    }
+                    AppRoot.MinerClientMqSender.SendAutoQueryClientsForWs(queryClientsRequests);
                 });
             });
             VirtualRoot.BuildEventPath<Per1MinuteEvent>("周期清理内存中过期的fastId", LogEnum.None, typeof(MqBufferRoot), PathPriority.Normal, message => {
@@ -177,5 +188,11 @@ namespace NTMiner {
                 _operationResultses.Add(operationResults);
             }
         }
+
+        public static void AutoQueryClientDatas(QueryClientsForWsRequest query) {
+            lock (_lockForAutoQueryClientDatas) {
+                _autoQueryClientDatas.Add(query);
+            }
+        }
     }
 }

+ 7 - 1
src/WsServer/WsMessageFromMinerStudioHandler.cs

@@ -176,7 +176,13 @@ namespace NTMiner {
                 [WsMessage.QueryClientDatas] = (session, studioId, message) => {
                     if (message.TryGetData(out QueryClientsRequest query)) {
                         ServerRoot.IfStudioClientTestIdLogElseNothing(studioId, $"{nameof(WsMessage)}.{nameof(WsMessage.QueryClientDatas)}");
-                        AppRoot.MinerClientMqSender.SendQueryClientsForWs(studioId, session.WsSessionId, QueryClientsForWsRequest.Create(query, session.LoginName));
+                        AppRoot.MinerClientMqSender.SendQueryClientsForWs(QueryClientsForWsRequest.Create(query, session.LoginName, studioId, session.WsSessionId));
+                    }
+                },
+                [WsMessage.AutoQueryClientDatas] = (session, studioId, message) => {
+                    if (message.TryGetData(out QueryClientsRequest query)) {
+                        ServerRoot.IfStudioClientTestIdLogElseNothing(studioId, $"{nameof(WsMessage)}.{nameof(WsMessage.AutoQueryClientDatas)}");
+                        MqBufferRoot.AutoQueryClientDatas(QueryClientsForWsRequest.Create(query, session.LoginName, studioId, session.WsSessionId));
                     }
                 }
             };