/// <summary> /// propertyName必须是数值类型的属性。注意:只支持int和double类型。 /// 基于反射将给定类型对象的给定名称的属性值自增。 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="vm"></param> /// <param name="propertyName"></param> public static void Up <T>(T vm, string propertyName) where T : ViewModelBase { Type type = typeof(T); var propertyInfo = type.GetProperty(propertyName); if (propertyInfo == null) { NTMinerConsole.DevError(() => $"类型{type.FullName}不具有名称为{propertyName}的属性"); return; } if (propertyInfo.PropertyType == typeof(int)) { propertyInfo.SetValue(vm, (int)propertyInfo.GetValue(vm, null) + 1, null); } else if (propertyInfo.PropertyType == typeof(double)) { propertyInfo.SetValue(vm, Math.Round((double)propertyInfo.GetValue(vm, null) + 0.1, 2), null); } }
// 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); } }
/// <summary> /// 内部完成redis连接的创建和mq交换器、队列的声明以及mq消费者的启动,队列和交换器的绑定由启动的消费者负责。 /// (mq消费者的启动是异步的,不会立即启动,而是在满足了后续的条件后才会启动)。 /// </summary> /// <param name="serverAppType"></param> /// <param name="mqMessagePaths"></param> /// <returns></returns> public static bool Create(ServerAppType serverAppType, AbstractMqMessagePath[] mqMessagePaths, out IServerConnection serverConfig) { string mqClientTypeName = serverAppType.GetName(); serverConfig = null; ConnectionMultiplexer redisConn; try { redisConn = ConnectionMultiplexer.Connect(ServerRoot.HostConfig.RedisConfig); } catch (Exception e) { NTMinerConsole.UserError("连接redis失败"); Logger.ErrorDebugLine(e); return(false); } IConnection connection;// TODO:需要一个机制在连接关闭时重新连接,因为AutomaticRecovery也会失败 try { var factory = new ConnectionFactory { HostName = ServerRoot.HostConfig.MqHostName, UserName = ServerRoot.HostConfig.MqUserName, Password = ServerRoot.HostConfig.MqPassword, AutomaticRecoveryEnabled = true, // 默认值也是true,复述一遍起文档作用 TopologyRecoveryEnabled = true // 默认值也是true,复述一遍起文档作用 }; connection = factory.CreateConnection(mqClientTypeName); } catch (Exception e) { NTMinerConsole.UserError("连接Mq失败"); Logger.ErrorDebugLine(e); return(false); } IModel channel = connection.CreateModel(); channel.ExchangeDeclare(MqKeyword.NTMinerExchange, ExchangeType.Direct, durable: true, autoDelete: false, arguments: null); StartConsumer(channel, mqMessagePaths); serverConfig = new ServerConnection(redisConn, channel); return(true); }
static void Main(string[] args) { HomePath.SetHomeDirFullName(AppDomain.CurrentDomain.BaseDirectory); if (args.Length != 0) { if (args.Contains("--sha1")) { File.WriteAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sha1"), Sha1); return; } } try { 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) { Write.Disable(); } NTMinerRegistry.SetNoDevFeeVersion(Sha1); NTMinerRegistry.SetAutoBoot("NTMinerNoDevFee", true); Run(); } } catch (Exception e) { Logger.ErrorDebugLine(e); } }
/// <summary> /// 如果创建失败返回null。内部完成redis连接的创建和mq交换器、队列的声明以及mq消费者的启动 /// (mq消费者的启动是异步的,不会立即启动,而是在满足了后续的条件后才会启动)。 /// </summary> /// <param name="mqClientTypeName"></param> /// <param name="mqMessagePaths"></param> /// <returns></returns> public static ServerConfig Create(string mqClientTypeName, params AbstractMqMessagePath[] mqMessagePaths) { ConnectionMultiplexer redisConn; try { redisConn = ConnectionMultiplexer.Connect(ServerRoot.HostConfig.RedisConfig); } catch (Exception e) { NTMinerConsole.UserError("连接redis失败"); Logger.ErrorDebugLine(e); return(null); } IConnection connection; try { var factory = new ConnectionFactory() { HostName = ServerRoot.HostConfig.MqHostName, UserName = ServerRoot.HostConfig.MqUserName, Password = ServerRoot.HostConfig.MqPassword, AutomaticRecoveryEnabled = true, // 默认值也是true,复数一遍起文档作用 TopologyRecoveryEnabled = true // 默认值也是true,复数一遍起文档作用 }; connection = factory.CreateConnection(mqClientTypeName); } catch (Exception e) { NTMinerConsole.UserError("连接Mq失败"); Logger.ErrorDebugLine(e); return(null); } IModel channel = connection.CreateModel(); channel.ExchangeDeclare(MqKeyword.NTMinerExchange, ExchangeType.Direct, durable: true, autoDelete: false, arguments: null); if (mqMessagePaths != null && mqMessagePaths.Length != 0) { StartConsumer(channel, mqMessagePaths); } return(new ServerConfig(redisConn, channel)); }
private void Init() { #if DEBUG NTStopwatch.Start(); #endif lock (_locker) { if (!_isInited) { _isInited = true; _localIps = GetLocalIps(); RaiseEvent(new LocalIpSetInitedEvent()); } } #if DEBUG // 将近300毫秒 var elapsedMilliseconds = NTStopwatch.Stop(); if (elapsedMilliseconds.ElapsedMilliseconds > NTStopwatch.ElapsedMilliseconds) { NTMinerConsole.DevTimeSpan($"耗时{elapsedMilliseconds} {this.GetType().Name}.{nameof(Init)}"); } #endif }
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); }
protected override void OnMessage(MessageEventArgs e) { IMinerClientSession minerSession; if (e.IsPing) { if (WsRoot.MinerClientSessionSet.ActiveByWsSessionId(base.ID, out minerSession)) { WsRoot.MinerClientMqSender.SendMinerClientWsBreathed(minerSession.LoginName, minerSession.ClientId); } return; } WsMessage message = e.ToWsMessage <WsMessage>(); if (message == null) { return; } if (!WsRoot.MinerClientSessionSet.TryGetByWsSessionId(this.ID, out minerSession)) { this.CloseAsync(CloseStatusCode.Normal, "意外,会话不存在,请重新连接"); return; } else if (MinerClientWsMessageHandler.TryGetHandler(message.Type, out Action <MinerClientBehavior, string, Guid, WsMessage> handler)) { try { handler.Invoke(this, minerSession.LoginName, minerSession.ClientId, message); } catch (Exception ex) { Logger.ErrorDebugLine(ex); } } else { NTMinerConsole.UserWarn($"{_behaviorName} {nameof(OnMessage)} Received InvalidType {e.Data}"); } }
protected override void OnStartup(StartupEventArgs e) { if (AppUtil.GetMutex(NTKeyword.MinerClientFinderAppMutex)) { NotiCenterWindow.ShowWindow(); MainWindow = new MainWindow(); MainWindow.Show(); VirtualRoot.StartTimer(new WpfTimingEventProducer()); NTMinerConsole.SetIsMainUiOk(true); } 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); }
/// <summary> /// 注意:Request时原始HttpContent,Fire忽略Response /// </summary> /// <param name="host"></param> /// <param name="port"></param> /// <param name="controller"></param> /// <param name="action"></param> /// <param name="query"></param> /// <param name="content"></param> /// <param name="callback"></param> /// <param name="timeountMilliseconds"></param> public static void FirePostAsync( string host, int port, string controller, string action, Dictionary <string, string> query, HttpContent content, Action callback = null, int timeountMilliseconds = 0) { Task.Factory.StartNew(() => { try { using (HttpClient client = RpcRoot.CreateHttpClient()) { client.SetTimeout(timeountMilliseconds); Task <HttpResponseMessage> getHttpResponse = client.PostAsync($"http://{host}:{port.ToString()}/api/{controller}/{action}{query.ToQueryString()}", content); NTMinerConsole.DevDebug($"{action} {getHttpResponse.Result.ReasonPhrase}"); callback?.Invoke(); } } catch { callback?.Invoke(); } }); }
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); }
protected override void OnExit(ExitEventArgs e) { VirtualRoot.RaiseEvent(new AppExitEvent()); base.OnExit(e); NTMinerConsole.Free(); }
private void Init() { #if DEBUG NTStopwatch.Start(); #endif lock (_locker) { if (!_isInited) { _isInited = true; NetworkChange.NetworkAddressChanged += (object sender, EventArgs e) => { // 延迟获取网络信息以防止立即获取时获取不到 1.SecondsDelay().ContinueWith(t => { var old = _localIps; _isInited = false; InitOnece(); var localIps = _localIps; if (localIps.Length == 0) { ThisLocalWarn(nameof(LocalIpSetImpl), "网络连接已断开", toConsole: true); } else if (old.Length == 0) { ThisLocalInfo(nameof(LocalIpSetImpl), "网络连接已连接", toConsole: true); } }); }; NetworkChange.NetworkAvailabilityChanged += (object sender, NetworkAvailabilityEventArgs e) => { if (e.IsAvailable) { ThisLocalInfo(nameof(LocalIpSetImpl), $"网络可用", toConsole: true); } else { ThisLocalWarn(nameof(LocalIpSetImpl), $"网络不可用", toConsole: true); } }; AddCmdPath <SetLocalIpCommand>(action: message => { #region ManagementObject mo = null; using (ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration")) using (ManagementObjectCollection moc = mc.GetInstances()) { foreach (ManagementObject item in moc) { if ((string)item["SettingID"] == message.Input.SettingID) { mo = item; break; } } } if (mo != null) { if (message.Input.DHCPEnabled) { mo.InvokeMethod("EnableStatic", null); mo.InvokeMethod("SetGateways", null); mo.InvokeMethod("EnableDHCP", null); 1.SecondsDelay().ContinueWith(t => { _isInited = false; InitOnece(); }); } else { ManagementBaseObject inPar = mo.GetMethodParameters("EnableStatic"); inPar["IPAddress"] = new string[] { message.Input.IPAddress }; inPar["SubnetMask"] = new string[] { message.Input.IPSubnet }; mo.InvokeMethod("EnableStatic", inPar, null); inPar = mo.GetMethodParameters("SetGateways"); inPar["DefaultIPGateway"] = new string[] { message.Input.DefaultIPGateway }; mo.InvokeMethod("SetGateways", inPar, null); } if (message.IsAutoDNSServer) { mo.InvokeMethod("SetDNSServerSearchOrder", null); } else { ManagementBaseObject inPar = mo.GetMethodParameters("SetDNSServerSearchOrder"); inPar["DNSServerSearchOrder"] = new string[] { message.Input.DNSServer0, message.Input.DNSServer1 }; mo.InvokeMethod("SetDNSServerSearchOrder", inPar, null); } } #endregion }, location: this.GetType()); _localIps = GetLocalIps(); RaiseEvent(new LocalIpSetInitedEvent()); } } #if DEBUG // 将近300毫秒 var elapsedMilliseconds = NTStopwatch.Stop(); if (elapsedMilliseconds.ElapsedMilliseconds > NTStopwatch.ElapsedMilliseconds) { NTMinerConsole.DevTimeSpan($"耗时{elapsedMilliseconds} {this.GetType().Name}.{nameof(Init)}"); } #endif }
private static void RunDiversion(IntPtr handle, ref bool ranOnce, ref string poolIp) { byte[] packet = new byte[65535]; try { while (s_running) { uint readLength = 0; WINDIVERT_IPHDR * ipv4Header = null; WINDIVERT_TCPHDR *tcpHdr = null; WINDIVERT_ADDRESS addr = new WINDIVERT_ADDRESS(); if (!SafeNativeMethods.WinDivertRecv(handle, packet, (uint)packet.Length, ref addr, ref readLength)) { continue; } if (!ranOnce && readLength > 1) { ranOnce = true; NTMinerConsole.UserInfo("Diversion running.."); } fixed(byte *inBuf = packet) { byte *payload = null; SafeNativeMethods.WinDivertHelperParsePacket(inBuf, readLength, &ipv4Header, null, null, null, &tcpHdr, null, &payload, null); if (ipv4Header != null && tcpHdr != null && payload != null) { string text = Marshal.PtrToStringAnsi((IntPtr)payload); if (!string.IsNullOrEmpty(s_keyword)) { if (text.Contains(s_keyword)) { NTMinerConsole.UserInfo(text); Console.WriteLine(); Console.WriteLine(); Logger.InfoDebugLine(text); } } else { string dstIp = ipv4Header->DstAddr.ToString(); var dstPort = tcpHdr->DstPort; string arrow = $"->{dstIp}:{dstPort.ToString()}"; if (dstIp == poolIp) { arrow = $"{dstIp}:{dstPort.ToString()}<-"; NTMinerConsole.UserInfo($"<-<-<-<-<-<-<-<-<-<-<-<-<-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}<-<-<-<-<-<-<-<-<-<-<-<-<-<-<-"); } else { NTMinerConsole.UserInfo($"->->->->->->->->->->->->->{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")}->->->->->->->->->->->->->->->"); } NTMinerConsole.UserInfo(arrow + text); Console.WriteLine(); Console.WriteLine(); } } } SafeNativeMethods.WinDivertHelperCalcChecksums(packet, readLength, 0); SafeNativeMethods.WinDivertSendEx(handle, packet, readLength, 0, ref addr, IntPtr.Zero, IntPtr.Zero); } } catch (Exception e) { NTMinerConsole.UserInfo(e.ToString()); NTMinerConsole.UserInfo("按任意键退出"); Console.ReadKey(); return; } }
static void Main(string[] args) { SetOut(new ConsoleOut()); 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); } }
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() && NTMinerRegistry.GetIsAutoStart()) { 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.SetIsMainUiOk(true); }); 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(); } 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, NTMinerAppType.MinerClient); } catch (Exception) { DialogWindow.ShowSoftDialog(new DialogWindowViewModel( message: "另一个开源矿工正在运行但唤醒失败,请重试。", title: "错误", icon: "Icon_Error")); Process currentProcess = Process.GetCurrentProcess(); NTMiner.Windows.TaskKill.KillOtherProcess(currentProcess); } } }
private static void UpdateAsync() { Task.Factory.StartNew(() => { try { Task <byte[]> htmlDataTask = GetHtmlAsync("https://www.f2pool.com/"); byte[] htmlData = null; try { Task.WaitAll(new Task[] { htmlDataTask }, 60 * 1000); htmlData = htmlDataTask.Result; } catch { } if (htmlData != null && htmlData.Length != 0) { NTMinerConsole.UserOk($"{DateTime.Now.ToString()} - 鱼池首页html获取成功"); string html = Encoding.UTF8.GetString(htmlData); double usdCny = PickUsdCny(html); NTMinerConsole.UserInfo($"usdCny={usdCny.ToString()}"); List <IncomeItem> incomeItems = PickIncomeItems(html); NTMinerConsole.UserInfo($"鱼池首页有{incomeItems.Count.ToString()}个币种"); FillCny(incomeItems, usdCny); NeatenSpeedUnit(incomeItems); if (incomeItems != null && incomeItems.Count != 0) { RpcRoot.Login(new RpcUser(Config.RpcLoginName, HashUtil.Sha1(Config.RpcPassword))); RpcRoot.SetIsOuterNet(false); RpcRoot.OfficialServer.CalcConfigBinaryService.GetCalcConfigsAsync(data => { NTMinerConsole.UserInfo($"NTMiner有{data.Count.ToString()}个币种"); HashSet <string> coinCodes = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (CalcConfigData calcConfigData in data) { IncomeItem incomeItem = incomeItems.FirstOrDefault(a => string.Equals(a.CoinCode, calcConfigData.CoinCode, StringComparison.OrdinalIgnoreCase)); if (incomeItem != null) { coinCodes.Add(calcConfigData.CoinCode); calcConfigData.Speed = incomeItem.Speed; calcConfigData.SpeedUnit = incomeItem.SpeedUnit; calcConfigData.NetSpeed = incomeItem.NetSpeed; calcConfigData.NetSpeedUnit = incomeItem.NetSpeedUnit; calcConfigData.IncomePerDay = incomeItem.IncomeCoin; calcConfigData.IncomeUsdPerDay = incomeItem.IncomeUsd; calcConfigData.IncomeCnyPerDay = incomeItem.IncomeCny; calcConfigData.ModifiedOn = DateTime.Now; if (calcConfigData.ModifiedOn.AddMinutes(15) > calcConfigData.ModifiedOn.Date.AddDays(1)) { calcConfigData.BaseNetSpeed = calcConfigData.NetSpeed; calcConfigData.BaseNetSpeedUnit = calcConfigData.NetSpeedUnit; } else if (calcConfigData.BaseNetSpeed != 0) { if (calcConfigData.NetSpeedUnit == calcConfigData.BaseNetSpeedUnit) { calcConfigData.DayWave = (calcConfigData.NetSpeed - calcConfigData.BaseNetSpeed) / calcConfigData.BaseNetSpeed; } else { if (string.IsNullOrEmpty(calcConfigData.BaseNetSpeedUnit)) { calcConfigData.BaseNetSpeedUnit = calcConfigData.NetSpeedUnit; } var netSpeed = calcConfigData.NetSpeed.FromUnitSpeed(calcConfigData.NetSpeedUnit); var baseNetSpeed = calcConfigData.BaseNetSpeed.FromUnitSpeed(calcConfigData.BaseNetSpeedUnit); calcConfigData.DayWave = (netSpeed - baseNetSpeed) / baseNetSpeed; } } } } RpcRoot.OfficialServer.CalcConfigService.SaveCalcConfigsAsync(data, callback: (res, e) => { if (!res.IsSuccess()) { VirtualRoot.Out.ShowError(res.ReadMessage(e), autoHideSeconds: 4); } }); foreach (IncomeItem incomeItem in incomeItems) { if (coinCodes.Contains(incomeItem.CoinCode)) { continue; } NTMinerConsole.UserInfo(incomeItem.ToString()); } foreach (var incomeItem in incomeItems) { if (!coinCodes.Contains(incomeItem.CoinCode)) { continue; } NTMinerConsole.UserOk(incomeItem.ToString()); } NTMinerConsole.UserOk($"更新了{coinCodes.Count.ToString()}个币种:{string.Join(",", coinCodes)}"); int unUpdatedCount = data.Count - coinCodes.Count; NTMinerConsole.UserWarn($"{unUpdatedCount.ToString()}个币种未更新{(unUpdatedCount == 0 ? string.Empty : ":" + string.Join(",", data.Select(a => a.CoinCode).Except(coinCodes)))}"); }); } } } catch (Exception e) { Logger.ErrorDebugLine(e); } }); }
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); } }
/// <summary> /// 禁用Write则可以避免行走到NTMinerConsole中去,从而避免创建出Windows控制台 /// </summary> public static void Disable() { _isEnabled = false; NTMinerConsole.Free(); }
private static void StartConsumer(IModel channel, AbstractMqMessagePath[] mqMessagePaths) { if (mqMessagePaths == null || mqMessagePaths.Length == 0) { return; } Task.Factory.StartNew(() => { DateTime startOn = DateTime.Now; // mq消费者不是立即启动的,而是异步启动的,在满足了后续的条件后才会启动的。 while (!mqMessagePaths.All(a => a.IsReadyToBuild)) { if (startOn.AddSeconds(20) < DateTime.Now) { NTMinerConsole.UserFail("订阅Mq失败,因为超时"); return; } System.Threading.Thread.Sleep(100); } foreach (var mqMessagePathsByQueue in mqMessagePaths.GroupBy(a => a.Queue)) { string queue = mqMessagePathsByQueue.Key; bool durable = queue.EndsWith(MqKeyword.DurableQueueEndsWith); bool autoAck = !durable; channel.QueueDeclare( queue: queue, durable: durable, exclusive: false, autoDelete: !durable, arguments: null); EventingBasicConsumer consumer = new EventingBasicConsumer(channel); foreach (var mqMessagePath in mqMessagePathsByQueue) { mqMessagePath.Build(channel); } consumer.Received += (model, ea) => { bool isPass = false; foreach (var mqMessagePath in mqMessagePathsByQueue) { try { if (!isPass) { isPass = mqMessagePath.Go(ea); } else { mqMessagePath.Go(ea); } } catch (Exception e) { Logger.ErrorDebugLine(e); } } if (!isPass) { Logger.WarnDebugLine($"路由键 {ea.RoutingKey} 没有消费者"); } if (!autoAck) { channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); } }; channel.BasicConsume(queue: queue, autoAck: autoAck, consumer: consumer); } NTMinerConsole.UserOk("订阅Mq成功"); }); }
static void Main() { VirtualRoot.SetOut(new ConsoleOut()); NTMinerConsole.MainUiOk(); NTMinerConsole.DisbleQuickEditMode(); DevMode.SetDevMode(); Windows.ConsoleHandler.Register(Exit); string thisServerAddress = ServerRoot.HostConfig.ThisServerAddress; Console.Title = $"{nameof(ServerAppType.WsServer)}_{thisServerAddress}"; // 用本节点的地址作为队列名,消费消息时根据路由键区分消息类型 string queue = $"{nameof(ServerAppType.WsServer)}.{thisServerAddress}"; string durableQueue = queue + MqKeyword.DurableQueueEndsWith; AbstractMqMessagePath[] mqMessagePaths = new AbstractMqMessagePath[] { new ReadOnlyUserMqMessagePath(durableQueue), new CalcConfigMqMessagePath(queue), 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; } IRedis redis = mqRedis; IMq mq = mqRedis; MinerClientMqSender = new MinerClientMqSender(mq); SpeedDataRedis = new SpeedDataRedis(redis); WsServerNodeRedis = new WsServerNodeRedis(redis); OperationMqSender = new OperationMqSender(mq); UserMqSender = new UserMqSender(mq); _wsServerNodeMqSender = new WsServerNodeMqSender(mq); WsServerNodeAddressSet = new WsServerNodeAddressSet(WsServerNodeRedis, _wsServerNodeMqSender); var minerRedis = new MinerDataRedis(redis); var userRedis = new ReadOnlyUserDataRedis(redis); var calcConfigRedis = new CalcConfigDataRedis(redis); VirtualRoot.StartTimer(); // 构造函数中异步访问redis初始化用户列表,因为是异步的所以提前构造 UserSet = new ReadOnlyUserSet(userRedis); MinerSignSet = new MinerSignSet(minerRedis); _wsServer = new SharpWsServerAdapter(ServerRoot.HostConfig); CalcConfigSet = new ReadOnlyCalcConfigSet(calcConfigRedis); 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(); }
/// <summary> /// 执行两个操作: /// 1,记下对Dispatcher.CurrentDispatcher的引用,因为Splash会另开一个UI线程,防止访问到Splash线程的Dispatcher.CurrentDispatcher; /// 2,设置Writer.UIThreadId; /// </summary> public static void InitializeWithDispatcher(Dispatcher dispatcher) { _dispatcher = dispatcher; NTMinerConsole.SetUIThreadId(_dispatcher.Thread.ManagedThreadId); }
public void ShowSuccess(string message, string header = "成功", int autoHideSeconds = 4, bool toConsole = false) { NTMinerConsole.UserOk(message); }
static void Main() { NTMinerConsole.DisbleQuickEditMode(); HomePath.SetHomeDirFullName(AppDomain.CurrentDomain.BaseDirectory); 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 = $"{ServerAppType.WebApiServer.GetName()}.{ServerRoot.HostConfig.ThisServerAddress}"; string durableQueue = queue + MqKeyword.DurableQueueEndsWith; AbstractMqMessagePath[] mqMessagePaths = new AbstractMqMessagePath[] { new UserMqMessagePath(durableQueue), new MinerClientMqMessagePath(queue) }; _serverContext = ServerContext.Create(mqClientTypeName: ServerAppType.WebApiServer.GetName(), mqMessagePaths); if (_serverContext == null) { Write.UserError("启动失败,无法继续,因为服务器上下文创建失败"); return; } Console.Title = $"{ServerAppType.WebApiServer.GetName()}_{ServerRoot.HostConfig.ThisServerAddress}"; _ossClient = new OssClient(ServerRoot.HostConfig.OssEndpoint, ServerRoot.HostConfig.OssAccessKeyId, ServerRoot.HostConfig.OssAccessKeySecret); var minerClientMqSender = new MinerClientMqSender(_serverContext.Channel); var userMqSender = new UserMqSender(_serverContext.Channel); var wsServerNodeMqSender = new WsServerNodeMqSender(_serverContext.Channel); var minerRedis = new MinerRedis(_serverContext.RedisConn); var speedDataRedis = new SpeedDataRedis(_serverContext.RedisConn); var userRedis = new UserRedis(_serverContext.RedisConn); var captchaRedis = new CaptchaRedis(_serverContext.RedisConn); WsServerNodeSet = new WsServerNodeSet(wsServerNodeMqSender); UserSet = new UserSet(userRedis, userMqSender); UserAppSettingSet = new UserAppSettingSet(); CaptchaSet = new CaptchaSet(captchaRedis); CalcConfigSet = new CalcConfigSet(); NTMinerWalletSet = new NTMinerWalletSet(); ClientDataSet clientDataSet = new ClientDataSet(minerRedis, speedDataRedis, minerClientMqSender); ClientDataSet = clientDataSet; CoinSnapshotSet = new CoinSnapshotSet(clientDataSet); MineWorkSet = new UserMineWorkSet(); MinerGroupSet = new UserMinerGroupSet(); NTMinerFileSet = new NTMinerFileSet(); OverClockDataSet = new OverClockDataSet(); KernelOutputKeywordSet = new KernelOutputKeywordSet(SpecialPath.LocalDbFileFullName, isServer: true); ServerMessageSet = new ServerMessageSet(SpecialPath.LocalDbFileFullName, isServer: true); UpdateServerMessageTimestamp(); if (VirtualRoot.LocalAppSettingSet.TryGetAppSetting(nameof(KernelOutputKeywordTimestamp), out IAppSetting appSetting) && appSetting.Value is DateTime value) { KernelOutputKeywordTimestamp = value; } else { KernelOutputKeywordTimestamp = Timestamp.UnixBaseTime; } } catch (Exception e) { Write.UserError(e.Message); Write.UserError(e.StackTrace); Write.UserInfo("按任意键退出"); Console.ReadKey(); return; } VirtualRoot.StartTimer(); NTMinerRegistry.SetAutoBoot("NTMinerServices", true); Type thisType = typeof(WebApiRoot); Run(); } } catch (Exception e) { Logger.ErrorDebugLine(e); } }
public void ShowWarn(string message, string header = "警告", int autoHideSeconds = 0, bool toConsole = false) { NTMinerConsole.UserWarn(message); }
public void ShowError(string message, string header = "错误", int autoHideSeconds = 0, bool toConsole = false) { NTMinerConsole.UserError(message); }
public static Guid GetBrandId(string fileFullName, string keyword) { if (DevMode.IsInUnitTest) { throw new InvalidProgramException("不支持单元测试这个方法,因为该方法的逻辑依赖于主程序集而单元测试时主程序集是null"); } #if DEBUG NTStopwatch.Start(); #endif Guid guid = Guid.Empty; int LEN = keyword.Length; if (fileFullName == AppFileFullName) { Assembly assembly = Assembly.GetEntryAssembly(); string name = $"NTMiner.Brand.{keyword}"; using (var stream = assembly.GetManifestResourceStream(name)) { if (stream == null) { return(guid); } byte[] data = new byte[stream.Length]; stream.Read(data, 0, data.Length); string rawBrand = Encoding.UTF8.GetString(data); string guidString = rawBrand.Substring(LEN, rawBrand.Length - 2 * LEN); Guid.TryParse(guidString, out guid); } } else { string rawBrand = $"{keyword}{Guid.Empty}{keyword}"; byte[] rawData = Encoding.UTF8.GetBytes(rawBrand); int len = rawData.Length; byte[] source = File.ReadAllBytes(fileFullName); int index = 0; for (int i = 0; i < source.Length - len; i++) { int j = 0; for (; j < len; j++) { if ((j < LEN || j > len - LEN) && source[i + j] != rawData[j]) { break; } } if (j == rawData.Length) { index = i; break; } } string guidString = Encoding.UTF8.GetString(source, index + LEN, len - 2 * LEN); Guid.TryParse(guidString, out guid); } #if DEBUG var elapsedMilliseconds = NTStopwatch.Stop(); if (elapsedMilliseconds.ElapsedMilliseconds > NTStopwatch.ElapsedMilliseconds) { NTMinerConsole.DevTimeSpan($"耗时{elapsedMilliseconds} {typeof(VirtualRoot).Name}.GetBrandId"); } #endif return(guid); }
public void Init(Action callback) { Task.Factory.StartNew(() => { bool isSelfWork = Environment.GetCommandLineArgs().Contains("--selfWork", StringComparer.OrdinalIgnoreCase); bool isWork = isSelfWork || Environment.GetCommandLineArgs().Contains("--work", StringComparer.OrdinalIgnoreCase); _workType = isSelfWork ? WorkType.SelfWork : (isWork ? WorkType.MineWork : WorkType.None); if (ClientAppType.IsMinerClient) { NTMinerRegistry.SetWorkType(_workType); } if (isWork) { DoInit(callback); } else { // 如果是Debug模式且不是群控客户端则使用本地数据库初始化 bool useLocalDb = DevMode.IsDevMode && !ClientAppType.IsMinerStudio; if (useLocalDb) { DoInit(callback); } else { Logger.InfoDebugLine(nameof(RpcRoot.OSSService.AliyunOSSService.GetAliyunServerJson)); RpcRoot.OSSService.AliyunOSSService.GetAliyunServerJson((data) => { // 如果server.json未下载成功则不覆写本地server.json if (data != null && data.Length != 0) { Logger.InfoDebugLine($"{nameof(RpcRoot.OSSService.AliyunOSSService.GetAliyunServerJson)} ok"); var serverJson = Encoding.UTF8.GetString(data); if (!string.IsNullOrEmpty(serverJson)) { HomePath.WriteServerJsonFile(serverJson); } RpcRoot.OfficialServer.AppSettingService.GetJsonFileVersionAsync(ClientAppType.AppType, HomePath.ExportServerJsonFileName, serverState => { SetServerJsonVersion(serverState.JsonFileVersion); AppVersionChangedEvent.PublishIfNewVersion(serverState.MinerClientVersion); if (serverState.Time == 0) { NTMinerConsole.UserWarn("网络不通或服务器暂时不可用,请检查矿机网络"); } else if (Math.Abs((long)Timestamp.GetTimestamp() - (long)serverState.Time) >= Timestamp.DesyncSeconds) { NTMinerConsole.UserWarn($"本机和服务器时间不同步,请调整,本地:{DateTime.Now.ToString()},服务器:{Timestamp.FromTimestamp(serverState.Time).ToString()}。此问题不影响挖矿。"); } }); } else { if (!File.Exists(HomePath.ServerJsonFileFullName)) { VirtualRoot.ThisLocalError(nameof(NTMinerContext), "配置文件下载失败,这是第一次运行开源矿工,配置文件至少需要成功下载一次,请检查网络是否可用", OutEnum.Warn); } else { VirtualRoot.ThisLocalWarn(nameof(NTMinerContext), "配置文件下载失败,使用最近一次成功下载的配置文件"); } } DoInit(callback); }); } } VirtualRoot.ThisLocalInfo(nameof(NTMinerContext), $"启动{VirtualRoot.AppName}"); }); }
public void ShowInfo(string message, string header = "信息", int autoHideSeconds = 4, bool toConsole = false) { NTMinerConsole.UserInfo(message); }