using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; using WCS.Entity; namespace WCS.Core { public abstract class LogicHandler { protected bool Stoped = false; protected string Description { get; private set; } public static List AllObjects = new List(); private static List Handlers = new List(); public static Action DbLog; public LogicHandler() { var attr = this.GetType().GetCustomAttributes(false).OfType().FirstOrDefault(); if (attr != null) Description = attr.Description; else Description = this.GetType().Name; } public abstract void Start(); public virtual bool ParallelRun { get { return false; } } /// /// 数据刷新时触发 /// /// 离上次触发的间隔时间(毫秒) public abstract void Update(double milliseconds); public void Stop() { Stoped = true; } public static void AddManager(LogicHandler handler) { Handlers.Add(handler); } public static void StartAll() { foreach (var h in Handlers) { h.Start(); } var th = new Thread(new ThreadStart(Loop)); th.IsBackground = true; th.Start(); } private static DateTime last = DateTime.Now; private static DateTime last2 = DateTime.Now; private static int logicTimes; public static DateTime Frame { get; private set; } private static void Loop() { var arr = AllObjects.OfType().Where(v => v.ENABLED).SelectMany(v => v.PROTOCOLS) .Where(v => v.ENABLED && v.DB.ENABLED && v.DB.PLC.ENABLED) .GroupBy(v => v.DB).Select(v => v.Key) .ToArray(); while (true) { var dd = DateTime.Now; Frame = DateTime.Now; Parallel.ForEach(arr, db => { try { Ltc.SetChannel("刷新"); db.Ex().DataRefresh(); } catch (Exception ex) { Console.WriteLine("更新" + db.NAME + "数据失败:" + ex.Message); } }); var dbTimes = (DateTime.Now - dd).TotalMilliseconds; // Console.WriteLine("----------"+dd2); var total = (DateTime.Now - last).TotalMilliseconds; var s = (int)(600 - total); if (s > 0) Thread.Sleep(s); total = (DateTime.Now - last).TotalMilliseconds; Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine("------刷新DB块数据耗时:" + ((int)dbTimes).ToString().PadRight(4, ' ') + ";业务逻辑耗时:" + ((int)logicTimes).ToString().PadRight(4, ' ') + ";周期总耗时" + ((int)total).ToString().PadRight(4, ' ') + ""); Console.ResetColor(); last = DateTime.Now; Configs.Publish(); logicTimes = (int)(DateTime.Now - last).TotalMilliseconds; } } public static void StopAll() { foreach (var h in Handlers) { try { h.Stop(); } catch { } } } } public abstract class LogicHandler : LogicHandler where T : EntityEx { private string logPath = ""; protected List> Works = new List>(); private IEnumerable _Objects = null; protected IEnumerable Objects { get { if (_Objects == null) { _Objects = AllObjects.OfType().Where(v => SelectDevice(v)).Select(v => Activator.CreateInstance(typeof(T), v)).OfType().ToArray(); } return _Objects.Where(v => v.Entity.ENABLED && v.Entity.PROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED)); } } private bool SelectDevice(WCS_DEVICE dev) { var typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray(); var res = typenames.All(v => dev.PROTOCOLS.Any(d => d.DB.PROTOCOL == v)); return res; } public LogicHandler() { logPath = @"Log\" + this.Description + @"\"; } public void AddWork(Func condition, Action work, bool parallel = false) { var title = work.Method.Name; var attr = work.Method.GetCustomAttributes(false).OfType().FirstOrDefault(); if (attr != null) title = attr.Description; var arr = Objects.Where(condition).ToArray(); this.Works.Add(new WorkInfo { Work = work, Params = arr, Title = title, Parallel = parallel }); } public void AddWork(IEnumerable arr, Action work, bool parallel = false) { var title = work.Method.Name; var attr = work.Method.GetCustomAttributes(false).OfType().FirstOrDefault(); if (attr != null) title = attr.Description; this.Works.Add(new WorkInfo { Work = work, Params = arr, Title = title, Parallel = parallel }); } public override void Update(double milliseconds) { if (ParallelRun) { Parallel.ForEach(Works, w => { DoWork(w); }); } else { foreach (var w in Works) { DoWork(w); } } } protected virtual void DoWork(WorkInfo work) { if (work.Parallel) { Parallel.ForEach(work.Params, p => { Do(work, p); }); } else { foreach (var p in work.Params) { Do(work, p); } } } protected virtual void Do(WorkInfo wi, T p) { var channel = Description + "." + wi.Title + "." + p.ToString(); try { Ltc.SetChannel(channel); Ltc.Log("开始---------------------------------------"); wi.Work(p); } catch (Exception ex) { Ltc.Log(ex.GetBaseException().Message); Log(wi, p, ex); } finally { Ltc.Log("结束\n"); } } protected virtual void Log(WorkInfo wi, T p, Exception ex) { try { var msg = Description + "--" + wi.Title + "--"; if (p is IProtocol) { msg += (p as IProtocol).PROTOCOL().DEVICE.NAME; } msg = msg + ":" + ex.GetBaseException().Message; Console.WriteLine(msg); Log(msg); DbLog.Invoke(msg, DateTime.Now); } catch (Exception ex2) { } } private static object lockobj = new object(); protected void Log(string msg) { lock (lockobj) { try { var str = "-----------" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss:fff") + "-----------\r\n"; str += msg; if (!Directory.Exists(logPath)) Directory.CreateDirectory(logPath); var file = logPath + DateTime.Now.ToString("yyyyMMdd") + ".log"; var writer = File.AppendText(file); writer.WriteLine(str); writer.Flush(); writer.Close(); } catch (Exception ex) { } } } /// /// 此方法不会被自动调用,请在Start方法中使用AddWork将其添加至工作队列 /// /// [Description("执行")] protected abstract void Execute(T dev); } public abstract class WorkHandler : LogicHandler { private string logPath = ""; protected List Works = new List(); public WorkHandler() { logPath = @"Log\" + this.Description + @"\"; var arr = Assembly.GetEntryAssembly().GetTypes().Where(v => v.IsSubclassOf(typeof(Work))).Where(v => { var attr = v.GetCustomAttribute(); if (attr == null) return false; return attr.Handler == this.GetType(); }); var works = arr.Select(v => Activator.CreateInstance(v) as Work).Select(v => { var attr = v.GetType().GetCustomAttribute(); return new WorkInfo { Params = v.GetObjs(), Work = v.Execute, Title = attr.Title, Parallel = attr.Parallel }; }).ToArray(); Works.AddRange(works); } public override sealed void Start() { //throw new NotImplementedException(); } public override void Update(double milliseconds) { if (ParallelRun) { Parallel.ForEach(Works, w => { DoWork(w); }); } else { foreach (var w in Works) { DoWork(w); } } } protected virtual void DoWork(WorkInfo work) { if (work.Parallel) { Parallel.ForEach(work.Params, p => { Do(work, p); }); } else { foreach (var p in work.Params) { Do(work, p); } } } protected virtual void Do(WorkInfo wi, object p) { var dt = DateTime.Now; var channel = Description + "." + wi.Title + "." + p.ToString(); try { Ltc.SetChannel(channel); Ltc.Log("开始---------------------------------------"); wi.Work(p); } catch (Exception ex) { Ltc.Log(ex.GetBaseException().Message); Log(wi, p, ex); Configs.UploadException?.Invoke(p.ToString(), ex.GetBaseException().Message); } finally { var dd = (DateTime.Now - dt).TotalMilliseconds; if (dd > 500) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(channel + "耗时" + dd); Console.ResetColor(); } if (dd > 10000) Configs.UploadException?.Invoke(p.ToString(), wi.Title + "执行耗时" + Math.Floor(dd / 1000) + "秒"); Ltc.Log("结束\n"); } } protected virtual void Log(WorkInfo wi, object p, Exception ex) { try { var msg = Description + "--" + wi.Title + "--"; if (p is IProtocol) { msg += (p as IProtocol).PROTOCOL().DEVICE.NAME; } msg = msg + ":" + ex.GetBaseException().Message; Console.WriteLine(msg); Log(msg); DbLog.Invoke(msg, DateTime.Now); } catch (Exception ex2) { } } private static object lockobj = new object(); protected void Log(string msg) { lock (lockobj) { try { var str = "-----------" + DateTime.Now.ToString("yyyyMMdd HH:mm:ss:fff") + "-----------\r\n"; str += msg; if (!Directory.Exists(logPath)) Directory.CreateDirectory(logPath); var file = logPath + DateTime.Now.ToString("yyyyMMdd") + ".log"; var writer = File.AppendText(file); writer.WriteLine(str); writer.Flush(); writer.Close(); } catch (Exception ex) { } } } } public class WorkTitleAttribute : Attribute { public Type Handler { get; set; } public string Title { get; set; } public bool Parallel { get; set; } public WorkTitleAttribute(Type handler, string title, bool parallel = false) { this.Handler = handler; this.Title = title; this.Parallel = parallel; } } public abstract class Work { public abstract IEnumerable GetObjs(); public abstract void Execute(object obj); } public abstract class Work : Work { public override sealed void Execute(object obj) { Do((T)obj); } public override sealed IEnumerable GetObjs() { return InitObjects().OfType().ToArray(); } protected abstract void Do(T obj); protected abstract IEnumerable InitObjects(); } public abstract class DeviceWork : Work where T : EntityEx { private string[] typenames; public DeviceWork() { typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray(); } protected abstract bool SelectDevice(WCS_DEVICE dev); protected abstract override void Do(T obj); protected override sealed IEnumerable InitObjects() { var res = Device.Where(v => v.ENABLED && v.PROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED)) .Where(v => typenames.All(d => v.PROTOCOLS.Any(e => e.DB.PROTOCOL == d))) .Where(v => SelectDevice(v)) .Select(v => Activator.CreateInstance(typeof(T), v) as T); return res; } } }