using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using TeamAAS.Communication.Attributes;
using TeamAAS.Communication.Base;
using TeamAAS.Communication.Interfaces;
using TeamAAS.Communication.Models;
using TeamAAS.Communication.PLCs;
namespace TeamAAS.Communication
{
///
/// 通讯设备统一管理器。
/// 整合设备管理、类型注册(反射)、连接操作、PLC读写和配置持久化。
/// 同时作为懒汉单例使用:CommunicationManager.Instance。
///
public class CommunicationManager : IDisposable
{
#region 单例
private static readonly Lazy _instance =
new Lazy(() => new CommunicationManager(), isThreadSafe: true);
///
/// 懒汉单例入口。首次访问时初始化,线程安全。
///
public static CommunicationManager Instance => _instance.Value;
#endregion
private readonly object _sync = new object();
private readonly Dictionary _devices = new Dictionary();
#region 类型注册(反射扫描)
private static readonly Lazy> _types =
new Lazy>(Scan);
public IReadOnlyList GetAvailableTypes() => _types.Value;
public CommunicationTypeInfo GetTypeInfo(string typeKey) =>
string.IsNullOrWhiteSpace(typeKey) ? null : _types.Value.FirstOrDefault(t => t.TypeKey == typeKey);
public IReadOnlyList GetPlcTypes() =>
_types.Value.Where(t => typeof(PlcCommunicationBase).IsAssignableFrom(t.Type)).ToList();
public IReadOnlyList GetBasicTypes() =>
_types.Value.Where(t => string.Equals(t.Category, "基础通讯", StringComparison.Ordinal)).ToList();
private static List Scan()
{
var result = new List();
// 通用模块扫描:收集全部 ICommunication 实现(含 Runtime\Plugins 里的插件 DLL),
// 插件项目新增的通讯设备类型无需修改主程序即可被发现。
foreach (var type in TeamAAS.Modularity.AssemblyScanner.FindImplementations())
{
var attr = type.GetCustomAttribute();
if (attr == null) continue;
result.Add(new CommunicationTypeInfo
{
TypeKey = type.FullName,
DisplayName = attr.DisplayName,
Category = attr.Category,
Description = attr.Description,
Type = type,
});
}
return result
.GroupBy(t => t.TypeKey)
.Select(g => g.First())
.OrderBy(t => t.Category)
.ThenBy(t => t.DisplayName)
.ToList();
}
#endregion
#region 设备列表
public IReadOnlyList Devices
{
get { lock (_sync) return _devices.Values.OrderBy(d => d.Index).ToList(); }
}
public int Count
{
get { lock (_sync) return _devices.Count; }
}
#endregion
#region 创建与注册
public ICommunication Create(string typeKey, Guid id, string name, int index)
{
if (string.IsNullOrWhiteSpace(typeKey))
throw new ArgumentException("TypeKey 不能为空。", nameof(typeKey));
var typeInfo = GetTypeInfo(typeKey);
if (typeInfo == null)
throw new InvalidOperationException($"未找到通讯设备类型: {typeKey}");
var device = (ICommunication)Activator.CreateInstance(typeInfo.Type);
device.Id = id;
device.Index = index;
device.Name = name;
Register(device);
return device;
}
public void Register(ICommunication device)
{
if (device == null) throw new ArgumentNullException(nameof(device));
ICommunication replaced = null;
lock (_sync)
{
if (_devices.TryGetValue(device.Id, out replaced)
&& ReferenceEquals(replaced, device))
{
return;
}
_devices[device.Id] = device;
}
// 替换同一 ID 的设备时,先从注册表移除旧实例,再在锁外释放底层连接资源,
// 避免 Dispose/Disconnect 回调反向访问管理器造成锁重入。
if (replaced != null)
{
try { replaced.Disconnect(); } catch { }
try { replaced.Dispose(); } catch { }
}
}
#endregion
#region 设备获取
public ICommunication Get(Guid id)
{
lock (_sync) { _devices.TryGetValue(id, out var device); return device; }
}
public bool TryGet(Guid id, out ICommunication device)
{
lock (_sync) { return _devices.TryGetValue(id, out device); }
}
public ICommunication GetByName(string name) => Devices.FirstOrDefault(d => d.Name == name);
public bool Remove(Guid id)
{
ICommunication device;
lock (_sync)
{
if (!_devices.TryGetValue(id, out device)) return false;
_devices.Remove(id);
}
try { device.Disconnect(); } catch { }
device.Dispose();
return true;
}
#endregion
#region 便捷查询
public IReadOnlyList GetAll() => Devices;
public IReadOnlyList GetConnected() => Devices.Where(d => d.IsConnected).ToList();
public IReadOnlyList GetDisconnected() => Devices.Where(d => !d.IsConnected).ToList();
public IReadOnlyList GetTcpClients() => Devices.Where(d => d is Devices.TcpClientCommunication).ToList();
public IReadOnlyList GetTcpServers() => Devices.Where(d => d is Devices.TcpServerCommunication).ToList();
public IReadOnlyList GetSerials() => Devices.Where(d => d is Devices.SerialCommunication).ToList();
public IReadOnlyList GetUdps() => Devices.Where(d => d is Devices.UdpCommunication).ToList();
public IReadOnlyList GetWebs() => Devices.Where(d => d is Devices.WebCommunication).ToList();
#endregion
#region PLC 查询
public IReadOnlyList GetAllPlcModules() => Devices.Where(d => d is PlcCommunicationBase).ToList();
public IReadOnlyList GetConnectedPlcModules() => GetAllPlcModules().Where(p => p.IsConnected).ToList();
public IReadOnlyList GetPlcByProtocol(string typeKey) => Devices.Where(d => d is PlcCommunicationBase && d.TypeKey == typeKey).ToList();
#endregion
#region 连接操作
public void Connect(Guid id)
{
var device = Get(id);
if (device != null) device.Connect();
}
public void Disconnect(Guid id)
{
var device = Get(id);
if (device != null) device.Disconnect();
}
public void ConnectAll()
{
foreach (var device in Devices) try { device.Connect(); } catch { }
}
public void DisconnectAll()
{
foreach (var device in Devices) try { device.Disconnect(); } catch { }
}
public void ConnectAllPlc()
{
foreach (var plc in GetAllPlcModules()) try { plc.Connect(); } catch { }
}
public void DisconnectAllPlc()
{
foreach (var plc in GetAllPlcModules()) try { plc.Disconnect(); } catch { }
}
#endregion
#region PLC 读写便捷方法
public object ReadPlcValue(Guid plcId, string address)
{
var plc = Get(plcId);
if (plc == null) throw new InvalidOperationException($"PLC 设备未找到: {plcId}");
return plc.ReadValue(address);
}
public void WritePlcValue(Guid plcId, string address, object value)
{
var plc = Get(plcId);
if (plc == null) throw new InvalidOperationException($"PLC 设备未找到: {plcId}");
plc.WriteValue(address, value);
}
public async System.Threading.Tasks.Task