lixun il y a 2 ans
Parent
commit
54a6306e9e

+ 4 - 13
src/YSAI.DAQ/YSAI.DaqManage/DaqManageData.cs

@@ -25,14 +25,15 @@ namespace YSAI.DaqManage
             /// 库配置文件夹,绝对路径
             /// </summary>
             public string? LibConfigFolder { get; set; } = $"{AppDomain.CurrentDomain.BaseDirectory}config";
+
             /// <summary>
-            /// 唯一标识符键
+            /// 库配置唯一标识符键
             /// </summary>
-            public string? SNKey { get; set; } = "SN";
+            public string? LibConfigSNKey { get; set; } = "SN";
 
             /// <summary>
             /// 配置文件名称的格式,SN与配置数据中的SN一致
-            /// *.Config-SN.json
+            /// *.Config-*.json
             /// </summary>
             public string? ConfigFileNameFormat { get; set; } = "{0}.Config-*.json";
 
@@ -40,16 +41,6 @@ namespace YSAI.DaqManage
             /// 接口名称
             /// </summary>
             public string? InterfaceFullName { get; set; } = "YSAI.Core.interface.unify.IDaq";
-
-            /// <summary>
-            /// 抽象类
-            /// </summary>
-            public string? AbstractClassFullName { get; set; }= "YSAI.Core.interface.unify.IBaseAbstract";
-
-            /// <summary>
-            /// 监控间隔
-            /// </summary>
-            public int MonitorInterval { get; set; } = 5000;
         }
     }
 }

+ 588 - 139
src/YSAI.DAQ/YSAI.DaqManage/DaqManageOperate.cs

@@ -1,10 +1,12 @@
 using Newtonsoft.Json.Linq;
+using StackExchange.Redis;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Net;
 using System.Reflection;
 using System.Reflection.Metadata;
 using System.Text;
@@ -21,7 +23,7 @@ namespace YSAI.DaqManage
     /// 库:*.dll,
     /// 库配置:*.Config*.json
     /// </summary>
-    public class DaqManageOperate : IBaseAbstract, IDaq
+    public class DaqManageOperate : IBaseAbstract
     {
         protected override string LogHead => "[ DaqManageOperate 操作 ]";
         protected override string ClassName => "DaqManageOperate";
@@ -110,108 +112,356 @@ namespace YSAI.DaqManage
         }
 
         /// <summary>
-        /// 实例集合
+        /// 实例容器集合
         /// </summary>
