Exemple #1
0
        static void Main()
        {
            VirtualRoot.SetOut(new ConsoleOut());
            NTMinerConsole.MainUiOk();
            NTMinerConsole.DisbleQuickEditMode();
            try {
                VirtualRoot.StartTimer();
                // 将服务器地址设为localhost从而使用内网ip访问免于验证用户名密码
                RpcRoot.SetOfficialServerAddress(NTKeyword.Localhost);
                NTMinerRegistry.SetAutoBoot("NTMiner.CalcConfigUpdater", true);
                VirtualRoot.BuildEventPath <Per10MinuteEvent>("每10分钟更新收益计算器", LogEnum.DevConsole, location: typeof(Program), PathPriority.Normal,
                                                              path: message => {
                    UpdateAsync();
                });
                UpdateAsync();
                NTMinerConsole.UserInfo("输入exit并回车可以停止服务!");

                while (Console.ReadLine() != "exit")
                {
                }

                NTMinerConsole.UserOk($"服务停止成功: {DateTime.Now.ToString()}.");
            }
            catch (Exception e) {
                Logger.ErrorDebugLine(e);
            }

            System.Threading.Thread.Sleep(1000);
        }
Exemple #2
0
 static void Main(string[] args) {
     SetOut(new ConsoleOut());
     NTMinerConsole.MainUiOk();
     if (args.Length != 0) {
         if (args.Contains("--sha1", StringComparer.OrdinalIgnoreCase)) {
             File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sha1"), Sha1);
             return;
         }
     }
     try {
         SystemEvents.SessionEnding += SessionEndingEventHandler;
         StartTimer();
         _waitHandle = new AutoResetEvent(false);
         bool mutexCreated;
         try {
             _sMutexApp = new Mutex(true, "NTMinerDaemonAppMutex", out mutexCreated);
         }
         catch {
             mutexCreated = false;
         }
         if (mutexCreated) {
             if (!DevMode.IsDevMode) {
                 NTMinerConsole.Disable();
             }
             NTMinerRegistry.SetDaemonVersion(Sha1);
             NTMinerRegistry.SetAutoBoot("NTMinerDaemon", true);
             if (!CommandLineArgs.Args.Contains("--bootByMinerClient")) {
                 #region 是否自动启动挖矿端
                 bool isAutoBoot = MinerProfileUtil.GetIsAutoBoot();
                 if (isAutoBoot) {
                     string location = NTMinerRegistry.GetLocation(NTMinerAppType.MinerClient);
                     if (!string.IsNullOrEmpty(location) && File.Exists(location)) {
                         string processName = Path.GetFileName(location);
                         Process[] processes = Process.GetProcessesByName(processName);
                         if (processes.Length == 0) {
                             string arguments = NTMinerRegistry.GetMinerClientArguments(NTMinerAppType.MinerClient);
                             try {
                                 Process.Start(location, arguments);
                                 NTMinerConsole.DevOk(() => $"启动挖矿端 {location} {arguments}");
                             }
                             catch (Exception e) {
                                 Logger.ErrorDebugLine($"启动挖矿端失败因为异常 {location} {arguments}", e);
                             }
                         }
                         else {
                             NTMinerConsole.DevDebug($"挖矿端已经在运行中无需启动");
                         }
                     }
                 }
                 #endregion
             }
             Run();
         }
     }
     catch (Exception e) {
         Logger.ErrorDebugLine(e);
     }
 }
