SystemControl.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. using DBModel;
  2. using DBNames;
  3. using log4net;
  4. using SCADA.CommonLib;
  5. using SCADA.CommonLib.Helper;
  6. using SCADA.CommonLib.License;
  7. using SCADA_DAQ.Plugin.Core;
  8. using SCADA_DAQ.Plugin.Core.License;
  9. using SCADA_DAQ.Plugin.CoreUI;
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Diagnostics;
  13. using System.IO;
  14. using System.Linq;
  15. using System.Reflection;
  16. using System.Threading;
  17. using System.Threading.Tasks;
  18. using System.Windows;
  19. namespace SCADA_DAQ
  20. {
  21. internal class SystemControl
  22. {
  23. /// <summary>
  24. ///
  25. /// </summary>
  26. bool isShutDown = false;
  27. ILog Log { get; set; } = null;
  28. private EventWaitHandle evh;
  29. public App App { get; private set; }
  30. private static SystemControl systemControl;
  31. private static readonly object syncObj = new object();
  32. private readonly List<AdvanceTimer> Timers = new List<AdvanceTimer>();
  33. private readonly Task initTask;
  34. private readonly Task initServer;
  35. public string UidVersion { get; }
  36. private string SoftWareId { get; set; }
  37. private SystemControl(App app)
  38. {
  39. App = app;
  40. PowerOnTime = DateTime.Now;
  41. SoftWareId = MD5Helper.GetFileMD5(GetType().Assembly.Location);
  42. UidVersion = $"{ApplicationHelper.GetAppVersion()}.{Convert.ToUInt16(SoftWareId.Substring(0, 3), 16):D4}";
  43. app.RuntimeInfo.UidVersion = UidVersion;
  44. initTask = Task.Factory.StartNew(() =>
  45. {
  46. bool createdNew = true;
  47. if (app.SystemConfig.SingleModel == true)
  48. {
  49. evh = new EventWaitHandle(false, EventResetMode.AutoReset, App.RuntimeInfo.ProductId, out createdNew);
  50. var currentProcess = Process.GetCurrentProcess();
  51. var ps = Process.GetProcessesByName(
  52. Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().ManifestModule.Name))
  53. .Where(t => t.Id != currentProcess.Id);
  54. if (createdNew) //信号锁创建成功,且是单例模式
  55. {
  56. foreach (Process p in ps)
  57. {
  58. p.Kill();
  59. }
  60. }
  61. else
  62. {
  63. if (ps.Count() == 1 && ps.First().MainWindowHandle != IntPtr.Zero)
  64. {
  65. evh?.Set();
  66. app.Dispatcher.Invoke(new Action(() =>
  67. {
  68. isShutDown = true;
  69. App.Shutdown(1);
  70. }));
  71. return;
  72. }
  73. else
  74. {
  75. foreach (Process p in ps) //单例模式下如果主界面没有出现,或者有多个进程,直接全部kill掉
  76. {
  77. p.Kill();
  78. }
  79. }
  80. }
  81. }
  82. Console.WriteLine($"开始获取电脑ID {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
  83. LicenseManage.GenerateID(App.RuntimeInfo.ProductId, out var str);
  84. Console.WriteLine($"检查释放系统组件 {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}");
  85. ReleaseRunTime();
  86. try
  87. {
  88. var dtClass = DataTableHelper.DtToList<App_Classes>(Env.DAL.App_Classes.GetData($"{T_Col_Name.App_Classes.ClassType_Int}=2"));
  89. if (dtClass != null)
  90. {
  91. Env.Schedual.Classes.Clear();
  92. foreach (var appClassese in dtClass)
  93. {
  94. var startTime = TimeSpan.Parse(appClassese.StartTime_Str);
  95. var endTime = TimeSpan.Parse(appClassese.EndTime_Str);
  96. Env.Schedual.Classes.Add(new WorkShift(startTime,
  97. endTime, appClassese.ClassesName_Str));
  98. }
  99. }
  100. }
  101. catch (Exception)
  102. {
  103. Env.Schedual.Classes.Add(new WorkShift(new TimeSpan(7, 30, 0), new TimeSpan(19, 30, 0), "白班"));
  104. Env.Schedual.Classes.Add(new WorkShift(new TimeSpan(19, 30, 0), new TimeSpan(7, 30, 0), "夜班"));
  105. }
  106. CreateBackGroundTask(ReportOnLine, 10 * 1000 * 60, 10 * 1000, true, "ReportAppInfo");
  107. var systemStatics = Plugin.CoreUI.SystemApp.SystemStatictics.Create();
  108. systemStatics.AppRuntime = App;
  109. systemStatics.Start();
  110. });
  111. initServer = Task.Factory.StartNew(() =>
  112. {
  113. });
  114. }
  115. private DateTime PowerOnTime { get; set; }
  116. public static SystemControl Create(App app)
  117. {
  118. lock (syncObj)
  119. {
  120. if (systemControl == null)
  121. {
  122. systemControl = new SystemControl(app);
  123. }
  124. }
  125. return systemControl;
  126. }
  127. public static SystemControl GetInstance()
  128. {
  129. return systemControl;
  130. }
  131. public void SystemInit()
  132. {
  133. App.DispatcherUnhandledException += Application_DispatcherUnhandledException;
  134. AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
  135. TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
  136. Task.Factory.StartNew(() =>
  137. {
  138. Task.WaitAll(initTask);
  139. if (isShutDown) return;
  140. var st = new Stopwatch();
  141. st.Start();
  142. EicpCoreManage.AppRuntime = App;
  143. try
  144. {
  145. App.RuntimeInfo.StartTime = DateTime.Now;
  146. Log = SCADA.CommonLib.LoggerHelper.Logger.CreateLogger(typeof(App));
  147. Dictionary<SCADA.CommonLib.LoggerHelper.LogLevel, log4net.Core.Level> logLevel =
  148. new Dictionary<SCADA.CommonLib.LoggerHelper.LogLevel, log4net.Core.Level>()
  149. {
  150. { SCADA.CommonLib.LoggerHelper.LogLevel.All,log4net.Core.Level.All},
  151. { SCADA.CommonLib.LoggerHelper.LogLevel.Debug,log4net.Core.Level.Debug},
  152. { SCADA.CommonLib.LoggerHelper.LogLevel.Info,log4net.Core.Level.Info},
  153. { SCADA.CommonLib.LoggerHelper.LogLevel.Warn,log4net.Core.Level.Warn},
  154. { SCADA.CommonLib.LoggerHelper.LogLevel.Error,log4net.Core.Level.Error},
  155. { SCADA.CommonLib.LoggerHelper.LogLevel.Fatal,log4net.Core.Level.Fatal},
  156. { SCADA.CommonLib.LoggerHelper.LogLevel.None,log4net.Core.Level.Off},
  157. };
  158. LogManager.GetRepository().Threshold = logLevel[App.SystemConfig.LogLevel];
  159. Log.Info($"App {App.RuntimeInfo.ProductId} ({UidVersion}) [{App.SystemConfig.ComputerTag}] is starting ……");
  160. Task.WaitAll(initServer);
  161. Console.WriteLine($"系统初始化完成 {DateTime.Now:yyyy-MM-dd HH:mm:ss,fff}");
  162. Func<bool> action = null;
  163. LoadLicense();
  164. App.RuntimeInfo.ComputerId = App.RuntimeInfo.LicenseInfo.Computer.ComputerId;
  165. var host = ServiceHost.Instance;
  166. App.ServiceHost = host;
  167. host.Start(App);
  168. App.Dispatcher.Invoke(new Action(() =>
  169. {
  170. if (App.MainWindow is MainWindow window)
  171. {
  172. action = window.GetLicense;
  173. }
  174. }));
  175. if (!LicenseManage.CheckID(App as IApp, out var str, action))
  176. {
  177. App.Dispatcher.Invoke(new Action(() =>
  178. {
  179. isShutDown = true;
  180. App.Shutdown(100);
  181. }));
  182. return;
  183. }
  184. else
  185. {
  186. App.RuntimeInfo.LicenseInfo = LicenseManage.GetLicenseInfo(App.RuntimeInfo.ProductId);
  187. }
  188. App.Dispatcher.Invoke(new Action(() =>
  189. {
  190. if (App.MainWindow is MainWindow window)
  191. {
  192. window.LicenseInfo = App.RuntimeInfo.LicenseInfo;
  193. Log.Debug($"系统初始化完成,即将开启");
  194. Env.SetLanguage();
  195. window.SystemInited();
  196. Env.SetTheme();
  197. Env.SetFont();
  198. }
  199. }));
  200. }
  201. catch (Exception ex)
  202. {
  203. FalatReport(ex);
  204. Log.Error(ex);
  205. }
  206. new Thread(() =>
  207. {
  208. while (!isShutDown && evh != null)
  209. {
  210. if (evh.WaitOne(-1))
  211. {
  212. if (isShutDown)
  213. {
  214. return;
  215. }
  216. App.Dispatcher.Invoke(new Action(() =>
  217. {
  218. App.MainWindow.Topmost = true;
  219. App.MainWindow.WindowState = WindowState.Maximized;
  220. App.MainWindow.Topmost = false;
  221. }));
  222. }
  223. }
  224. }).Start();
  225. });
  226. }
  227. /// <summary>
  228. /// 重新加载授权文件
  229. /// </summary>
  230. internal void LoadLicense()
  231. {
  232. App.RuntimeInfo.LicenseInfo = LicenseManage.GetLicenseInfo(App.RuntimeInfo.ProductId);
  233. if (isShutDown || App.RuntimeInfo.LicenseInfo == null) return;
  234. if (!App.Dispatcher.HasShutdownStarted)
  235. {
  236. App.Dispatcher.Invoke(new Action(() =>
  237. {
  238. if (App.MainWindow is MainWindow window)
  239. {
  240. window.MainWindowViewModel.CopyRightInfo = $"{App.SystemConfig.AuthorInfo}({App.RuntimeInfo.LicenseInfo.LicenseType})";
  241. }
  242. }));
  243. ReportAppInfo(true);
  244. }
  245. }
  246. private DateTime lastReportSuccessTime = DateTime.MinValue;
  247. private void ReportOnLine()
  248. {
  249. if ((DateTime.Now - lastReportSuccessTime).TotalSeconds > 590)
  250. {
  251. ReportAppInfo(true);
  252. }
  253. }
  254. private void ReportAppInfo(bool isOnline = true)
  255. {
  256. var license = App.RuntimeInfo.LicenseInfo;
  257. if (license != null && (license.LicenseType == LicenseType.TempLicense || license.LicenseType == LicenseType.Permanentlicense))
  258. {
  259. var reportInfo = new
  260. {
  261. SessionID = App.RuntimeInfo.SessionId,
  262. AppName = license?.AppName,
  263. Version = UidVersion,
  264. CustomerTag = App.SystemConfig.ComputerTag,
  265. ComputerId = license?.Computer.ComputerId,
  266. LicenseId = license?.LicenseId,
  267. LicenseType = license?.LicenseType.ToString(),
  268. ActiveTime = license?.ActiveTime,
  269. ExpireDate = license?.ActiveTime.AddDays(license.ExpireDays),
  270. TotalOutputPcs = Env.TotalOutputPcs.Value,
  271. TotalOutputQty = Env.TotalOutputQty.Value,
  272. IsOnline = isOnline
  273. };
  274. if (EicpCoreManage.ReportAppInfo(reportInfo, out var appName))
  275. {
  276. lastReportSuccessTime = DateTime.Now;
  277. App.SystemConfig.ComputerTag = appName;
  278. }
  279. }
  280. }
  281. private void FalatReport(Exception exception)
  282. {
  283. if (isShutDown) return;
  284. var license = App.RuntimeInfo.LicenseInfo;
  285. if (license != null && (license.LicenseType == LicenseType.TempLicense || license.LicenseType == LicenseType.Permanentlicense))
  286. {
  287. try
  288. {
  289. EicpCoreManage.FalatReport(new
  290. {
  291. SessionID = App.RuntimeInfo.SessionId,
  292. AppName = license?.AppName,
  293. Version = UidVersion,
  294. ComputerId = license?.Computer?.ComputerId,
  295. SoftwareID = SoftWareId,
  296. Customer = System.Windows.Forms.Application.CompanyName,
  297. Message = exception.Message,
  298. PowerOnTime = PowerOnTime,
  299. RunTime = DateTime.Now - PowerOnTime,
  300. Exception = exception?.ToString()
  301. });
  302. }
  303. catch (Exception ex)
  304. {
  305. Log?.Error(ex);
  306. }
  307. }
  308. }
  309. public bool RestartHost()
  310. {
  311. return App.ServiceHost.Restart();
  312. }
  313. private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
  314. {
  315. Log?.Error(e.Exception);
  316. e.Handled = true;
  317. if (!isShutDown)
  318. {
  319. FalatReport(e.Exception);
  320. }
  321. }
  322. private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
  323. {
  324. FalatReport(e.ExceptionObject as Exception);
  325. Log?.Fatal(e.ExceptionObject);
  326. LogManager.Flush(10);
  327. ExitHandler(e.ExceptionObject.ToString());
  328. App?.Dispatcher.BeginInvoke(new Action(() =>
  329. {
  330. MessageBox.Show(e.ExceptionObject.ToString());
  331. }));
  332. }
  333. /// <summary>
  334. /// 释放运行时压缩包
  335. /// </summary>
  336. private void ReleaseRunTime()
  337. {
  338. var runTimeLibDic = new Dictionary<string, string>()
  339. {
  340. {"Content.zip","Content" },
  341. {"EicpWeb.zip","Content" },
  342. {"EicpCustomer.zip","Content" },
  343. {"HCNETSDKLib.zip",null },
  344. {"RunTime.zip",null },
  345. {"SyntecLib_v4.zip",null},
  346. {"Fwlib.zip",AppDomain.CurrentDomain.BaseDirectory },
  347. {"DeviceCfg.zip",null},
  348. {"x86_x64.zip",null },
  349. };
  350. foreach (var item in runTimeLibDic)
  351. {
  352. try
  353. {
  354. if (System.IO.File.Exists(item.Key))
  355. {
  356. ZipHelper.UnZip(item.Key, item.Value);
  357. FileHelper.DeleteFile(item.Key);
  358. }
  359. }
  360. catch (Exception ex)
  361. {
  362. Log.Error(ex);
  363. }
  364. }
  365. }
  366. private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  367. {
  368. Log?.Fatal(e.Exception);
  369. FalatReport(e.Exception);
  370. ExitHandler(e.Exception.Message);
  371. }
  372. private void ExitHandler(string exitMsg)
  373. {
  374. Plugin.CoreUI.SystemApp.SystemStatictics.Create().AppExit(exitMsg);
  375. ReportAppInfo(false);
  376. }
  377. public void ApplicationExit(int exitCode)
  378. {
  379. isShutDown = true;
  380. evh?.Set();
  381. evh?.Dispose();
  382. }
  383. public void ApplicationDispose(int exitCode)
  384. {
  385. isShutDown = true;
  386. App.ServiceHost?.Stop();
  387. foreach (var item in Timers)
  388. {
  389. item.Dispose();
  390. }
  391. var exitReason = "";
  392. if (ExitCode.ContainsKey(exitCode))
  393. {
  394. exitReason = ExitCode[exitCode];
  395. }
  396. ExitHandler(exitReason);
  397. if (Log != null)
  398. {
  399. Log.Info($"{App.RuntimeInfo.ProductId}({UidVersion}) is shutdown by {exitReason}");
  400. SCADA.CommonLib.LoggerHelper.Logger.Dispose();
  401. }
  402. }
  403. public void ApplicationSessionEnding(object sender, SessionEndingCancelEventArgs e)
  404. {
  405. Log.Error($"计算机已注销或关闭,原因:{e.ReasonSessionEnding}");
  406. }
  407. /// <summary>
  408. /// 创建一个后台任务
  409. /// </summary>
  410. /// <param name="task"></param>
  411. /// <param name="cycleTime">重复执行间隔 毫秒</param>
  412. /// <param name="delayTime">延迟时间</param>
  413. /// <param name="backgroundContinue">当转到后台时继续执行</param>
  414. /// <param name="taskName"></param>
  415. public void CreateBackGroundTask(ThreadStart task, int cycleTime, int delayTime = 0, bool backgroundContinue = false, string taskName = null)
  416. {
  417. Timers.Add(new AdvanceTimer(task, taskName, cycleTime, delayTime)
  418. {
  419. IsBackground = backgroundContinue,
  420. IsActived = true,
  421. TimerName = taskName
  422. });
  423. }
  424. private readonly Dictionary<int, string> ExitCode = new Dictionary<int, string>()
  425. {
  426. {0,"User Exit"},
  427. {100,"invalid license"},
  428. };
  429. }
  430. }