using Logs; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; using WCS.Entity; using WCS.Service; namespace WCS.Core { /// /// 逻辑处理器 /// public abstract class LogicHandler { /// /// 停止 /// protected bool Stoped = false; /// /// 描述 /// protected string Description { get; } /// /// 所有对象 /// public static List AllObjects = new(); /// /// 所有处理器 /// private static readonly List Handlers = new(); /// /// 日志委托,暂时弃用 /// [Obsolete] public static Action DbLog; /// /// 逻辑处理器 /// protected LogicHandler() { var attr = this.GetType().GetCustomAttributes(false).OfType().FirstOrDefault(); Description = attr != null ? attr.Description : this.GetType().Name; } /// /// 开始 /// public abstract void Start(); /// /// 是否并行 /// public virtual bool ParallelRun => 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(Loop) { IsBackground = true //前台线程即主线程关闭,立即结束该线程 }; th.Start(); } /// /// 最后一次执行结束的时间 /// private static DateTime _last = DateTime.Now; /// ///逻辑耗时 /// private static int _logicTimes; public static DateTime Frame { get; private set; } /// /// 主循环体,用于PLC数据的读取与逻辑执行 /// private static void Loop() { //TODO:可能存在异常,使用时需验证一次 var arr = AllObjects.OfType().Where(v => v.ENABLED).SelectMany(v => v.DEVICEPROTOCOLS) .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; 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; //此处打印的logicTimes实际是上一个周期的业务处理时长 Console.WriteLine("------刷新DB块数据耗时:" + ((int)dbTimes).ToString().PadRight(4, ' ') + ";业务逻辑耗时:" + ((int)_logicTimes).ToString().PadRight(4, ' ') + ";周期总耗时" + ((int)total).ToString().PadRight(4, ' ') + ""); Console.ResetColor(); _last = DateTime.Now; Parallel.ForEach(Handlers, m => { var dm = DateTime.Now; try { m.Update(total); } catch (Exception) { //TODO:增加一个异常记录 } var dm2 = (DateTime.Now - dm).TotalMilliseconds; }); Configs.Publish(); _logicTimes = (int)(DateTime.Now - _last).TotalMilliseconds; } } /// /// 停止所有的处理器 /// public static void StopAll() { foreach (var h in Handlers) { try { h.Stop(); } catch { // TODO:等待处理 } } } } /// /// 逻辑处理器 泛型 /// /// public abstract class LogicHandler : LogicHandler where T : EntityEx { /// /// 业务类集合 /// protected List> Works = new(); /// /// TODO:? /// private IEnumerable _objects = null; protected IEnumerable Objects { get { _objects ??= AllObjects.OfType().Where(SelectDevice) .Select(v => Activator.CreateInstance(typeof(T), v)).OfType().ToArray(); return _objects.Where(v => v.Entity.ENABLED && v.Entity.DEVICEPROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED)); } } /// /// 写入设备信息 /// /// 设备 /// private static bool SelectDevice(WCS_DEVICE dev) { var typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray(); var res = typenames.All(v => dev.DEVICEPROTOCOLS.Any(d => d.DB.PROTOCOL == v)); return res; } /// /// 添加Work /// /// /// work /// 是否并发 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, DoWork); } else { foreach (var w in Works) { DoWork(w); } } } /// /// 执行Work /// /// 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; try { Ltc.SetChannel(channel); Ltc.Log("开始---------------------------------------"); wi.Work(p); } catch (DoException ex) { InfoLog.INFO_INFO($"[{channel}]--{ex.Message}"); } //WarnException进阶条件未满足,添加数据库,记录文本日志、数据库,上抛WCS,上抛WMS catch (WarnException ex) { InfoLog.INFO_WARN($"[{channel}]--{ex.Message}"); Ltc.Log(ex.GetBaseException().Message); Configs.UploadException?.Invoke(p.ToString(), ex.GetBaseException().Message); } //未知异常,仅记录文本日志,需定期排查该文件,检查系统是否有未知异常,并处理 catch (Exception ex) { InfoLog.INFO_ERROR($"[{channel}]--{ex.Message}--{ex.StackTrace}"); } finally { Ltc.Log("结束\n"); } } /// /// 此方法不会被自动调用,请在Start方法中使用AddWork将其添加至工作队列 /// /// [Description("执行")] protected abstract void Execute(T dev); } 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 bool SelectDevice(WCS_DEVICE dev); protected virtual IEnumerable InitObjects() { var arr = Device.Where(v => v.ENABLED) .Where(SelectDevice).ToArray(); var res = arr.Select(v => (T)Activator.CreateInstance(typeof(T), v)); return res; } } public abstract class DeviceWork : Work where T : EntityEx { private readonly string[] _typenames; protected DeviceWork() { _typenames = typeof(T).GenericTypeArguments.Select(v => v.AssemblyQualifiedName).ToArray(); } protected abstract override void Do(T obj); protected override sealed IEnumerable InitObjects() { var arr = Device.Where(v => v.ENABLED && v.DEVICEPROTOCOLS.All(d => d.ENABLED && d.DB.ENABLED && d.DB.PLC.ENABLED)) .Where(v => _typenames.All(d => v.DEVICEPROTOCOLS.Any(e => e.DB.PROTOCOL == d))) .Where(SelectDevice).ToArray(); var res = arr.Select(v => Activator.CreateInstance(typeof(T), v) as T); return res; } } }