-        private ConcurrentDictionary<string, IDaq> instanceArray;
-
+        private ConcurrentDictionary<string, IDaq> InstanceIoc;
+        /// <summary>
+        /// 库类型容器
+        /// </summary>
+        private ConcurrentDictionary<string, Type> TypeIoc;
+        /// <summary>
+        /// 文件夹监控
+        /// </summary>
+        private FileSystemWatcher watcherLibFolder;
+        /// <summary>
+        /// 文件夹监控
+        /// </summary>
+        private FileSystemWatcher watcherLibConfigFolder;
         /// <summary>
         /// 监控文件夹
         /// </summary>
         public Task Monitor()
         {
-            //起个新线程处理
+            //起个新线程
             return Task.Factory.StartNew(() =>
             {
-                while (true)
+                //实例容器实例化
+                if (InstanceIoc == null)
                 {
-                    try
+                    InstanceIoc = new ConcurrentDictionary<string, IDaq>();
+                }
+                //程序集
+                if (TypeIoc == null)
+                {
+                    TypeIoc = new ConcurrentDictionary<string, Type>();
+                }
+                //获取配置
+                if (basics == null)
+                {
+                    this.basics = GetConfig();
+                }
+
+                if (basics != null)
+                {
+                    //检索
+                    Search();
+
+                    //文件夹监控
+                    watcherLibFolder = new FileSystemWatcher(basics.LibFolder);
+                    //监控的配置
+                    watcherLibFolder.Filter = "*.dll";
+                    //当文件夹中新增文件
+                    watcherLibFolder.Created += delegate (object sender, FileSystemEventArgs e) { Watcher_Created(sender, e, 0); };
+                    //当文件夹中删除文件
+                    watcherLibFolder.Deleted += delegate (object sender, FileSystemEventArgs e) { Watcher_Deleted(sender, e, 0); };
+                    //启动监听
+                    watcherLibFolder.EnableRaisingEvents = true;
+
+
+                    //文件夹监视
+                    watcherLibConfigFolder = new FileSystemWatcher(basics.LibConfigFolder);
+                    //监控的配置
+                    watcherLibConfigFolder.Filter = "*.Config-*.json";
+                    //当文件夹中新增文件
+                    watcherLibConfigFolder.Created += delegate (object sender, FileSystemEventArgs e) { Watcher_Created(sender, e, 1); };
+                    //当文件夹中删除文件
+                    watcherLibConfigFolder.Deleted += delegate (object sender, FileSystemEventArgs e) { Watcher_Deleted(sender, e, 1); };
+                    //启动监听
+                    watcherLibConfigFolder.EnableRaisingEvents = true;
+
+                }
+                else
+                {
+                    OnEventHandler?.Invoke(this, new EventResult(false, $"配置文件不存在"));
+                }
+            });
+        }
+        /// <summary>
+        /// 当文件夹中删除文件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        /// <param name="Type">【0:库文件】【1:配置文件】</param>
+        private void Watcher_Deleted(object sender, FileSystemEventArgs e, int Type)
+        {
+            //程序集SN
+            string TypeSN = string.Empty;
+            switch (Type)
+            {
+                case 0:
+                    OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 文件被删除,移除此库程序集,并移除所有实例"));
+                    //程序集SN
+                    TypeSN = e.Name.Replace(".dll", string.Empty);
+
+                    foreach (var item in InstanceIoc)
                     {
-                        if (basics == null)
+                        if (item.Key.Contains(TypeSN))
                         {
-                            this.basics = GetConfig();
+                            InstanceIoc[item.Key].Dispose();
+                            if (InstanceIoc.Remove(item.Key, out _))
+                            {
+                                OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 移除配置实例 {item.Key} 成功"));
+                            }
+                            else
+                            {
+                                OnEventHandler?.Invoke(this, new EventResult(false, $"{e.Name} 移除配置实例 {item.Key} 失败"));
+                            }
                         }
-                        //库
-                        List<string> libs = Directory.GetFiles(basics.LibFolder, "*.dll", SearchOption.AllDirectories).ToList();
-                        //程序集
-                        List<Type> TypeArray = new();
-                        //循环文件,添加程序集
-                        foreach (var lib in libs)
+                    }
+
+                    foreach (var item in TypeIoc)
+                    {
+                        if (item.Key.Contains(TypeSN))
                         {
-                            //加载程序集
-                            Assembly assembly = Assembly.LoadFrom(lib);
-                            //获取所有类
-                            Type[] types = assembly.GetExportedTypes();
-                            //过滤器
-                            TypeFilter typeFilter = new TypeFilter(InterfaceFilter);
-                            //集合
-                            List<Type> typesArray = new List<Type>();
-                            //检索类是否继承接口
-                            foreach (Type type in types)
+                            if (TypeIoc.Remove(item.Key, out _))
                             {
-                                if (type.FindInterfaces(typeFilter, basics.InterfaceFullName).Count() > 0)
-                                {
-                                    typesArray.Add(type);
-                                }
+                                OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 移除程序集 {item.Key} 成功"));
+                            }
+                            else
+                            {
+                                OnEventHandler?.Invoke(this, new EventResult(false, $"{e.Name} 移除程序集 {item.Key} 失败"));
                             }
-                            //添加至集合
-                            TypeArray.AddRange(typesArray.ToArray());
                         }
-                        //获取配置
-                        foreach (var type in TypeArray)
+                    }
+                    break;
+                case 1:
+                    OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 文件被删除,移除对应配置实例"));
+                    //程序集SN
+                    TypeSN = e.Name.Split('-')[0].Replace(".Config", string.Empty);
+                    //分割
+                    string[] strs = e.Name.Split('-');
+                    if (strs.Length > 1)
+                    {
+                        //获取配置实例SN
+                        string SN = $"{TypeSN}:{e.Name.Split('-')[1].Split('.')[0]}";
+                        if (InstanceIoc.ContainsKey(SN))
                         {
-                            //组织配置文件
-                            string configFile = string.Format(basics.ConfigFileNameFormat, type.FullName);
-                            //目录信息
-                            DirectoryInfo directoryInfo = new DirectoryInfo(basics.LibConfigFolder);
-                            //文件检索得到文件信息
-                            List<FileInfo> fieldInfos = new List<FileInfo>(directoryInfo.GetFiles(configFile, SearchOption.AllDirectories));
-                            //如果文件信息为空则不创建实例
-                            if (fieldInfos.Count > 0)
+                            InstanceIoc[SN].Dispose();
+                            if (InstanceIoc.Remove(SN, out _))
                             {
-                                //循环检索配置文件信息
-                                foreach (FileInfo fi in fieldInfos)
-                                {
-                                    //获取结构参数
-                                    JObject? jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject>(File.ReadAllText(fi.FullName));
-                                    //获取唯一标识符
-                                    string SN = jsonObject[basics.SNKey].ToString();
-                                    //获取实例
-                                    IDaq? instance = CreateInstance(type, new object[] { jsonObject }) as IDaq;
-                                    //获取这个实例实例
-
-
-                                    Console.WriteLine();
-                                }
+                                OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 移除配置实例成功"));
+                            }
+                            else
+                            {
+                                OnEventHandler?.Invoke(this, new EventResult(false, $"{e.Name} 移除配置实例失败"));
                             }
-
-
-
-
                         }
-
-
-                        //文件夹监视
-                        FileSystemWatcher watcher = new FileSystemWatcher(basics.LibFolder);
-                        //启动监听
-                        watcher.EnableRaisingEvents = true;
-                        //当文件夹中新增文件
-                        watcher.Created += Watcher_Created;
-                        //当文件夹中删除文件
-                        watcher.Deleted += Watcher_Deleted;
-                        //当文件夹中重命名文件
-                        watcher.Renamed += Watcher_Renamed;
-
+                        else
+                        {
+                            OnEventHandler?.Invoke(this, new EventResult(false, $"{e.Name} 移除配置实例失败 {TypeSN} 实例不存在"));
+                        }
                     }
-                    catch (Exception ex)
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// 当文件夹中新增文件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        /// <param name="Type">【0:库文件】【1:配置文件】</param>
+        private void Watcher_Created(object sender, FileSystemEventArgs e, int Type)
+        {
+            switch (Type)
+            {
+                case 0:
+                    OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 文件新增,添加此库程序集"));
+                    SearchType(e.FullPath);
+                    break;
+                case 1:
+                    OnEventHandler?.Invoke(this, new EventResult(true, $"{e.Name} 文件新增,新增对应配置实例"));
+                    #region 新增对应配置实例
+                    int until = 5;
+                    int i = 0;
+                    bool success = false;
+                    while (!success && i < until)
                     {
-                        OnEventHandler?.Invoke(this,new EventResult(false, $"监控异常:{ex.Message}") );
+                        try
+                        {
+                            string path = String.Format(e.FullPath);
+                            string? filename = Path.GetFileName(path);
+                            using (Stream fs = File.OpenRead(@path))
+                            {
+                                StreamReader srdPreview = new StreamReader(fs);
+                                String temp = string.Empty;
+                                while (srdPreview.Peek() > -1)
+                                {
+                                    String input = srdPreview.ReadLine();
+                                    temp += input;
+                                }
+                                srdPreview.Close();
+                                srdPreview.Dispose();
+
+                                //获取程序集SN
+                                string TypeSN = e.Name.Split('-')[0].Replace(".Config", string.Empty);
+                                //分割
+                                string[] strs = e.Name.Split('-');
+                                if (strs.Length > 1)
+                                {
+                                    //获取配置实例SN
+                                    string SN = $"{TypeSN}:{strs[1].Split('.')[0]}";
+                                    //判断是否存在此程序集SN
+                                    if (TypeIoc.ContainsKey(TypeSN))
+                                    {
+                                        if (!InstanceIoc.ContainsKey(SN))
+                                        {
+                                            ConfigCreateInstance(TypeIoc[TypeSN], temp);
+                                        }
+                                        else
+                                        {
+                                            OnEventHandler?.Invoke(this, new EventResult(false, $" {e.Name} 此配置实例已存在"));
+                                        }
+                                    }
+                                    else
+                                    {
+                                        OnEventHandler?.Invoke(this, new EventResult(false, $" {e.Name} 新增对应配置创建实例失败 {TypeSN} 程序集不存在"));
+                                    }
+                                }
+                                fs.Close();
+                                fs.Dispose();
+                            }
+                            success = true;
+                        }
+                        catch
+                        {
+                            i++;
+                            Thread.Sleep(TimeSpan.FromSeconds(1));
+                        }
                     }
-                    Thread.Sleep(basics.MonitorInterval);
-                }
-            });
+                    #endregion
+                    break;
+            }
         }
 
