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;
}
}
}