public static void CreateProcess(IMineContext mineContext) { Global.DebugLine("解压内核包"); // 解压内核包 mineContext.Kernel.ExtractPackage(); string kernelExeFileFullName; string arguments; Global.DebugLine("组装命令"); // 组装命令 BuildCmdLine(mineContext, out kernelExeFileFullName, out arguments); bool isLogFile = arguments.Contains("{logfile}"); // 这是不应该发生的,如果发生很可能是填写命令的时候拼写错误了 if (!File.Exists(kernelExeFileFullName)) { Global.WriteLine(kernelExeFileFullName + "文件不存在,请检查是否有拼写错误", ConsoleColor.Red); } if (isLogFile) { Global.DebugLine("创建日志文件型进程"); // 如果内核支持日志文件 // 推迟打印cmdLine,因为{logfile}变量尚未求值 CreateLogfileProcess(mineContext, kernelExeFileFullName, arguments); } else { Global.DebugLine("创建管道型进程"); // 如果内核不支持日志文件 string cmdLine = $"\"{kernelExeFileFullName}\" {arguments}"; Global.DebugLine(cmdLine, ConsoleColor.Yellow); CreatePipProcess(mineContext, cmdLine); } }
private static void ReadPrintLoopLogFile(IMineContext mineContext, string logFile) { bool isLogFileCreated = true; int n = 0; while (!File.Exists(logFile)) { if (n >= 10) { // 10秒钟都没有建立日志文件,不可能 isLogFileCreated = false; break; } Thread.Sleep(1000); if (mineContext != Current.CurrentMineContext) { isLogFileCreated = false; break; } n++; } if (isLogFileCreated) { using (FileStream stream = File.Open(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (StreamReader sreader = new StreamReader(stream, Encoding.Default)) { while (mineContext == Current.CurrentMineContext) { string outline = sreader.ReadLine(); if (string.IsNullOrEmpty(outline)) { Thread.Sleep(1000); } else { string input = outline; Guid kernelOutputId = mineContext.Kernel.KernelOutputId; Current.KernelOutputFilterSet.Filter(kernelOutputId, ref input); ConsoleColor color = ConsoleColor.White; Current.KernelOutputTranslaterSet.Translate(kernelOutputId, ref input, ref color, isPre: true); // 使用Claymore挖其非ETH币种时它也打印ETH,所以这里需要纠正它 if ("Claymore".Equals(mineContext.Kernel.Code, StringComparison.OrdinalIgnoreCase)) { if (mineContext.MainCoin.Code != "ETH" && input.Contains("ETH")) { input = input.Replace("ETH", mineContext.MainCoin.Code); } } Current.KernelOutputSet.Pick(kernelOutputId, ref input, mineContext); Current.KernelOutputTranslaterSet.Translate(kernelOutputId, ref input, ref color); if (!string.IsNullOrEmpty(input)) { Global.WriteLine(input, color); } } } } Global.Logger.WarnWriteLine("日志输出结束"); } }
private static void ReadPrintLoopLogFile(IMineContext mineContext, string logFile) { bool isLogFileCreated = true; int n = 0; while (!File.Exists(logFile)) { if (n >= 10) { // 10秒钟都没有建立日志文件,不可能 isLogFileCreated = false; break; } Thread.Sleep(1000); if (mineContext != Current.CurrentMineContext) { isLogFileCreated = false; break; } n++; } if (isLogFileCreated) { using (FileStream stream = File.Open(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (StreamReader sreader = new StreamReader(stream, Encoding.Default)) { while (mineContext == Current.CurrentMineContext) { string outline = sreader.ReadLine(); if (string.IsNullOrEmpty(outline)) { Thread.Sleep(1000); } else { string input = outline; Guid kernelId = mineContext.Kernel.GetId(); Current.KernelOutputFilterSet.Filter(kernelId, ref input); ConsoleColor color = ConsoleColor.White; Current.KernelOutputTranslaterSet.Translate(kernelId, ref input, ref color, isPre: true); Current.KernelSet.Pick(kernelId, ref input, mineContext); Current.KernelOutputTranslaterSet.Translate(kernelId, ref input, ref color); if (!string.IsNullOrEmpty(input)) { Global.WriteLine(input, color); } } } } Global.Logger.WarnWriteLine("日志输出结束"); } }
private static void Daemon(IMineContext mineContext, Action clear) { string processName = mineContext.Kernel.GetProcessName(); Bus.DelegateHandler <Per1MinuteEvent> daemon = null; daemon = Global.Access <Per1MinuteEvent>( Guid.Parse("a4761e90-dc3c-4483-b055-546084863640"), "周期性检查挖矿内核是否消失,如果消失尝试重启", LogEnum.None, action: message => { if (mineContext == Current.CurrentMineContext) { if (!string.IsNullOrEmpty(processName)) { Process[] processes = Process.GetProcessesByName(processName); if (processes.Length == 0) { mineContext.ProcessDisappearedCound = mineContext.ProcessDisappearedCound + 1; Global.WriteLine(processName + $"挖矿内核进程消失", ConsoleColor.Red); if (Current.MinerProfile.IsAutoRestartKernel && mineContext.ProcessDisappearedCound <= 3) { Global.WriteLine($"尝试第{mineContext.ProcessDisappearedCound}次重启,共3次", ConsoleColor.Red); Current.RestartMine(); Current.CurrentMineContext.ProcessDisappearedCound = mineContext.ProcessDisappearedCound; } else { Current.StopMine(); } Global.UnAccess(daemon); clear?.Invoke(); } } } else { Global.UnAccess(daemon); clear?.Invoke(); } }); }
// 创建管道,将输出通过管道转送到日志文件,然后读取日志文件内容打印到控制台 private static void CreatePipProcess(IMineContext mineContext, string cmdLine) { SECURITY_ATTRIBUTES saAttr = new SECURITY_ATTRIBUTES(); IntPtr hReadOut, hWriteOut; //set the bInheritHandle flag so pipe handles are inherited saAttr.bInheritHandle = true; saAttr.lpSecurityDescriptor = IntPtr.Zero; saAttr.length = Marshal.SizeOf(typeof(SECURITY_ATTRIBUTES)); saAttr.lpSecurityDescriptor = IntPtr.Zero; //get handle to current stdOut bool bret; IntPtr mypointer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(STARTUPINFO))); Marshal.StructureToPtr(saAttr, mypointer, true); bret = CreatePipe(out hReadOut, out hWriteOut, mypointer, 0); //ensure the read handle to pipe for stdout is not inherited SetHandleInformation(hReadOut, HANDLE_FLAG_INHERIT, 0); ////Create pipe for the child process's STDIN STARTUPINFO lpStartupInfo = new STARTUPINFO { cb = (uint)Marshal.SizeOf(typeof(STARTUPINFO)), dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW, wShowWindow = SW_HIDE, // SW_HIDE; //SW_SHOW hStdOutput = hWriteOut, hStdError = hWriteOut, hStdInput = IntPtr.Zero }; PROCESS_INFORMATION lpProcessInformation; if (CreateProcess( lpApplicationName: null, lpCommandLine: new StringBuilder(cmdLine), lpProcessAttributes: IntPtr.Zero, lpThreadAttributes: IntPtr.Zero, bInheritHandles: true, dwCreationFlags: NORMAL_PRIORITY_CLASS, lpEnvironment: IntPtr.Zero, lpCurrentDirectory: null, lpStartupInfo: ref lpStartupInfo, lpProcessInformation: out lpProcessInformation)) { if (bret == false) { int lasterr = Marshal.GetLastWin32Error(); } else { Bus.DelegateHandler <MineStopedEvent> closeHandle = null; bool isHWriteOutHasClosed = false; Daemon(mineContext, () => { if (!isHWriteOutHasClosed) { CloseHandle(hWriteOut); isHWriteOutHasClosed = true; } Global.UnAccess(closeHandle); }); closeHandle = Global.Access <MineStopedEvent>( Guid.Parse("91642027-fd28-4bdd-a05a-31caac6609b1"), "挖矿停止后关闭非托管的日志句柄", LogEnum.Log, action: message => { if (!isHWriteOutHasClosed) { CloseHandle(hWriteOut); isHWriteOutHasClosed = true; } Global.UnAccess(closeHandle); }); string pipLogFileFullName = Path.Combine(SpecialPath.LogsDirFullName, mineContext.PipeFileName); Task.Factory.StartNew(() => { using (FileStream fs = new FileStream(pipLogFileFullName, FileMode.OpenOrCreate, FileAccess.ReadWrite)) using (StreamReader sr = new StreamReader(fs)) { byte[] buffer = new byte[1024]; int ret; // Read会阻塞,直到读取到字符或者hWriteOut被关闭 while ((ret = Read(buffer, 0, buffer.Length, hReadOut)) > 0) { fs.Write(buffer, 0, ret); if (buffer[ret - 1] == '\r' || buffer[ret - 1] == '\n') { fs.Flush(); } } } CloseHandle(hReadOut); }); Task.Factory.StartNew(() => { ReadPrintLoopLogFile(mineContext, pipLogFileFullName); }); } } else { Global.WriteLine("内核启动失败,请重试", ConsoleColor.Red); } }
public void Start() { BootLog.Log("开始启动Wcf服务"); string baseUrl = $"http://{MinerClientHost}:{Global.ClientPort}/"; ServiceHost minerClientServiceHost = new ServiceHost(typeof(Core.Impl.MinerClientService)); minerClientServiceHost.AddServiceEndpoint(typeof(IMinerClientService), ChannelFactory.BasicHttpBinding, new Uri(new Uri(baseUrl), nameof(IMinerClientService))); _serviceHosts = new List <ServiceHost> { minerClientServiceHost }; foreach (var serviceHost in _serviceHosts) { ServiceMetadataBehavior serviceMetadata = serviceHost.Description.Behaviors.Find <ServiceMetadataBehavior>(); if (serviceMetadata == null) { serviceMetadata = new ServiceMetadataBehavior(); serviceHost.Description.Behaviors.Add(serviceMetadata); } serviceMetadata.HttpGetEnabled = false; serviceHost.Open(); } Global.DebugLine($"服务启动成功: {DateTime.Now}."); Global.DebugLine("服务列表:"); foreach (var serviceHost in _serviceHosts) { foreach (var endpoint in serviceHost.Description.Endpoints) { Global.DebugLine(endpoint.Address.Uri.ToString()); } } BootLog.Log("Wcf服务启动完成"); Server.TimeService.GetTime((remoteTime) => { if (Math.Abs((DateTime.Now - remoteTime).TotalSeconds) < Global.DesyncSeconds) { Global.DebugLine("时间同步"); } else { Global.WriteLine($"本机时间和服务器时间不同步,请调整,本地:{DateTime.Now},服务器:{remoteTime}", ConsoleColor.Red); } }); Windows.Registry.SetValue(Registry.Users, ClientId.NTMinerRegistrySubKey, "Location", ClientId.AppFileFullName); Windows.Registry.SetValue(Registry.Users, ClientId.NTMinerRegistrySubKey, "Arguments", string.Join(" ", CommandLineArgs.Args)); Windows.Registry.SetValue(Registry.Users, ClientId.NTMinerRegistrySubKey, "CurrentVersion", CurrentVersion.ToString()); Windows.Registry.SetValue(Registry.Users, ClientId.NTMinerRegistrySubKey, "CurrentVersionTag", CurrentVersionTag); Report.Init(this); int shareCount = 0; DateTime shareOn = DateTime.Now; #region 挖矿开始时将无份额内核重启份额计数置0 Global.Access <MineStartedEvent>( Guid.Parse("e69e8729-868b-4b5d-b120-2914fffddf90"), "挖矿开始时将无份额内核重启份额计数置0", LogEnum.None, action: message => { shareCount = 0; shareOn = DateTime.Now; }); #endregion #region 每10秒钟检查是否需要重启 Global.Access <Per10SecondEvent>( Guid.Parse("16b3b7b4-5e6c-46b0-97a4-90e085614b78"), "每10秒钟检查是否需要重启", LogEnum.None, action: message => { #region 重启电脑 try { if (MinerProfile.IsPeriodicRestartComputer) { if ((DateTime.Now - shareOn).TotalHours > MinerProfile.PeriodicRestartComputerHours) { Global.WriteLine($"每运行{MinerProfile.PeriodicRestartKernelHours}小时重启电脑", ConsoleColor.Red); Windows.Power.Restart(); return; // 退出 } } } catch (Exception e) { Global.Logger.Error(e.Message, e); } #endregion #region 周期重启内核 try { if (IsMining && MinerProfile.IsPeriodicRestartKernel) { if ((DateTime.Now - shareOn).TotalHours > MinerProfile.PeriodicRestartKernelHours) { Global.WriteLine($"每运行{MinerProfile.PeriodicRestartKernelHours}小时重启内核", ConsoleColor.Red); RestartMine(); return; // 退出 } } } catch (Exception e) { Global.Logger.Error(e.Message, e); } #endregion #region 收益没有增加重启内核 try { if (IsMining && MinerProfile.IsNoShareRestartKernel) { if ((DateTime.Now - shareOn).TotalMinutes > MinerProfile.NoShareRestartKernelMinutes) { if (this.CurrentMineContext.MainCoin != null) { ICoinShare mainCoinShare = this.CoinShareSet.GetOrCreate(this.CurrentMineContext.MainCoin.GetId()); int totalShare = mainCoinShare.TotalShareCount; if ((this.CurrentMineContext is IDualMineContext dualMineContext) && dualMineContext.DualCoin != null) { ICoinShare dualCoinShare = this.CoinShareSet.GetOrCreate(dualMineContext.DualCoin.GetId()); totalShare += dualCoinShare.TotalShareCount; } if (shareCount == totalShare) { Global.WriteLine($"{MinerProfile.NoShareRestartKernelMinutes}分钟收益没有增加重启内核", ConsoleColor.Red); RestartMine(); } else { shareCount = totalShare; shareOn = DateTime.Now; } }