+        /// <summary>
+        /// 检索文件并创建实例
+        /// </summary>
+        private void Search()
+        {
+            try
+            {
+                //库
+                List<string> libs = Directory.GetFiles(basics.LibFolder, "*.dll", SearchOption.AllDirectories).ToList();
+                //循环文件,添加程序集
+                foreach (var lib in libs)
+                {
+                    SearchType(lib);
+                }
+                //获取配置
+                foreach (var type in TypeIoc)
+                {
+                    TypeSearchConfig(type.Value);
+                }
+            }
+            catch (Exception ex)
+            {
+                OnEventHandler?.Invoke(this, new EventResult(false, $"检索异常:{ex.Message}"));
+            }
+        }
 
+        /// <summary>
+        /// 通过DLL检索程序集
+        /// </summary>
+        /// <param name="lib">库文件</param>
+        private void SearchType(string lib)
+        {
+            //加载程序集
+            Assembly assembly = Assembly.LoadFrom(lib);
+            //获取所有类
+            Type[] types = assembly.GetExportedTypes();
+            //过滤器
+            TypeFilter typeFilter = new TypeFilter(InterfaceFilter);
+            //集合
+            List<Type> typesArray = new List<Type>();
+            //检索类是否继承接口
+            foreach (Type type in types)
+            {
+                if (type.FindInterfaces(typeFilter, basics.InterfaceFullName).Count() > 0)
+                {
+                    typesArray.Add(type);
+                }
+            }
+            //添加至集合
+            foreach (Type type in typesArray)
+            {
+                TypeIoc.TryAdd(type.FullName, type);
+                //抛出信息
+                OnEventHandler?.Invoke(this, new EventResult(true, $"{type.FullName} 程序集添加成功"));
+            }
+        }
+        /// <summary>
+        /// 通过程序集检索配置
+        /// </summary>
+        /// <param name="type">程序集</param>
+        private void TypeSearchConfig(Type type)
+        {
+            //组织配置文件
+            string configFile = string.Format(basics.ConfigFileNameFormat, type.FullName);
+            //目录信息
+            DirectoryInfo directoryInfo = new DirectoryInfo(basics.LibConfigFolder);
+            //文件检索得到文件信息
+            List<FileInfo> fieldInfos = directoryInfo.GetFiles(configFile, SearchOption.AllDirectories).ToList();
+            //如果文件信息为空则不创建实例
+            if (fieldInfos.Count > 0)
+            {
+                //循环检索配置文件信息
+                foreach (FileInfo fi in fieldInfos)
+                {
+                    ConfigCreateInstance(type, FileTool.FileToString(fi.FullName));
+                }
+            }
+        }
+        /// <summary>
+        /// 通过配置创建实例
+        /// </summary>
+        /// <param name="type">程序集</param>
+        /// <param name="content">内容</param>
+        private void ConfigCreateInstance(Type type, string content)
+        {
+            //获取结构参数
+            JObject? jsonObject = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject>(content);
+            //获取唯一标识符
+            string SN = $"{type.FullName}:{jsonObject[basics.LibConfigSNKey]}";
+            //获取实例
+            IDaq? instance = CreateInstance(type, new object[] { jsonObject }) as IDaq;
+            //实例不为空
+            if (instance != null)
+            {
+                //把这个实例添加到容器中
+                InstanceIoc.TryAdd(SN, instance);
+                //事件注册
+                instance.OnEvent += Instance_OnEvent;
+                //抛出信息
+                OnEventHandler?.Invoke(this, new EventResult(true, $"{SN} 实例创建成功"));
+            }
+            else
+            {
+                //抛出信息
+                OnEventHandler?.Invoke(this, new EventResult(false, $"{SN} 实例创建失败"));
+            }
+        }
+        /// <summary>
+        /// 实例事件信息
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        /// <exception cref="NotImplementedException"></exception>
+        private void Instance_OnEvent(object? sender, EventResult e)
+        {
+            //抛出信息
+            OnEventHandler?.Invoke(this, e);
+        }
         /// <summary>
         /// 创建实例
         /// </summary>
