LogicHandler.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. using WCS.Entity;
  10. namespace WCS.Core
  11. {
  12. public abstract class LogicHandler
  13. {
  14. protected bool Stoped = false;
  15. protected string Description { get; private set; }
  16. public static List<object> AllObjects = new List<object>();
  17. private static List<LogicHandler> Handlers = new List<LogicHandler>();
  18. public static Action<string, string, string> DbLog;
  19. public LogicHandler()
  20. {
  21. var attr = this.GetType().GetCustomAttributes(false).OfType<DescriptionAttribute>().FirstOrDefault();
  22. if (attr != null)
  23. Description = attr.Description;
  24. else
  25. Description = this.GetType().Name;
  26. }
  27. public abstract void Start();
  28. public virtual bool ParallelRun
  29. {
  30. get
  31. {
  32. return false;
  33. }
  34. }
  35. /// <summary>
  36. /// 数据刷新时触发
  37. /// </summary>
  38. /// <param name="milliseconds">离上次触发的间隔时间(毫秒)</param>
  39. public abstract void Update(double milliseconds);
  40. public void Stop()
  41. {
  42. Stoped = true;
  43. }
  44. public static void AddManager(LogicHandler handler)
  45. {
  46. Handlers.Add(handler);
  47. }
  48. public static void StartAll()
  49. {
  50. foreach (var h in Handlers)
  51. {
  52. h.Start();
  53. }
  54. var th = new Thread(new ThreadStart(Loop));
  55. th.IsBackground = true;
  56. th.Start();
  57. }
  58. private static DateTime last = DateTime.Now;
  59. private static DateTime last2 = DateTime.Now;
  60. private static int logicTimes;
  61. public static DateTime Frame { get; private set; }
  62. private static void Loop()
  63. {
  64. var arr = AllObjects.OfType<WCS_DEVICE>().Where(v => v.ENABLED).SelectMany(v => v.PROTOCOLS)
  65. .Where(v => v.ENABLED && v.DB.ENABLED && v.DB.PLC.ENABLED)
  66. .GroupBy(v => v.DB).Select(v => v.Key)
  67. .ToArray();
  68. while (true)
  69. {
  70. var dd = DateTime.Now;
  71. Frame = DateTime.Now;
  72. Parallel.ForEach<WCS_DATABLOCK>(arr, db =>
  73. {
  74. try
  75. {
  76. Ltc.SetChannel("刷新");
  77. db.Ex().DataRefresh();
  78. }
  79. catch (Exception ex)
  80. {
  81. Console.WriteLine("更新" + db.NAME + "数据失败:" + ex.Message);
  82. }
  83. });
  84. var dbTimes = (DateTime.Now - dd).TotalMilliseconds;
  85. // Console.WriteLine("----------"+dd2);
  86. var total = (DateTime.Now - last).TotalMilliseconds;
  87. var s = (int)(600 - total);
  88. if (s > 0)
  89. Thread.Sleep(s);
  90. total = (DateTime.Now - last).TotalMilliseconds;
  91. Console.ForegroundColor = ConsoleColor.Blue;
  92. Console.WriteLine("------刷新DB块数据耗时:" + ((int)dbTimes).ToString().PadRight(4, ' ') + ";业务逻辑耗时:" + ((int)logicTimes).ToString().PadRight(4, ' ') + ";周期总耗时" + ((int)total).ToString().PadRight(4, ' ') + "");
  93. Console.ResetColor();
  94. last = DateTime.Now;
  95. //Configs.DoCmds(cmd =>
  96. //{
  97. // try
  98. // {
  99. // if (!cmd.ENABLED)
  100. // return;
  101. // var obj = Device.Find(cmd.DEVICE_CODE).PROTOCOLS.Where(v => v.DB.PROTOCOL == cmd.PROTOCOL).FirstOrDefault();
  102. // //var obj = AllObjects.OfType<WCS_DEVICEPROTOCOL>().Where(v => v.DB.PROTOCOL == cmd.PROTOCOL && v.DEVICE.CODE == cmd.DEVICE_CODE).FirstOrDefault();
  103. // if (obj != null)
  104. // {
  105. // var proxy = obj.Data() as ProtocolProxyBase;
  106. // if (proxy.WCSVersion != cmd.WCSVERSION && cmd.WCSVERSION >= 0)
  107. // {
  108. // throw new Exception("WCS数据已变更,无法执行CMD。ID:" + cmd.ID);
  109. // }
  110. // var prop = proxy.GetType().GetProperty(cmd.PROPERTY);
  111. // if (prop.PropertyType.IsEnum)
  112. // {
  113. // var value = Enum.Parse(prop.PropertyType, cmd.VALUE);
  114. // proxy.Update(cmd.PROPERTY, value, cmd.UPDATEUSER);
  115. // }
  116. // else
  117. // {
  118. // var value = Convert.ChangeType(cmd.VALUE, prop.PropertyType);
  119. // proxy.Update(cmd.PROPERTY, value, cmd.UPDATEUSER);
  120. // }
  121. // }
  122. // }
  123. // catch (Exception ex)
  124. // {
  125. // Console.WriteLine(ex.Message);
  126. // }
  127. //});
  128. Parallel.ForEach<LogicHandler>(Handlers, m =>
  129. {
  130. var dm = DateTime.Now;
  131. try
  132. {
  133. m.Update(total);
  134. }
  135. catch (Exception ex)
  136. {
  137. //Console.WriteLine(ex.GetBaseException().Message);
  138. }
  139. var dm2 = (DateTime.Now - dm).TotalMilliseconds;
  140. //Console.WriteLine(m.GetType().Name + ":" + dm2);
  141. });
  142. //foreach (var m in Handlers)
  143. //{
  144. // var dm = DateTime.Now;
  145. // try
  146. // {
  147. // m.Update(total);
  148. // }
  149. // catch (Exception ex)
  150. // {
  151. // //Console.WriteLine(ex.GetBaseException().Message);
  152. // }
  153. // var dm2 = (DateTime.Now - dm).TotalMilliseconds;
  154. //}
  155. Configs.Publish();
  156. logicTimes = (int)(DateTime.Now - last).TotalMilliseconds;
  157. }
  158. }
  159. public static void StopAll()
  160. {
  161. foreach (var h in Handlers)
  162. {
  163. try
  164. {
  165. h.Stop();
  166. }
  167. catch { }
  168. }
  169. }
  170. }
  171. public abstract class LogicHandler<T> : LogicHandler where T : EntityEx<WCS_DEVICE>
  172. {
  173. private string logPath = "";
  174. protected List<WorkInfo<T>> Works = new List<WorkInfo<T>>();
  175. private IEnumerable<T> _Objects = null;
  176. protected IEnumerable<T> Objects
  177. {
  178. get
  179. {
  180. if (_Objects == null)
  181. {
  182. _Objects = AllObjects.OfType<WCS_DEVICE>().Where(v => SelectDevice(v)).Select(v => Activator.CreateInstance(typeof(T), v)).OfType<T>().ToArray();
  183. }
  184. return _Objects.Where(v => v.Entity.ENABLED && v.Entity.PROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED));
  185. }
  186. }
  187. private bool SelectDevice(WCS_DEVICE dev)
  188. {
  189. var typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray();
  190. var res = typenames.All(v => dev.PROTOCOLS.Any(d => d.DB.PROTOCOL == v));
  191. return res;
  192. }
  193. public LogicHandler()
  194. {
  195. logPath = @"D:\WCSLog\Log\" + this.Description + @"\";
  196. }
  197. public void AddWork(Func<T, bool> condition, Action<T> work, bool parallel = false)
  198. {
  199. var title = work.Method.Name;
  200. var attr = work.Method.GetCustomAttributes(false).OfType<DescriptionAttribute>().FirstOrDefault();
  201. if (attr != null)
  202. title = attr.Description;
  203. var arr = Objects.Where(condition).ToArray();
  204. this.Works.Add(new WorkInfo<T> { Work = work, Params = arr, Title = title, Parallel = parallel });
  205. }
  206. public void AddWork(IEnumerable<T> arr, Action<T> work, bool parallel = false)
  207. {
  208. var title = work.Method.Name;
  209. var attr = work.Method.GetCustomAttributes(false).OfType<DescriptionAttribute>().FirstOrDefault();
  210. if (attr != null)
  211. title = attr.Description;
  212. this.Works.Add(new WorkInfo<T> { Work = work, Params = arr, Title = title, Parallel = parallel });
  213. }
  214. public override void Update(double milliseconds)
  215. {
  216. if (ParallelRun)
  217. {
  218. Parallel.ForEach(Works, w =>
  219. {
  220. DoWork(w);
  221. });
  222. }
  223. else
  224. {
  225. foreach (var w in Works)
  226. {
  227. DoWork(w);
  228. }
  229. }
  230. }
  231. protected virtual void DoWork(WorkInfo<T> work)
  232. {
  233. if (work.Parallel)
  234. {
  235. Parallel.ForEach(work.Params, p =>
  236. {
  237. Do(work, p);
  238. });
  239. }
  240. else
  241. {
  242. foreach (var p in work.Params)
  243. {
  244. Do(work, p);
  245. }
  246. }
  247. }
  248. protected virtual void Do(WorkInfo<T> wi, T p)
  249. {
  250. var channel = Description + "." + wi.Title + "." + p.ToString();
  251. try
  252. {
  253. Ltc.SetChannel(channel);
  254. Ltc.Log("开始---------------------------------------");
  255. wi.Work(p);
  256. }
  257. catch (Exception ex)
  258. {
  259. Ltc.Log(ex.GetBaseException().Message);
  260. Log(wi, p, ex);
  261. }
  262. finally
  263. {
  264. Ltc.Log("结束\n");
  265. }
  266. }
  267. protected virtual void Log(WorkInfo<T> wi, T p, Exception ex)
  268. {
  269. try
  270. {
  271. var msg = Description + "--" + wi.Title + "--";
  272. if (p is IProtocol)
  273. {
  274. msg += (p as IProtocol).PROTOCOL().DEVICE.CODE;
  275. }
  276. var con = ex.GetBaseException().Message.Split("|");
  277. msg = msg + ":" + con[0];
  278. //Console.WriteLine(msg);
  279. DbLog.Invoke(msg, con[1], con[2]);
  280. }
  281. catch (Exception ex2)
  282. {
  283. }
  284. }
  285. private static object lockobj = new object();
  286. protected void Log(string msg)
  287. {
  288. lock (lockobj)
  289. {
  290. try
  291. {
  292. var str = "-----------" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss:fff") + "-----------\r\n";
  293. str += msg;
  294. if (!Directory.Exists(logPath))
  295. Directory.CreateDirectory(logPath);
  296. var file = logPath + DateTime.Now.ToString("yyyyMMdd") + ".log";
  297. var writer = File.AppendText(file);
  298. writer.WriteLine(str);
  299. writer.Flush();
  300. writer.Close();
  301. }
  302. catch (Exception ex)
  303. {
  304. }
  305. }
  306. }
  307. /// <summary>
  308. /// 此方法不会被自动调用,请在Start方法中使用AddWork将其添加至工作队列
  309. /// </summary>
  310. /// <param name="dev"></param>
  311. [Description("执行")]
  312. protected abstract void Execute(T dev);
  313. }
  314. public abstract class WorkHandler : LogicHandler
  315. {
  316. private string logPath = "";
  317. protected List<WorkInfo> Works = new List<WorkInfo>();
  318. public WorkHandler()
  319. {
  320. logPath = @"Log\" + this.Description + @"\";
  321. var arr = Assembly.GetEntryAssembly().GetTypes().Where(v => v.IsSubclassOf(typeof(Work))).Where(v =>
  322. {
  323. var attr = v.GetCustomAttribute<WorkTitleAttribute>();
  324. if (attr == null)
  325. return false;
  326. return attr.Handler == this.GetType();
  327. });
  328. var works = arr.Select(v => Activator.CreateInstance(v) as Work).Select(v =>
  329. {
  330. var attr = v.GetType().GetCustomAttribute<WorkTitleAttribute>();
  331. return new WorkInfo { Params = v.GetObjs(), Work = v.Execute, Title = attr.Title, Parallel = attr.Parallel };
  332. }).ToArray();
  333. Works.AddRange(works);
  334. }
  335. public override sealed void Start()
  336. {
  337. //throw new NotImplementedException();
  338. }
  339. public override void Update(double milliseconds)
  340. {
  341. if (ParallelRun)
  342. {
  343. Parallel.ForEach(Works, w =>
  344. {
  345. DoWork(w);
  346. });
  347. }
  348. else
  349. {
  350. foreach (var w in Works)
  351. {
  352. DoWork(w);
  353. }
  354. }
  355. }
  356. protected virtual void DoWork(WorkInfo work)
  357. {
  358. if (work.Parallel)
  359. {
  360. Parallel.ForEach(work.Params, p =>
  361. {
  362. Do(work, p);
  363. });
  364. }
  365. else
  366. {
  367. foreach (var p in work.Params)
  368. {
  369. Do(work, p);
  370. }
  371. }
  372. }
  373. protected virtual void Do(WorkInfo wi, object p)
  374. {
  375. var dt = DateTime.Now;
  376. var channel = Description + "." + wi.Title + "." + p.ToString();
  377. try
  378. {
  379. Ltc.SetChannel(channel);
  380. Ltc.Log("开始---------------------------------------");
  381. wi.Work(p);
  382. }
  383. catch (Exception ex)
  384. {
  385. Ltc.Log(ex.GetBaseException().Message);
  386. Log(wi, p, ex);
  387. Configs.UploadException?.Invoke(p.ToString(), ex.GetBaseException().Message);
  388. }
  389. finally
  390. {
  391. var dd = (DateTime.Now - dt).TotalMilliseconds;
  392. if (dd > 500)
  393. {
  394. Console.ForegroundColor = ConsoleColor.Red;
  395. Console.WriteLine(channel + "耗时" + dd);
  396. Console.ResetColor();
  397. }
  398. if (dd > 10000)
  399. Configs.UploadException?.Invoke(p.ToString(), wi.Title + "执行耗时" + Math.Floor(dd / 1000) + "秒");
  400. Ltc.Log("结束\n");
  401. }
  402. }
  403. protected virtual void Log(WorkInfo wi, object p, Exception ex)
  404. {
  405. try
  406. {
  407. var msg = Description + "--" + wi.Title + "--";
  408. if (p is IProtocol)
  409. {
  410. msg += (p as IProtocol).PROTOCOL().DEVICE.CODE;
  411. }
  412. var con = ex.GetBaseException().Message.Split("|");
  413. msg = msg + ":" + con[0];
  414. //Console.WriteLine(msg);
  415. DbLog.Invoke(msg, con[1], con[2]);
  416. }
  417. catch (Exception ex2)
  418. {
  419. }
  420. }
  421. private static object lockobj = new object();
  422. protected void Log(string msg)
  423. {
  424. lock (lockobj)
  425. {
  426. try
  427. {
  428. var str = "-----------" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss:fff") + "-----------\r\n";
  429. str += msg;
  430. if (!Directory.Exists(logPath))
  431. Directory.CreateDirectory(logPath);
  432. var file = logPath + DateTime.Now.ToString("yyyyMMdd") + ".log";
  433. var writer = File.AppendText(file);
  434. writer.WriteLine(str);
  435. writer.Flush();
  436. writer.Close();
  437. }
  438. catch (Exception ex)
  439. {
  440. }
  441. }
  442. }
  443. }
  444. public class WorkTitleAttribute : Attribute
  445. {
  446. public Type Handler { get; set; }
  447. public string Title { get; set; }
  448. public bool Parallel { get; set; }
  449. public WorkTitleAttribute(Type handler, string title, bool parallel = false)
  450. {
  451. this.Handler = handler;
  452. this.Title = title;
  453. this.Parallel = parallel;
  454. }
  455. }
  456. public abstract class Work
  457. {
  458. public abstract IEnumerable<Object> GetObjs();
  459. public abstract void Execute(object obj);
  460. }
  461. public abstract class Work<T> : Work
  462. {
  463. public override sealed void Execute(object obj)
  464. {
  465. Do((T)obj);
  466. }
  467. public override sealed IEnumerable<object> GetObjs()
  468. {
  469. return InitObjects().OfType<object>().ToArray();
  470. }
  471. protected abstract void Do(T obj);
  472. protected abstract bool SelectDevice(WCS_DEVICE dev);
  473. protected virtual IEnumerable<T> InitObjects()
  474. {
  475. var arr = Device.Where(v => v.ENABLED)
  476. .Where(v => SelectDevice(v)).ToArray();
  477. var res = arr.Select(v => (T)Activator.CreateInstance(typeof(T), v));
  478. return res;
  479. }
  480. }
  481. public abstract class DeviceWork<T> : Work<T> where T : EntityEx<WCS_DEVICE>
  482. {
  483. private string[] typenames;
  484. public DeviceWork()
  485. {
  486. typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray();
  487. }
  488. protected abstract override void Do(T obj);
  489. protected override sealed IEnumerable<T> InitObjects()
  490. {
  491. var arr = Device.Where(v => v.ENABLED && v.PROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED))
  492. .Where(v => typenames.All(d => v.PROTOCOLS.Any(e => e.DB.PROTOCOL == d)))
  493. .Where(v => SelectDevice(v)).ToArray();
  494. var res = arr.Select(v => Activator.CreateInstance(typeof(T), v) as T);
  495. return res;
  496. }
  497. }
  498. }