| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using TeamAAS.Robot.Core.Robots;
- using TeamAAS.Robot.Interfaces;
- using TeamAAS.Robot.Models;
- using System.Reflection;
- using TeamAAS.Robot.Attributes;
- using TeamAAS.Robot.Enums;
- namespace TeamAAS.Robot
- {
- /// <summary>
- /// 机器人生命周期管理器。懒汉单例:<c>RobotManager.Instance</c>。
- /// 整合:设备创建/连接/运动/配置持久化 + 反射发现品牌类型 + IDisposable。
- /// 管理类按架构规则保留在根命名空间 TeamAAS.Robot。
- /// </summary>
- public class RobotManager : IRobotManager, IDisposable
- {
- #region 单例
- private static readonly Lazy<RobotManager> _instance =
- new Lazy<RobotManager>(() => new RobotManager(), isThreadSafe: true);
- /// <summary>
- /// 懒汉单例入口。首次访问时初始化,线程安全。
- /// </summary>
- public static RobotManager Instance => _instance.Value;
- #endregion
- private readonly Dictionary<Guid, IRobot> _robotCollection;
- private readonly object _sync = new object();
- private List<RobotTypeInfo> _scannedTypes;
- private readonly object _scanLock = new object();
- public RobotManager()
- {
- _robotCollection = new Dictionary<Guid, IRobot>();
- }
- #region 机器人 CRUD
- public bool CreateRobot(Guid id, RobotInfo robotInfo)
- {
- if (robotInfo == null) throw new ArgumentNullException(nameof(robotInfo));
- var robot = CreateRobotInstance(robotInfo);
- robot.Id = id;
- IRobot replaced = null;
- lock (_sync)
- {
- _robotCollection.TryGetValue(id, out replaced);
- _robotCollection[id] = robot;
- }
- if (replaced != null && !ReferenceEquals(replaced, robot))
- {
- try { replaced.Dispose(); } catch { }
- }
- return true;
- }
- public Task<bool> CreateRobotAsync(Guid id, RobotInfo robotInfo)
- {
- return Task.Run(() => CreateRobot(id, robotInfo));
- }
- public IRobot GetRobot(Guid id)
- {
- lock (_sync)
- {
- return _robotCollection.TryGetValue(id, out var robot) ? robot : null;
- }
- }
- public Task<IRobot> GetRobotAsync(Guid id)
- {
- return Task.Run(() => GetRobot(id));
- }
- public void UnRegisterRobot(Guid id)
- {
- IRobot robot = null;
- lock (_sync)
- {
- if (_robotCollection.TryGetValue(id, out robot))
- _robotCollection.Remove(id);
- }
- if (robot != null)
- {
- try { robot.Dispose(); } catch { }
- }
- }
- public Task UnRegisterRobotAsync(Guid id)
- {
- return Task.Run(() => UnRegisterRobot(id));
- }
- public IReadOnlyCollection<IRobot> GetAllRobots()
- {
- lock (_sync)
- {
- return _robotCollection.Values.ToList().AsReadOnly();
- }
- }
- public Task<IReadOnlyCollection<IRobot>> GetAllRobotsAsync()
- {
- return Task.Run(() => GetAllRobots());
- }
- public bool TryGetRobot(Guid id, out IRobot robot)
- {
- lock (_sync)
- {
- return _robotCollection.TryGetValue(id, out robot);
- }
- }
- public Task<(bool found, IRobot robot)> TryGetRobotAsync(Guid id)
- {
- return Task.Run(() =>
- {
- IRobot robot;
- bool found;
- lock (_sync)
- {
- found = _robotCollection.TryGetValue(id, out robot);
- }
- return (found, robot);
- });
- }
- public System.Collections.Generic.IReadOnlyList<IRobot> Devices
- {
- get
- {
- lock (_sync)
- {
- return _robotCollection.Values.ToList().AsReadOnly();
- }
- }
- }
- public bool ContainsRobot(Guid id)
- {
- lock (_sync)
- {
- return _robotCollection.ContainsKey(id);
- }
- }
- public Task<bool> ContainsRobotAsync(Guid id)
- {
- return Task.Run(() => ContainsRobot(id));
- }
- public bool RemoveRobot(Guid id)
- {
- IRobot robot = null;
- lock (_sync)
- {
- if (_robotCollection.TryGetValue(id, out robot))
- _robotCollection.Remove(id);
- }
- if (robot != null)
- {
- try { robot.Dispose(); } catch { }
- return true;
- }
- return false;
- }
- public Task<bool> RemoveRobotAsync(Guid id)
- {
- return Task.Run(() => RemoveRobot(id));
- }
- public IRobot GetRobotByNumber(int robotNo)
- {
- return TryFindRobotByNumber(robotNo, out _, out var robot) ? robot : null;
- }
- public Task<IRobot> GetRobotByNumberAsync(int robotNo)
- {
- return Task.Run(() => GetRobotByNumber(robotNo));
- }
- public Task UnRegisterRobotByNumberAsync(int robotNo)
- {
- return Task.Run(() => UnRegisterRobotByNumber(robotNo));
- }
- public void UnRegisterRobotByNumber(int robotNo)
- {
- if (TryFindRobotByNumber(robotNo, out var id, out _))
- UnRegisterRobot(id);
- }
- public void RemoveAllRobots()
- {
- List<Guid> robotIds;
- lock (_sync)
- {
- robotIds = _robotCollection.Keys.ToList();
- }
- foreach (var id in robotIds)
- {
- RemoveRobot(id);
- }
- }
- public (bool IsSucceed, string Message) InitializeAllRobots(RobotInfo[] robots)
- {
- RemoveAllRobots();
- foreach (var robotInfo in robots)
- {
- var robot = CreateRobotInstance(robotInfo);
- lock (_sync)
- {
- _robotCollection[robot.Id] = robot;
- }
- }
- bool allConnected = true;
- StringBuilder errorMessages = new StringBuilder();
- var allRobots = GetAllRobots();
- foreach (var robot in allRobots)
- {
- try { robot.Connect(); } catch { }
- if (!robot.IsConnected)
- {
- allConnected = false;
- errorMessages.AppendLine($"机器人[{robot.Name}]连接失败。");
- }
- }
- return allConnected ? (true, "所有机器人初始化并连接成功。") : (false, errorMessages.ToString());
- }
- public Task<(bool IsSucceed, string Message)> InitializeAllRobotsAsync(RobotInfo[] robots)
- {
- return Task.Run(() => InitializeAllRobots(robots));
- }
- public void UpdateRobotNumber(Guid id, int newNumber)
- {
- lock (_sync)
- {
- if (_robotCollection.TryGetValue(id, out var robot))
- robot.RobotNo = newNumber;
- }
- }
- private bool TryFindRobotByNumber(int robotNo, out Guid id, out IRobot robot)
- {
- lock (_sync)
- {
- foreach (var kvp in _robotCollection)
- {
- if (kvp.Value == null) continue;
- if (kvp.Value.RobotNo == robotNo)
- {
- id = kvp.Key;
- robot = kvp.Value;
- return true;
- }
- }
- }
- id = Guid.Empty;
- robot = null;
- return false;
- }
- #endregion
- #region 配置持久化
- public static string DefaultConfigPath
- {
- get
- {
- return Path.Combine(TeamAAS.PathHelper.ConfigDirectory, "Robots.json");
- }
- }
- public bool SaveConfig(string path = null)
- {
- path = path ?? DefaultConfigPath;
- var infos = new List<RobotInfo>();
- lock (_sync)
- {
- foreach (var robot in _robotCollection.Values)
- {
- infos.Add(new RobotInfo
- {
- Id = robot.Id,
- RobotNo = robot.RobotNo,
- RobotName = robot.Name,
- RobotBrand = robot.Brand,
- IP = robot.RobotIp,
- Port = robot.RobotPort,
- ConnectType = robot.ConnectType,
- Terminator = robot.Terminator,
- DataEncoding = robot.DataEncoding,
- });
- }
- }
- return TeamAAS.JsonFileStore.Save(path, infos);
- }
- public IReadOnlyList<RobotInfo> GetAllRobotInfos()
- {
- var infos = new List<RobotInfo>();
- lock (_sync)
- {
- foreach (var robot in _robotCollection.Values)
- {
- infos.Add(new RobotInfo
- {
- Id = robot.Id,
- RobotNo = robot.RobotNo,
- RobotName = robot.Name,
- RobotBrand = robot.Brand,
- IP = robot.RobotIp,
- Port = robot.RobotPort,
- ConnectType = robot.ConnectType,
- Terminator = robot.Terminator,
- DataEncoding = robot.DataEncoding,
- });
- }
- }
- return infos.AsReadOnly();
- }
- public void LoadConfig(string path = null)
- {
- path = path ?? DefaultConfigPath;
- if (!File.Exists(path)) return;
- var infos = TeamAAS.JsonFileStore.Load<List<RobotInfo>>(path);
- if (infos == null || infos.Count == 0) return;
- InitializeAllRobots(infos.ToArray());
- }
- #endregion
- #region 反射扫描 + 工厂
- public IReadOnlyList<RobotTypeInfo> GetAvailableTypes()
- {
- if (_scannedTypes != null) return _scannedTypes.AsReadOnly();
- lock (_scanLock)
- {
- if (_scannedTypes != null) return _scannedTypes.AsReadOnly();
- _scannedTypes = ScanTypes();
- return _scannedTypes.AsReadOnly();
- }
- }
- private List<RobotTypeInfo> ScanTypes()
- {
- var result = new List<RobotTypeInfo>();
- // 通用模块扫描:收集全部 IRobot 实现(含 Runtime\Plugins 里的插件 DLL)
- foreach (var type in TeamAAS.Modularity.AssemblyScanner.FindImplementations<IRobot>())
- {
- var attrs = type.GetCustomAttributes<RobotAttribute>();
- foreach (var attr in attrs)
- {
- result.Add(new RobotTypeInfo
- {
- TypeKey = type.FullName,
- DisplayName = attr.DisplayName,
- Brand = attr.Brand,
- Description = attr.Description,
- Type = type
- });
- }
- }
- return result
- .GroupBy(t => t.TypeKey + "|" + t.Brand)
- .Select(g => g.First())
- .OrderBy(t => t.DisplayName)
- .ToList();
- }
- private IRobot CreateRobotInstance(RobotInfo robotInfo)
- {
- if (robotInfo == null) throw new ArgumentNullException(nameof(robotInfo));
- var types = GetAvailableTypes();
- var match = types.FirstOrDefault(t => t.Brand == robotInfo.RobotBrand);
- if (match == null)
- {
- // fallback 到 EPSON 实现(兼容未注册的品牌占位)
- return new EpsonRobot(robotInfo);
- }
- return (IRobot)Activator.CreateInstance(match.Type, robotInfo);
- }
- #endregion
- #region IDisposable
- public void Dispose()
- {
- List<IRobot> robots;
- lock (_sync)
- {
- robots = _robotCollection.Values.ToList();
- _robotCollection.Clear();
- }
- foreach (var r in robots)
- {
- try { r.Dispose(); } catch { }
- }
- GC.SuppressFinalize(this);
- }
- #endregion
- }
- }
|