@@ -291,9 +541,6 @@ namespace YSAI.DaqManage
             return null;
         }
 
-
-
-
         /// <summary>
         /// 接口过滤器
         /// </summary>
@@ -304,103 +551,305 @@ namespace YSAI.DaqManage
             else
                 return false;
         }
-
+      
         /// <summary>
-        /// 当文件夹中重命名文件
+        /// 这是释放所有包含自身对象
         /// </summary>
-        /// <param name="sender"></param>
-        /// <param name="e"></param>
-        /// <exception cref="NotImplementedException"></exception>
-        private void Watcher_Renamed(object sender, RenamedEventArgs e)
+        public void Dispose()
         {
+            //容器实例释放
+            foreach (var item in InstanceIoc) { item.Value.Dispose(); }
+            //清空
+            InstanceIoc.Clear();
+            InstanceIoc = null;
+            TypeIoc.Clear();
+            TypeIoc = null;
 
+            GC.Collect();
+            GC.SuppressFinalize(this);
+            ThisObjList = null;
         }
+
         /// <summary>
-        /// 当文件夹中删除文件
+        /// 释放
         /// </summary>
-        /// <param name="sender"></param>
-        /// <param name="e"></param>
-        /// <exception cref="NotImplementedException"></exception>
-        private void Watcher_Deleted(object sender, FileSystemEventArgs e)
+        /// <param name="SN">实例的唯一标识符</param>
+        public OperateResult Dispose(string SN)
         {
-
+            Depart("Dispose");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    InstanceIoc[SN].Dispose();
+                    return Break("Dispose", true);
+                }
+                else
+                {
+                    return Break("Dispose", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("Dispose", false,ex.Message);
+            }
         }
         /// <summary>