Exemple #3
0
        static void Main()
        {
            VirtualRoot.SetOut(new ConsoleOut());
            NTMinerConsole.MainUiOk();
            NTMinerConsole.DisbleQuickEditMode();
            DevMode.SetDevMode();

            Windows.ConsoleHandler.Register(Exit);

            string thisServerAddress = ServerRoot.HostConfig.ThisServerAddress;

            Console.Title = $"{ServerAppType.WsServer.GetName()}_{thisServerAddress}";
            // 用本节点的地址作为队列名,消费消息时根据路由键区分消息类型
            string queue        = $"{ServerAppType.WsServer.GetName()}.{thisServerAddress}";
            string durableQueue = queue + MqKeyword.DurableQueueEndsWith;

            AbstractMqMessagePath[] mqMessagePaths = new AbstractMqMessagePath[] {
                new ReadOnlyUserMqMessagePath(durableQueue),
                new MinerSignMqMessagePath(queue),
                new WsServerNodeMqMessagePath(queue),
                new OperationMqMessagePath(queue),
                new MinerClientMqMessagePath(queue, thisServerAddress),
                new ClientTestIdMqMessagePath(queue)
            };
            if (!MqRedis.Create(ServerAppType.WsServer, mqMessagePaths, out IMqRedis mqRedis))
            {
                NTMinerConsole.UserError("启动失败,无法继续,因为服务器上下文创建失败");
                return;
            }
            MinerClientMqSender    = new MinerClientMqSender(mqRedis);
            SpeedDataRedis         = new SpeedDataRedis(mqRedis);
            WsServerNodeRedis      = new WsServerNodeRedis(mqRedis);
            OperationMqSender      = new OperationMqSender(mqRedis);
            UserMqSender           = new UserMqSender(mqRedis);
            _wsServerNodeMqSender  = new WsServerNodeMqSender(mqRedis);
            WsServerNodeAddressSet = new WsServerNodeAddressSet(WsServerNodeRedis, _wsServerNodeMqSender);
            var minerRedis = new MinerDataRedis(mqRedis);
            var userRedis  = new ReadOnlyUserDataRedis(mqRedis);

            VirtualRoot.StartTimer();
            // 构造函数中异步访问redis初始化用户列表,因为是异步的所以提前构造
            UserSet               = new ReadOnlyUserSet(userRedis);
            MinerSignSet          = new MinerSignSet(minerRedis);
            _wsServer             = new SharpWsServerAdapter(ServerRoot.HostConfig);
            MinerClientSessionSet = new MinerClientSessionSet(_wsServer.MinerClientWsSessions);
            MinerStudioSessionSet = new MinerStudioSessionSet(_wsServer.MinerStudioWsSessions);
            _started              = _wsServer.Start();
            if (!_started)
            {
                NTMinerConsole.UserError("启动失败,无法继续,因为_wsServer启动失败");
                return;
            }
            VirtualRoot.RaiseEvent(new WebSocketServerStatedEvent());

            Console.ReadKey(true);
            Exit();
        }
Exemple #4
0
 static void Main(string[] args)
 {
     if (args.Length != 0)
     {
         if (args.Contains("--sha1", StringComparer.OrdinalIgnoreCase))
         {
             File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sha1"), Sha1);
             return;
         }
         else if (args.Contains("--ExtractCosturaCompressedDlls", StringComparer.OrdinalIgnoreCase))
         {
             CosturaUtil.ExtractCosturaCompressedDlls();
             return;
         }
     }
     try {
         NTMinerConsole.MainUiOk();
         if (DevMode.IsDevMode)
         {
             NTMinerConsole.GetOrAlloc();
         }
         SystemEvents.SessionEnding += SessionEndingEventHandler;
         StartTimer();
         _waitHandle = new AutoResetEvent(false);
         bool mutexCreated;
         try {
             _sMutexApp = new Mutex(true, "NTMinerNoDevFeeAppMutex", out mutexCreated);
         }
         catch {
             mutexCreated = false;
         }
         if (mutexCreated)
         {
             if (!DevMode.IsDevMode)
             {
                 NTMinerConsole.Disable();
             }
             NTMinerRegistry.SetNoDevFeeVersion(Sha1);
             NTMinerRegistry.SetAutoBoot("NTMinerNoDevFee", true);
             Run();
         }
     }
     catch (Exception e) {
         Logger.ErrorDebugLine(e);
     }
 }
