App.xaml.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. using NTMiner.Core;
  2. using NTMiner.Notifications;
  3. using NTMiner.RemoteDesktop;
  4. using NTMiner.View;
  5. using NTMiner.Views;
  6. using NTMiner.Views.Ucs;
  7. using NTMiner.Vms;
  8. using System;
  9. using System.Diagnostics;
  10. using System.Threading;
  11. using System.Threading.Tasks;
  12. using System.Windows;
  13. using System.Windows.Interop;
  14. using System.Windows.Media;
  15. namespace NTMiner {
  16. public partial class App : Application, IDisposable {
  17. public App() {
  18. VirtualRoot.SetOut(NotiCenterWindowViewModel.Instance);
  19. Logger.SetDir(SpecialPath.LogsDirFullName);
  20. Write.UIThreadId = Dispatcher.Thread.ManagedThreadId;
  21. AppUtil.Init(this);
  22. InitializeComponent();
  23. }
  24. private readonly IAppViewFactory _appViewFactory = new AppViewFactory();
  25. private bool createdNew;
  26. private Mutex appMutex;
  27. private static readonly string s_appPipName = "ntminerclient";
  28. protected override void OnExit(ExitEventArgs e) {
  29. AppContext.NotifyIcon?.Dispose();
  30. NTMinerRoot.Instance.Exit();
  31. HttpServer.Stop();
  32. base.OnExit(e);
  33. NTMinerConsole.Free();
  34. }
  35. protected override void OnStartup(StartupEventArgs e) {
  36. RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
  37. // 通过群控升级挖矿端的时候升级器可能不存在所以需要下载,下载的时候需要用到下载器所以下载器需要提前注册
  38. VirtualRoot.AddCmdPath<ShowFileDownloaderCommand>(action: message => {
  39. UIThread.Execute(() => {
  40. FileDownloader.ShowWindow(message.DownloadFileUrl, message.FileTitle, message.DownloadComplete);
  41. });
  42. });
  43. VirtualRoot.AddCmdPath<UpgradeCommand>(action: message => {
  44. AppStatic.Upgrade(message.FileName, message.Callback);
  45. });
  46. if (!string.IsNullOrEmpty(CommandLineArgs.Upgrade)) {
  47. VirtualRoot.Execute(new UpgradeCommand(CommandLineArgs.Upgrade, () => {
  48. UIThread.Execute(() => { Environment.Exit(0); });
  49. }));
  50. }
  51. else {
  52. try {
  53. appMutex = new Mutex(true, s_appPipName, out createdNew);
  54. }
  55. catch (Exception) {
  56. createdNew = false;
  57. }
  58. if (createdNew) {
  59. Logger.InfoDebugLine($"==================NTMiner.exe {MainAssemblyInfo.CurrentVersion.ToString()}==================");
  60. NotiCenterWindowViewModel.IsHotKeyEnabled = true;
  61. SplashWindow splashWindow = null;
  62. // 在另一个UI线程运行欢迎界面以确保欢迎界面的响应不被耗时的主界面初始化过程阻塞
  63. // 注意:必须确保SplashWindow没有用到任何其它界面用到的依赖对象
  64. SplashWindow.ShowWindowAsync(window => {
  65. splashWindow = window;
  66. });
  67. //ConsoleWindow.Instance.Show();
  68. NotiCenterWindow.ShowWindow();
  69. if (!NTMiner.Windows.WMI.IsWmiEnabled) {
  70. DialogWindow.ShowSoftDialog(new DialogWindowViewModel(
  71. message: "开源矿工无法运行所需的组件,因为本机未开启WMI服务,开源矿工需要使用WMI服务检测windows的内存、显卡等信息,请先手动开启WMI。",
  72. title: "提醒",
  73. icon: "Icon_Error"));
  74. Shutdown();
  75. Environment.Exit(0);
  76. }
  77. if (!NTMiner.Windows.Role.IsAdministrator) {
  78. NotiCenterWindowViewModel.Instance.Manager
  79. .CreateMessage()
  80. .Warning("请以管理员身份运行。")
  81. .WithButton("点击以管理员身份运行", button => {
  82. WpfUtil.RunAsAdministrator();
  83. })
  84. .Dismiss().WithButton("忽略", button => {
  85. }).Queue();
  86. }
  87. NTMinerRoot.Instance.Init(() => {
  88. _appViewFactory.Link();
  89. if (VirtualRoot.IsLTWin10) {
  90. VirtualRoot.ThisLocalWarn(nameof(App), AppStatic.LowWinMessage, toConsole: true);
  91. }
  92. if (NTMinerRoot.Instance.GpuSet.Count == 0) {
  93. VirtualRoot.ThisLocalError(nameof(App), "没有矿卡或矿卡未驱动。", toConsole: true);
  94. }
  95. if (NTMinerRoot.Instance.ServerContext.CoinSet.Count == 0) {
  96. VirtualRoot.ThisLocalError(nameof(App), "访问阿里云失败,请尝试更换本机dns解决此问题。", toConsole: true);
  97. }
  98. UIThread.Execute(() => {
  99. if (NTMinerRoot.Instance.MinerProfile.IsNoUi && NTMinerRoot.Instance.MinerProfile.IsAutoStart) {
  100. ConsoleWindow.Instance.Hide();
  101. VirtualRoot.Out.ShowSuccess("已切换为无界面模式运行,可在选项页调整设置", "开源矿工");
  102. }
  103. else {
  104. // 预热视图模型
  105. AppContext.Instance.VmsCtor();
  106. _appViewFactory.ShowMainWindow(isToggle: false);
  107. }
  108. StartStopMineButtonViewModel.Instance.AutoStart();
  109. AppContext.NotifyIcon = ExtendedNotifyIcon.Create("开源矿工", isMinerStudio: false);
  110. splashWindow?.Dispatcher.Invoke((Action)delegate () {
  111. splashWindow?.Close();
  112. });
  113. });
  114. Task.Factory.StartNew(() => {
  115. if (NTMinerRoot.Instance.MinerProfile.IsAutoDisableWindowsFirewall) {
  116. Firewall.DisableFirewall();
  117. }
  118. if (!Firewall.IsMinerClientRuleExists()) {
  119. Firewall.AddMinerClientRule();
  120. }
  121. try {
  122. HttpServer.Start($"http://localhost:{NTKeyword.MinerClientPort.ToString()}");
  123. Daemon.DaemonUtil.RunNTMinerDaemon();
  124. }
  125. catch (Exception ex) {
  126. Logger.ErrorDebugLine(ex);
  127. }
  128. NTMinerRoot.Instance.CpuPackage.Start();
  129. });
  130. });
  131. Link();
  132. }
  133. else {
  134. try {
  135. _appViewFactory.ShowMainWindow(this, MinerServer.NTMinerAppType.MinerClient);
  136. }
  137. catch (Exception) {
  138. DialogWindow.ShowSoftDialog(new DialogWindowViewModel(
  139. message: "另一个NTMiner正在运行,请手动结束正在运行的NTMiner进程后再次尝试。",
  140. title: "提醒",
  141. icon: "Icon_Error"));
  142. Process currentProcess = Process.GetCurrentProcess();
  143. NTMiner.Windows.TaskKill.KillOtherProcess(currentProcess);
  144. }
  145. }
  146. }
  147. base.OnStartup(e);
  148. }
  149. private void ShowMainWindow(bool isToggle) {
  150. UIThread.Execute(() => {
  151. _appViewFactory.ShowMainWindow(isToggle);
  152. // 使状态栏显示显示最新状态
  153. if (NTMinerRoot.Instance.IsMining) {
  154. var mainCoin = NTMinerRoot.Instance.LockedMineContext.MainCoin;
  155. if (mainCoin == null) {
  156. return;
  157. }
  158. var coinShare = NTMinerRoot.Instance.CoinShareSet.GetOrCreate(mainCoin.GetId());
  159. VirtualRoot.RaiseEvent(new ShareChangedEvent(Guid.Empty, coinShare));
  160. if ((NTMinerRoot.Instance.LockedMineContext is IDualMineContext dualMineContext) && dualMineContext.DualCoin != null) {
  161. coinShare = NTMinerRoot.Instance.CoinShareSet.GetOrCreate(dualMineContext.DualCoin.GetId());
  162. VirtualRoot.RaiseEvent(new ShareChangedEvent(Guid.Empty, coinShare));
  163. }
  164. AppContext.Instance.GpuSpeedVms.Refresh();
  165. }
  166. });
  167. }
  168. private void Link() {
  169. VirtualRoot.AddEventPath<StartingMineFailedEvent>("开始挖矿失败", LogEnum.DevConsole,
  170. action: message => {
  171. AppContext.Instance.MinerProfileVm.IsMining = false;
  172. VirtualRoot.Out.ShowError(message.Message);
  173. });
  174. #region 处理显示主界面命令
  175. VirtualRoot.AddCmdPath<ShowMainWindowCommand>(action: message => {
  176. ShowMainWindow(message.IsToggle);
  177. });
  178. #endregion
  179. VirtualRoot.AddCmdPath<CloseNTMinerCommand>(action: message => {
  180. // 不能推迟这个日志记录的时机,因为推迟会有windows异常日志
  181. VirtualRoot.ThisLocalWarn(nameof(NTMinerRoot), $"退出{VirtualRoot.AppName}。原因:{message.Reason}");
  182. UIThread.Execute(() => {
  183. try {
  184. Shutdown();
  185. }
  186. catch (Exception e) {
  187. Logger.ErrorDebugLine(e);
  188. Environment.Exit(0);
  189. }
  190. });
  191. });
  192. #region 周期确保守护进程在运行
  193. VirtualRoot.AddEventPath<Per1MinuteEvent>("周期确保守护进程在运行", LogEnum.DevConsole,
  194. action: message => {
  195. Daemon.DaemonUtil.RunNTMinerDaemon();
  196. });
  197. #endregion
  198. #region 开始和停止挖矿后
  199. VirtualRoot.AddEventPath<MineStartedEvent>("启动1080ti小药丸、启动DevConsole? 更新挖矿按钮状态", LogEnum.DevConsole,
  200. action: message => {
  201. AppContext.Instance.MinerProfileVm.IsMining = true;
  202. StartStopMineButtonViewModel.Instance.BtnStopText = "正在挖矿";
  203. // 启动DevConsole
  204. if (NTMinerRoot.IsUseDevConsole) {
  205. var mineContext = message.MineContext;
  206. string poolIp = mineContext.MainCoinPool.GetIp();
  207. string consoleTitle = mineContext.MainCoinPool.Server;
  208. Daemon.DaemonUtil.RunDevConsoleAsync(poolIp, consoleTitle);
  209. }
  210. OhGodAnETHlargementPill.OhGodAnETHlargementPillUtil.Start();
  211. });
  212. VirtualRoot.AddEventPath<MineStopedEvent>("停止挖矿后停止1080ti小药丸 挖矿停止后更新界面挖矿状态", LogEnum.DevConsole,
  213. action: message => {
  214. AppContext.Instance.MinerProfileVm.IsMining = false;
  215. StartStopMineButtonViewModel.Instance.BtnStopText = "尚未开始";
  216. OhGodAnETHlargementPill.OhGodAnETHlargementPillUtil.Stop();
  217. });
  218. #endregion
  219. #region 处理禁用win10系统更新
  220. VirtualRoot.AddCmdPath<BlockWAUCommand>(action: message => {
  221. NTMiner.Windows.WindowsUtil.BlockWAU();
  222. });
  223. #endregion
  224. #region 优化windows
  225. VirtualRoot.AddCmdPath<Win10OptimizeCommand>(action: message => {
  226. NTMiner.Windows.WindowsUtil.Win10Optimize();
  227. });
  228. #endregion
  229. #region 处理开启A卡计算模式
  230. VirtualRoot.AddCmdPath<SwitchRadeonGpuCommand>(action: message => {
  231. if (NTMinerRoot.Instance.GpuSet.GpuType == GpuType.AMD) {
  232. SwitchRadeonGpuMode(message.On);
  233. }
  234. });
  235. #endregion
  236. #region 处理A卡驱动签名
  237. VirtualRoot.AddCmdPath<AtikmdagPatcherCommand>(action: message => {
  238. if (NTMinerRoot.Instance.GpuSet.GpuType == GpuType.AMD) {
  239. AtikmdagPatcher.AtikmdagPatcherUtil.Run();
  240. }
  241. });
  242. #endregion
  243. #region 启用或禁用windows远程桌面
  244. VirtualRoot.AddCmdPath<EnableWindowsRemoteDesktopCommand>(action: message => {
  245. if (NTMinerRegistry.GetIsRemoteDesktopEnabled()) {
  246. return;
  247. }
  248. string msg = "确定启用Windows远程桌面吗?";
  249. DialogWindow.ShowSoftDialog(new DialogWindowViewModel(
  250. message: msg,
  251. title: "确认",
  252. onYes: () => {
  253. Rdp.SetRdpEnabled(true);
  254. Firewall.AddRdpRule();
  255. }));
  256. });
  257. #endregion
  258. #region 启用或禁用windows开机自动登录
  259. VirtualRoot.AddCmdPath<EnableOrDisableWindowsAutoLoginCommand>(action: message => {
  260. if (NTMiner.Windows.OS.Instance.IsAutoAdminLogon) {
  261. return;
  262. }
  263. NTMiner.Windows.Cmd.RunClose("control", "userpasswords2");
  264. });
  265. #endregion
  266. }
  267. private static void SwitchRadeonGpuMode(bool on) {
  268. SwitchRadeonGpu.SwitchRadeonGpu.Run(on, (isSuccess, e) => {
  269. if (isSuccess) {
  270. if (on) {
  271. VirtualRoot.ThisLocalInfo(nameof(App), "开启A卡计算模式成功", OutEnum.Success);
  272. }
  273. else {
  274. VirtualRoot.ThisLocalInfo(nameof(App), "关闭A卡计算模式成功", OutEnum.Success);
  275. }
  276. }
  277. else if (e != null) {
  278. VirtualRoot.Out.ShowError(e.Message, delaySeconds: 4);
  279. }
  280. else {
  281. if (on) {
  282. VirtualRoot.ThisLocalError(nameof(App), "开启A卡计算模式失败", OutEnum.Warn);
  283. }
  284. else {
  285. VirtualRoot.ThisLocalError(nameof(App), "关闭A卡计算模式失败", OutEnum.Warn);
  286. }
  287. }
  288. });
  289. }
  290. public void Dispose() {
  291. Dispose(true);
  292. GC.SuppressFinalize(this);
  293. }
  294. private void Dispose(bool disposing) {
  295. if (disposing) {
  296. if (appMutex != null) {
  297. appMutex.Dispose();
  298. }
  299. }
  300. }
  301. }
  302. }