-        /// 当文件夹中新增文件
+        /// 释放
         /// </summary>
-        /// <param name="sender"></param>
-        /// <param name="e"></param>
-        /// <exception cref="NotImplementedException"></exception>
-        private void Watcher_Created(object sender, FileSystemEventArgs e)
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> DisposeAsync(string SN)
         {
-
+            return Task.Run(() => Dispose(SN));
         }
-
-        public void Dispose()
+        /// <summary>
+        /// 移除实例
+        /// </summary>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult Remove(string SN)
         {
-            GC.Collect();
-            GC.SuppressFinalize(this);
-            ThisObjList= null;
+            Depart("Remove");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    if (InstanceIoc.Remove(SN, out _))
+                    {
+                        return Break("Remove", true);
+                    }
+                    else
+                    {
+                        return Break("Remove", false, $"{SN} 的实例移除失败");
+                    }
+                }
+                else
+                {
+                    return Break("Remove", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("Remove", false, ex.Message);
+            }
         }
-
-        public Task<OperateResult> ReadAsync(Address address)
+        /// <summary>
+        /// 移除实例
+        /// </summary>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> RemoveAsync(string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => Remove(SN));
         }
-
-        public OperateResult Read(Address address)
+        /// <summary>
+        /// 读取
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> ReadAsync(Address address,string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => Read(address, SN));
         }