Exemple #5
0
        static void Main(string[] args)
        {
            VirtualRoot.SetOut(new ConsoleOut());
            NTMinerConsole.MainUiOk();
            NTMinerConsole.DisbleQuickEditMode();
            DevMode.SetDevMode();
            Console.Title = $"{NTKeyword.WoLiuDao}-开源矿工外网群控服务端{NTKeyword.VersionBuild}";
            var defaultColor = Console.ForegroundColor;

            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine("这是开源矿工外网群控服务端程序,和官方运行的服务端功能上完全一样,唯一的区别是官方程序运行在集群上,这个程序运行在用户自己的比如阿里云服务器上,如果您没有上千台矿机建议您直接连接官方的外网群控服务器。");
            Console.ForegroundColor = defaultColor;
            // TODO:搁置,以后再实现,只要能保证官方外网服务器集群的可用性就不需要用户自己部署外网服务器
            Console.WriteLine();
            Console.WriteLine("按任意键退出");
            Console.ReadKey();
        }
Exemple #6
0
        // keyword=eth_submitLogin
        private static void Main(string[] args)
        {
            NTMinerConsole.MainUiOk();
            DevMode.SetDevMode();
            Console.CancelKeyPress += delegate { s_running = false; };

            if (args.Length >= 1)
            {
                _wallet = args[0];
            }
            else
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("未提供钱包地址");
                Console.ResetColor();
                Console.WriteLine("按任意键结束");
                Console.ReadKey();
                return;
            }

            Console.Title = $"{_keyword} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}";

            WinDivertExtract.Extract();

            string filter = $"ip && tcp && tcp.PayloadLength > 100";

            NTMinerConsole.UserInfo(filter);
            var divertHandle = SafeNativeMethods.WinDivertOpen(filter, WINDIVERT_LAYER.WINDIVERT_LAYER_NETWORK, 0, 0);

            try {
                if (divertHandle != IntPtr.Zero)
                {
                    Parallel.ForEach(Enumerable.Range(0, Environment.ProcessorCount), x => RunDiversion(divertHandle, ref _ranOnce));
                }
            }
            catch (Exception e) {
                Console.WriteLine(e.Message, e.StackTrace);
            }
            finally {
                SafeNativeMethods.WinDivertClose(divertHandle);
            }
        }
Exemple #7
0
 protected override void OnStartup(StartupEventArgs e)
 {
     if (AppUtil.GetMutex(NTKeyword.MinerUpdaterAppMutex))
     {
         NotiCenterWindow.ShowWindow();
         this.MainWindow = new MainWindow();
         this.MainWindow.Show();
         VirtualRoot.StartTimer(new WpfTimingEventProducer());
         NTMinerConsole.MainUiOk();
     }
     else
     {
         Process   thatProcess    = null;
         Process   currentProcess = Process.GetCurrentProcess();
         Process[] Processes      = Process.GetProcessesByName(currentProcess.ProcessName);
         foreach (Process process in Processes)
         {
             if (process.Id != currentProcess.Id)
             {
                 // 因为挖矿端和群控端的升级器是同一份程序所以区分一下
                 if (typeof(App).Assembly.Location.Equals(currentProcess.MainModule.FileName, StringComparison.OrdinalIgnoreCase))
                 {
                     thatProcess = process;
                 }
             }
         }
         if (thatProcess != null)
         {
             AppUtil.Show(thatProcess);
         }
         else
         {
             MessageBox.Show("另一个升级器已在运行", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Warning);
         }
         Environment.Exit(0);
         return;
     }
     base.OnStartup(e);
 }
