LogicHandler.cs 18 KB

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