-
-        public Task<OperateResult> WriteAsync<V>(ConcurrentDictionary<string, V> Values)
+        /// <summary>
+        /// 读取
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult Read(Address address, string SN)
         {
-            throw new NotImplementedException();
+            Depart("Read");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    return InstanceIoc[SN].Read(address);
+                }
+                else
+                {
+                    return Break("Read", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("Read", false, ex.Message);
+            }
         }
-
-        public OperateResult Write<V>(ConcurrentDictionary<string, V> Values)
+        /// <summary>
+        /// 写入
+        /// </summary>
+        /// <typeparam name="V">值类型</typeparam>
+        /// <param name="Values">数据</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> WriteAsync<V>(ConcurrentDictionary<string, V> Values, string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => Write(Values, SN));
         }
-
-        public OperateResult Subscribe(Address address)
+        /// <summary>
+        /// 写入
+        /// </summary>
+        /// <typeparam name="V">值类型</typeparam>
+        /// <param name="Values">数据</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult Write<V>(ConcurrentDictionary<string, V> Values, string SN)
         {
-            throw new NotImplementedException();
+            Depart("Write");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    return InstanceIoc[SN].Write(Values);
+                }
+                else
+                {
+                    return Break("Write", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("Write", false, ex.Message);
+            }
         }
-
-        public Task<OperateResult> SubscribeAsync(Address address)
+        /// <summary>
+        /// 订阅
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult Subscribe(Address address, string SN)
         {
-            throw new NotImplementedException();
+            Depart("Subscribe");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    return InstanceIoc[SN].Subscribe(address);
+                }
+                else
+                {
+                    return Break("Subscribe", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("Subscribe", false, ex.Message);
+            }
         }
-
-        public OperateResult UnSubscribe(Address address)
+        /// <summary>
+        /// 订阅
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> SubscribeAsync(Address address, string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => Subscribe(address, SN));
         }
-
-        public Task<OperateResult> UnSubscribeAsync(Address address)
+        /// <summary>
+        /// 取消订阅
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult UnSubscribe(Address address, string SN)
         {
-            throw new NotImplementedException();
+            Depart("UnSubscribe");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    return InstanceIoc[SN].UnSubscribe(address);
+                }
+                else
+                {
+                    return Break("UnSubscribe", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("UnSubscribe", false, ex.Message);
+            }
         }
-
-        public Task<OperateResult> OnAsync()
+        /// <summary>
+        /// 取消订阅
+        /// </summary>
+        /// <param name="address">地址</param>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> UnSubscribeAsync(Address address, string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => UnSubscribe(address, SN));
         }
-
-        public OperateResult On()
+        /// <summary>
+        /// 打开
+        /// </summary>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> OnAsync(string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => On(SN));
         }
-
-        public Task<OperateResult> OffAsync()
+        /// <summary>
+        /// 打开
+        /// </summary>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult On(string SN)
+        {
+            Depart("On");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    return InstanceIoc[SN].On();
+                }
+                else
+                {
+                    return Break("On", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("On", false, ex.Message);
+            }
+        }
+        /// <summary>
+        /// 关闭
+        /// </summary>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public Task<OperateResult> OffAsync(string SN)
         {
-            throw new NotImplementedException();
+            return Task.Run(() => Off(SN));
         }
-
-        public OperateResult Off()
+        /// <summary>
+        /// 关闭
+        /// </summary>
+        /// <param name="SN">实例的唯一标识符</param>
+        /// <returns>统一出参</returns>
+        public OperateResult Off(string SN)
         {
-            throw new NotImplementedException();
+            Depart("Off");
+            try
+            {
+                if (InstanceIoc.ContainsKey(SN))
+                {
+                    return InstanceIoc[SN].Off();
+                }
+                else
+                {
+                    return Break("Off", false, $"未找到 {SN} 的实例");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break("Off", false, ex.Message);
+            }
         }
     }
 }

+ 1 - 1
src/YSAI.DAQ/YSAI.DaqManage/YSAI.DaqManage.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
   </PropertyGroup>