Exemple #8
0
        protected override void OnStartup(StartupEventArgs e)
        {
            if (AppUtil.GetMutex(NTKeyword.MinerClientFinderAppMutex))
            {
                NotiCenterWindow.ShowWindow();
                MainWindow = new MainWindow();
                MainWindow.Show();
                VirtualRoot.StartTimer(new WpfTimingEventProducer());
                NTMinerConsole.MainUiOk();
            }
            else
            {
                Process   thatProcess    = null;
                Process   currentProcess = Process.GetCurrentProcess();
                Process[] Processes      = Process.GetProcessesByName(currentProcess.ProcessName);
                foreach (Process process in Processes)
                {
                    if (process.Id != currentProcess.Id)
                    {
                        thatProcess = process;
                        break;
                    }
                }
                if (thatProcess != null)
                {
                    AppUtil.Show(thatProcess);
                }
                else
                {
                    MessageBox.Show("另一个矿机雷达已在运行", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Warning);
                }
                Environment.Exit(0);
                return;
            }

            base.OnStartup(e);
        }
Exemple #9
0
        static void Main()
        {
            VirtualRoot.SetOut(new ConsoleOut());
            NTMinerConsole.MainUiOk();
            NTMinerConsole.DisbleQuickEditMode();
            DevMode.SetDevMode();

            Windows.ConsoleHandler.Register(Exit);

            try {
                bool mutexCreated;
                try {
                    // 锁名称上带上本节点的端口号,从而允许一个服务器上运行多个WebApiServer节点,这在软升级服务端程序时有用。
                    // 升级WebApiServer程序的时候步骤是:
                    // 1,在另一个端口启动新版本的程序;
                    // 2,让Widnows将来自旧端口的所有tcp请求转发到新端口;
                    // 3,退出旧版本的程序并更新到新版本;
                    // 4,删除第2步添加的Windows的端口转发;
                    // 5,退出第1步运行的节点;
                    // TODO:实现软升级策略
                    _sMutexApp = new Mutex(true, $"NTMinerServicesMutex{ServerRoot.HostConfig.GetServerPort().ToString()}", out mutexCreated);
                }
                catch {
                    mutexCreated = false;
                }
                if (mutexCreated)
                {
                    try {
                        // 用本节点的地址作为队列名,消费消息时根据路由键区分消息类型
                        string queue         = $"{nameof(ServerAppType.WebApiServer)}.{ServerRoot.HostConfig.ThisServerAddress}";
                        string durableQueue  = queue + MqKeyword.DurableQueueEndsWith;
                        string wsBreathQueue = queue + MqKeyword.WsBreathQueueEndsWith;
                        AbstractMqMessagePath[] mqMessagePaths = new AbstractMqMessagePath[] {
                            new UserMqMessagePath(durableQueue),
                            new CalcConfigMqMessagePath(queue),
                            new MinerClientMqMessagePath(queue),
                            new WsBreathMqMessagePath(wsBreathQueue),
                            new OperationMqMessagePath(queue),
                            new MqCountMqMessagePath(queue),
                            new ClientTestIdMqMessagePath(queue)
                        };
                        if (!MqRedis.Create(ServerAppType.WebApiServer, mqMessagePaths, out IMqRedis mqRedis))
                        {
                            NTMinerConsole.UserError("启动失败,无法继续,因为服务器上下文创建失败");
                            return;
                        }
                        Console.Title = $"{nameof(ServerAppType.WebApiServer)}_{ServerRoot.HostConfig.ThisServerAddress}";
                        // 阿里云OSS坑爹比七牛Kodo贵一半
                        CloudFileUrlGenerater = new AliCloudOSSFileUrlGenerater();
                        IRedis redis = mqRedis;
                        IMq    mq    = mqRedis;
                        AdminMqSender         = new AdminMqSender(mq);
                        ClientTestIdDataRedis = new ClientTestIdDataRedis(redis);
                        var minerClientMqSender = new MinerClientMqSender(mq);
                        var userMqSender        = new UserMqSender(mq);
                        var calcConfigMqSender  = new CalcConfigMqSender(mq);

                        var minerRedis          = new MinerDataRedis(redis);
                        var clientActiveOnRedis = new ClientActiveOnRedis(redis);
                        var speedDataRedis      = new SpeedDataRedis(redis);
                        var userRedis           = new UserDataRedis(redis);
                        var captchaRedis        = new CaptchaDataRedis(redis);
                        var calcConfigRedis     = new CalcConfigDataRedis(redis);

                        MqCountSet             = new MqCountSet();
                        WsServerNodeRedis      = new WsServerNodeRedis(redis);
                        WsServerNodeAddressSet = new WsServerNodeAddressSet(WsServerNodeRedis);
                        UserSet           = new UserSet(userRedis, userMqSender);
                        UserAppSettingSet = new UserAppSettingSet();
                        CaptchaSet        = new CaptchaSet(captchaRedis);
                        CalcConfigSet     = new CalcConfigSet(calcConfigRedis, calcConfigMqSender);
                        NTMinerWalletSet  = new NTMinerWalletSet();
                        GpuNameSet        = new GpuNameSet();
                        ClientDataSet clientDataSet = new ClientDataSet(minerRedis, clientActiveOnRedis, speedDataRedis, minerClientMqSender);
                        ClientDataSet = clientDataSet;
                        var operationMqSender = new OperationMqSender(mq);
                        MineWorkSet            = new UserMineWorkSet(operationMqSender);
                        MinerGroupSet          = new UserMinerGroupSet();
                        NTMinerFileSet         = new NTMinerFileSet();
                        OverClockDataSet       = new OverClockDataSet();
                        KernelOutputKeywordSet = new KernelOutputKeywordSet(SpecialPath.LocalDbFileFullName);
                        ServerMessageSet       = new ServerMessageSet(SpecialPath.LocalDbFileFullName);
                        if (VirtualRoot.LocalAppSettingSet.TryGetAppSetting(nameof(KernelOutputKeywordTimestamp), out IAppSetting appSetting) && appSetting.Value is DateTime value)
                        {
                            KernelOutputKeywordTimestamp = value;
                        }
                        else
                        {
                            KernelOutputKeywordTimestamp = Timestamp.UnixBaseTime;
                        }
                    }
                    catch (Exception e) {
                        NTMinerConsole.UserError(e.Message);
                        NTMinerConsole.UserError(e.StackTrace);
                        NTMinerConsole.UserInfo("按任意键退出");
                        Console.ReadKey();
                        return;
                    }
                    VirtualRoot.StartTimer();
                    NTMinerRegistry.SetAutoBoot("NTMinerServices", true);
                    Type thisType = typeof(AppRoot);
                    Run();
                }
            }
            catch (Exception e) {
                Logger.ErrorDebugLine(e);
            }
        }