-
+	
   <ItemGroup>
     <ProjectReference Include="..\YSAI.Core\YSAI.Core.csproj" />
   </ItemGroup>

+ 8 - 3
src/YSAI.DAQ/YSAI.Opc/da/client/OpcDaClientOperate.cs

@@ -241,7 +241,7 @@ namespace YSAI.Opc.da.client
                     if (!SubscriptionArray.ContainsKey(GroupName))
                     {
                         SubscriptionState subscriptionState = new SubscriptionState();
-                        subscriptionState.KeepAlive = 1000;
+                        subscriptionState.KeepAlive = int.MaxValue;
                         subscriptionState.Deadband = 0;
                         subscriptionState.Active = true;
                         subscriptionState.UpdateRate =basics.UpdateRate;
@@ -288,6 +288,11 @@ namespace YSAI.Opc.da.client
                     string GN = string.Empty;
                     if (string.IsNullOrEmpty(GroupName))
                     {
+                        //需要订阅
+                        if (SubscriptionArray == null)
+                        {
+                            SubscriptionArray = new ConcurrentDictionary<string, Tuple<ISubscription, List<ItemResult>>>();
+                        }
                         //先判断是否有此组,不存在则创建默认组
                         if (!SubscriptionArray.ContainsKey(DefaultGroupName))
                         {
@@ -322,14 +327,14 @@ namespace YSAI.Opc.da.client
                                     {
                                         items.Add(new Item() { ItemName = item.AddressName });
                                         ItemState = true;
-                                        AddAddressData(GroupName, item);
+                                        AddAddressData(GN, item);
                                     }
                                 }
                                 else
                                 {
                                     items.Add(new Item() { ItemName = item.AddressName });
                                     ItemState = true;
-                                    AddAddressData(GroupName, item);
+                                    AddAddressData(GN, item);
                                 }
                             }
                         }

+ 121 - 5
src/YSAI.DAQ/YSAI.TestConsole/Program.cs

@@ -37,22 +37,138 @@ namespace YSAI.TestConsole
         static void Main(string[] args)
         {
             DaqManageOperate daqManageOperate = DaqManageOperate.Instance();
+            daqManageOperate.OnEvent += DaqManageOperate_OnEvent;
 
+            Thread.Sleep(1000);
 
+         
 
 
+            while (true)
+            {
+                Console.ReadLine();
+                //打开连接
+                OperateResult operateResult = daqManageOperate.On($"YSAI.Opc.da.client.OpcDaClientOperate:OPCDA1");
+                Console.WriteLine(operateResult.Message);
 
+                operateResult = daqManageOperate.On($"YSAI.Opc.da.client.OpcDaClientOperate:OPCDA2");
+                Console.WriteLine(operateResult.Message);
 
+                //添加订阅
+                Address address = new Address();
+                address.AddressArray = new List<AddressDetails>()
+            {
+                new AddressDetails()
+                {
+                    AddressName = "a.a.a",
+                    AddressDataType = Core.@enum.DataType.Bool,
+                    AddressDescribe = "一个动态的布尔类型",
+                    AddressAnotherName = "test",
+                    AddressPropertyName = "aaa",
+                    AddressType = Core.@enum.AddressType.Reality
+                },
+                new AddressDetails()
+                {
+                    AddressName = "a.a.h",
+                    AddressDataType = Core.@enum.DataType.String,
+                    AddressDescribe = "一个动态的字符串类型",
+                    AddressAnotherName = "test",
+                    AddressPropertyName = "aah",
+                    AddressType = Core.@enum.AddressType.Reality,
+                    AddressParseParam = new AddressParse()
+                    {
+                        ParseType = Core.@enum.ParseType.ScriptAnalysis,
+                        Script = new Core.script.ScriptData.Basics()
+                        {
+                            ScriptCode = @"function Convert(value) 
+                                            {
+                                                return '这是脚本测试,传入的参数是:' + value;
+                                            }",
+                            ScriptFunction = "Convert",
+                            ScriptType = Core.script.ScriptData.ScriptType.JavaScript
+                        }
+                    }
+                },
+                new AddressDetails()
+                 {
+                     AddressName = "a.a.g",
+                     AddressDataType = Core.@enum.DataType.Double,
+                     AddressDescribe = "一个动态的浮点类型",
+                     AddressAnotherName = "test",
+                     AddressPropertyName = "aag",
+                     AddressType = Core.@enum.AddressType.Reality,
+                     AddressParseParam = new AddressParse()
+                     {
+                         ParseType = Core.@enum.ParseType.ScriptAnalysis,
+                         Script = new Core.script.ScriptData.Basics()
+                         {
+                             ScriptCode = @"function Convert(value) 
+                                            {
+                                                return value*1000;
+                                            }",
+                             ScriptFunction = "Convert",
+                             ScriptType = Core.script.ScriptData.ScriptType.JavaScript
+                         }
+                     }
+                 },
+                new AddressDetails()
+                 {
+                     AddressName = "OPCDA_VirtualAddress",
+                     AddressDataType = Core.@enum.DataType.String,
+                     AddressDescribe = "虚拟地址",
+                     AddressAnotherName = "test",
+                     AddressPropertyName = "OPCDA_VirtualAddress",
+                     AddressType = Core.@enum.AddressType.Virtual
+                 },
+                new AddressDetails()
+                  {
+                      AddressName = "OPCDA_VirtualDynamicAddress",
+                      AddressDataType = Core.@enum.DataType.String,
+                      AddressDescribe = "虚拟动态地址",
+                      AddressAnotherName = "test",
+                      AddressPropertyName = "OPCDA_VirtualDynamicAddress",
+                      AddressType = Core.@enum.AddressType.VirtualDynamic
+                  }
+            };
+                operateResult = daqManageOperate.Subscribe(address, $"YSAI.Opc.da.client.OpcDaClientOperate:OPCDA1");
+                Console.WriteLine(operateResult.Message);
 
-            Console.WriteLine();
 
-            while (true)
-            {
-                Console.ReadKey();
+                operateResult = daqManageOperate.Subscribe(address, $"YSAI.Opc.da.client.OpcDaClientOperate:OPCDA2");
+                Console.WriteLine(operateResult.Message);
             }
         }
 
-       
+        private static void DaqManageOperate_OnEvent(object? sender, EventResult e)
+        {
+            Console.WriteLine(e.Message);
+            switch (e.RType)
+            {
+                case ResultType.KeyValue:
+                    ConcurrentDictionary<string, AddressValue> pairs = e.RData as ConcurrentDictionary<string, AddressValue>;
+                    foreach (var item in pairs)
+                    {
+                        Console.WriteLine($"{item.Key} - {item.Value.Value}");
+                    }
+                    break;
+                case ResultType.KeyValueArray:
+                    break;
+                case ResultType.Json:
+                    break;
+                case ResultType.Bytes:
+                    break;
+                case ResultType.String:
+                    break;
+                case ResultType.Dynamic:
+                    break;
+                case ResultType.OperateResult:
+                    break;
+                case ResultType.Enum:
+                    break;
+                case ResultType.NULL:
+                    break;
+            }
+        }
     }
 
 

+ 1 - 0
src/YSAI.DAQ/YSAI.TestConsole/YSAI.TestConsole.csproj

@@ -5,6 +5,7 @@
     <TargetFramework>net6.0</TargetFramework>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
+    <PlatformTarget>x86</PlatformTarget>
   </PropertyGroup>
 
   <ItemGroup>

+ 4 - 2
src/YSAI.DAQ/YSAI.Unility/FileTool.cs

@@ -103,15 +103,17 @@ namespace YSAI.Unility
                         ms.Write(buffer, 0, positon);
                     }
                     allBytes = ms.ToArray();
+                    fs.Close();
+                    fs.Dispose();
                 }
-
+                ms.Close();
+                ms.Dispose();
             }
             stopwatch.Stop();
             if (null != allBytes)
             {
                 //尝试将字节转成字符串
                 txt = System.Text.Encoding.UTF8.GetString(allBytes);
-
             }
             return txt;
         }