Exemple #10
0
 private void DoRun()
 {
     if (AppUtil.GetMutex(NTKeyword.MinerClientAppMutex))
     {
         NotiCenterWindow.ShowWindow();
         Logger.InfoDebugLine($"==================NTMiner.exe {EntryAssemblyInfo.CurrentVersionStr}==================");
         // 在另一个UI线程运行欢迎界面以确保欢迎界面的响应不被耗时的主界面初始化过程阻塞
         // 注意:必须确保SplashWindow没有用到任何其它界面用到的依赖对象
         SplashWindow splashWindow = null;
         SplashWindow.ShowWindowAsync(window => {
             splashWindow = window;
         });
         if (!NTMiner.Windows.WMI.IsWmiEnabled)
         {
             DialogWindow.ShowHardDialog(new DialogWindowViewModel(
                                             message: "开源矿工无法运行所需的组件,因为本机未开启WMI服务,开源矿工需要使用WMI服务检测windows的内存、显卡等信息,请先手动开启WMI。",
                                             title: "提醒",
                                             icon: "Icon_Error"));
             Shutdown();
             Environment.Exit(0);
         }
         if (!NTMiner.Windows.Role.IsAdministrator)
         {
             NotiCenterWindowViewModel.Instance.Manager
             .CreateMessage()
             .Warning("提示", "请以管理员身份运行。")
             .WithButton("点击以管理员身份运行", button => {
                 WpfUtil.RunAsAdministrator();
             })
             .Dismiss().WithButton("忽略", button => {
             }).Queue();
         }
         BuildPaths();
         NTMinerContext.Instance.Init(() => {
             VirtualRoot.BuildCmdPath <ShowSignUpPageCommand>(path: message => {
                 UIThread.Execute(() => {
                     SignUpPage.ShowWindow();
                 });
             }, location: this.GetType());
             _appViewFactory.BuildPaths();
             if (VirtualRoot.IsLTWin10)
             {
                 VirtualRoot.ThisLocalWarn(nameof(App), AppRoot.LowWinMessage, toConsole: true);
             }
             if (NTMinerContext.Instance.GpuSet.Count == 0)
             {
                 VirtualRoot.ThisLocalError(nameof(App), "没有矿卡或矿卡未驱动。", toConsole: true);
             }
             if (NTMinerContext.WorkType != WorkType.None && NTMinerContext.Instance.ServerContext.CoinSet.Count == 0)
             {
                 VirtualRoot.ThisLocalError(nameof(App), "访问阿里云失败,请尝试更换本机dns解决此问题。", toConsole: true);
             }
             UIThread.Execute(() => {
                 Window mainWindow  = null;
                 AppRoot.NotifyIcon = ExtendedNotifyIcon.Create("开源矿工", isMinerStudio: false);
                 if (NTMinerRegistry.GetIsNoUi() && NTMinerContext.Instance.MinerProfile.IsAutoStart)
                 {
                     ConsoleWindow.Instance.Hide();
                     VirtualRoot.Out.ShowSuccess("以无界面模式启动,可在选项页调整设置", header: "开源矿工");
                 }
                 else
                 {
                     _appViewFactory.ShowMainWindow(isToggle: false, out mainWindow);
                 }
                 // 主窗口显式后退出SplashWindow
                 splashWindow?.Dispatcher.Invoke((Action) delegate() {
                     splashWindow?.OkClose();
                 });
                 // 启动时Windows状态栏显式的是SplashWindow的任务栏图标,SplashWindow关闭后激活主窗口的Windows任务栏图标
                 mainWindow?.Activate();
                 StartStopMineButtonViewModel.Instance.AutoStart();
                 // 注意:因为推迟到这里才启动的计时器,所以别忘了在Upgrade、和Action情况时启动计时器
                 VirtualRoot.StartTimer(new WpfTimingEventProducer());
                 if (CommandLineArgs.Action.TryParse(out MinerClientActionType resourceType))
                 {
                     VirtualRoot.Execute(new MinerClientActionCommand(resourceType));
                 }
                 NTMinerConsole.MainUiOk();
             });
             Task.Factory.StartNew(() => {
                 var minerProfile = NTMinerContext.Instance.MinerProfile;
                 if (minerProfile.IsDisableUAC)
                 {
                     NTMiner.Windows.UAC.DisableUAC();
                 }
                 if (minerProfile.IsAutoDisableWindowsFirewall)
                 {
                     Firewall.DisableFirewall();
                 }
                 if (minerProfile.IsDisableWAU)
                 {
                     NTMiner.Windows.WAU.DisableWAUAsync();
                 }
                 if (minerProfile.IsDisableAntiSpyware)
                 {
                     NTMiner.Windows.Defender.DisableAntiSpyware();
                 }
                 NTMiner.Windows.Crash.SetAutoReboot(minerProfile.IsAutoReboot);
                 if (!Firewall.IsMinerClientRuleExists())
                 {
                     Firewall.AddMinerClientRule();
                 }
                 try {
                     HttpServer.Start($"http://{NTKeyword.Localhost}:{NTKeyword.MinerClientPort.ToString()}");
                     Daemon.DaemonUtil.RunNTMinerDaemon();
                     NoDevFee.NoDevFeeUtil.RunNTMinerNoDevFee();
                 }
                 catch (Exception ex) {
                     Logger.ErrorDebugLine(ex);
                 }
             });
         });
     }
     else
     {
         try {
             _appViewFactory.ShowMainWindow(this);
         }
         catch (Exception) {
             DialogWindow.ShowSoftDialog(new DialogWindowViewModel(
                                             message: "另一个开源矿工正在运行但唤醒失败,请重试。",
                                             title: "错误",
                                             icon: "Icon_Error"));
             Process currentProcess = Process.GetCurrentProcess();
             NTMiner.Windows.TaskKill.KillOtherProcess(currentProcess);
         }
     }
 }
Exemple #11
0
 protected override void OnStartup(StartupEventArgs e)
 {
     // 之所以提前到这里是因为升级之前可能需要下载升级器,下载升级器时需要下载器
     VirtualRoot.BuildCmdPath <ShowFileDownloaderCommand>(path: message => {
         FileDownloader.ShowWindow(message.DownloadFileUrl, message.FileTitle, message.DownloadComplete);
     }, location: this.GetType());
     VirtualRoot.BuildCmdPath <UpgradeCommand>(path: message => {
         AppRoot.Upgrade(message.FileName, message.Callback);
     }, location: this.GetType());
     VirtualRoot.BuildCmdPath <ShowSignUpPageCommand>(path: message => {
         UIThread.Execute(() => {
             SignUpPage.ShowWindow();
         });
     }, location: this.GetType());
     if (AppUtil.GetMutex(NTKeyword.MinerStudioAppMutex))
     {
         this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
         // 因为登录窗口会用到VirtualRoot.Out,而Out的延迟自动关闭消息会用到倒计时
         VirtualRoot.StartTimer(new WpfTimingEventProducer());
         NotiCenterWindow.ShowWindow();
         AppRoot.RemoteDesktop = MsRemoteDesktop.OpenRemoteDesktop;
         MinerStudioRoot.Login(() => {
             MinerStudioRoot.Init(new MinerStudioWsClient());
             _ = MinerStudioRoot.MinerStudioService;// 访问一下从而提前拉取本地服务数据
             NTMinerContext.Instance.Init(() => {
                 _appViewFactory.BuildPaths();
                 UIThread.Execute(() => {
                     MinerStudioRoot.MinerClientsWindowVm.OnPropertyChanged(nameof(MinerStudioRoot.MinerClientsWindowVm.NetTypeText));
                     if (RpcRoot.IsOuterNet)
                     {
                         MinerStudioRoot.MinerClientsWindowVm.QueryMinerClients();
                     }
                     else
                     {
                         VirtualRoot.BuildOnecePath <ClientSetInitedEvent>("刷新矿机列表界面", LogEnum.DevConsole, path: message => {
                             MinerStudioRoot.MinerClientsWindowVm.QueryMinerClients();
                         }, pathId: PathId.Empty, this.GetType());
                     }
                     AppRoot.NotifyIcon = ExtendedNotifyIcon.Create("群控客户端", isMinerStudio: true);
                     VirtualRoot.Execute(new ShowMinerClientsWindowCommand(isToggle: false));
                     NTMinerConsole.MainUiOk();
                 });
             });
         }, btnCloseClick: () => {
             Shutdown();
         });
         #region 处理显示主界面命令
         VirtualRoot.BuildCmdPath <ShowMainWindowCommand>(path: message => {
             VirtualRoot.Execute(new ShowMinerClientsWindowCommand(isToggle: message.IsToggle));
         }, location: this.GetType());
         #endregion
         HttpServer.Start($"http://{NTKeyword.Localhost}:{NTKeyword.MinerStudioPort.ToString()}");
     }
     else
     {
         try {
             _appViewFactory.ShowMainWindow(this);
         }
         catch (Exception) {
             DialogWindow.ShowSoftDialog(new DialogWindowViewModel(
                                             message: "另一个群控客户端正在运行但唤醒失败,请重试。",
                                             title: "错误",
                                             icon: "Icon_Error"));
             Process currentProcess = Process.GetCurrentProcess();
             NTMiner.Windows.TaskKill.KillOtherProcess(currentProcess);
         }
     }
     base.OnStartup(e);
 }