NewLife/XCoder

升级基础组件
大石头 authored at 2022-09-01 15:53:48
94b36e0
Tree
1 Parent(s) 0d6f4f6
Summary: 13 changed files with 354 additions and 23 deletions.
Added +185 -0
Modified +11 -7
Modified +3 -3
Modified +1 -1
Modified +2 -2
Modified +2 -2
Modified +2 -2
Modified +2 -2
Modified +1 -1
Modified +1 -1
Added +142 -0
Modified +1 -1
Modified +1 -1
Added +185 -0
diff --git a/XCoder/Common/SpeechRecognition.cs b/XCoder/Common/SpeechRecognition.cs
new file mode 100644
index 0000000..45bc25e
--- /dev/null
+++ b/XCoder/Common/SpeechRecognition.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using NewLife.IO;
+using NewLife.Log;
+using NewLife.Model;
+using NewLife.Reflection;
+
+namespace NewLife.Windows
+{
+    /// <summary>语音识别</summary>
+    public class SpeechRecognition : DisposeBase
+    {
+        #region 属性
+        private ISpeech _speech;
+
+        private readonly IDictionary<String, Action> _dic;
+
+        /// <summary>系统名称。用于引导前缀</summary>
+        public String Name { get; set; } = "丁丁";
+
+        /// <summary>最后一次进入引导前缀的时间。</summary>
+        private DateTime _Tip;
+
+        /// <summary>是否可用</summary>
+        public Boolean Enable => _speech != null;
+        #endregion
+
+        #region 构造
+        private SpeechRecognition()
+        {
+            _dic = new Dictionary<String, Action>();
+        }
+
+        /// <summary>销毁</summary>
+        /// <param name="disposing"></param>
+        protected override void Dispose(Boolean disposing)
+        {
+            base.Dispose(disposing);
+
+            _speech.TryDispose();
+        }
+        #endregion
+
+        #region 静态
+        /// <summary>当前实例</summary>
+        public static SpeechRecognition Current { get; } = new SpeechRecognition();
+
+        /// <summary>获取已注册的所有键值</summary>
+        /// <returns></returns>
+        public String[] GetAllKeys() => _dic.Keys.ToArray();
+        #endregion
+
+        #region 方法
+        Boolean Init()
+        {
+            if (_speech != null) return true;
+
+            _speech = ObjectContainer.Current.Resolve<ISpeech>();
+            if (_speech != null) return true;
+
+            try
+            {
+                Assembly.Load("System.Speech, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
+
+                var code = Assembly.GetExecutingAssembly().GetFileResource("MySpeech.cs").ToStr();
+                var sc = ScriptEngine.Create(code, false);
+                sc.Compile();
+
+                _speech = sc.Type.CreateInstance() as ISpeech;
+                if (_speech == null) return false;
+
+                if (!_speech.Init()) return false;
+
+                _speech.SpeechRecognized += _rg_SpeechRecognized;
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                XTrace.WriteException(ex);
+                _speech.TryDispose();
+                return false;
+            }
+        }
+
+        /// <summary>注册要语音识别的关键字到委托</summary>
+        /// <param name="text"></param>
+        /// <param name="callback"></param>
+        public SpeechRecognition Register(String text, Action callback)
+        {
+            var flag = _dic.ContainsKey(text);
+
+            if (callback != null)
+            {
+                _dic[text] = callback;
+
+                if (!flag) Change();
+            }
+            else if (flag)
+                _dic.Remove(text);
+
+            return this;
+        }
+
+        void Change()
+        {
+            if (_speech == null) return;
+
+            lock (this)
+            {
+                if (!Init()) return;
+
+                var list = new List<String>
+                {
+                    Name
+                };
+                list.AddRange(_dic.Keys);
+                _speech.SetChoices(list);
+            }
+        }
+
+        //void _rg_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
+        void _rg_SpeechRecognized(Object sender, RecognitionEventArgs e)
+        {
+            var conf = e.Confidence;
+            if (conf < 0.5) return;
+
+            var txt = e.Text;
+
+            // 语音识别前,必须先识别前缀名称,然后几秒内识别关键字
+            if (_Tip.AddSeconds(3) < DateTime.Now)
+            {
+                // 此时只识别前缀
+                if (txt != Name) return;
+
+                XTrace.WriteLine("语音识别:{0} {1}", txt, conf);
+
+                // 现在可以开始识别关键字啦
+                _Tip = DateTime.Now;
+            }
+            else
+            {
+                XTrace.WriteLine("语音识别:{0} {1}", txt, conf);
+
+                if (_dic.TryGetValue(txt, out var func)) func();
+            }
+        }
+        #endregion
+    }
+
+    /// <summary>语音接口</summary>
+    public interface ISpeech
+    {
+        /// <summary>语音识别事件</summary>
+        event EventHandler<RecognitionEventArgs> SpeechRecognized;
+
+        /// <summary>初始化</summary>
+        /// <returns></returns>
+        Boolean Init();
+
+        /// <summary>设置识别短语</summary>
+        /// <param name="phrases"></param>
+        void SetChoices(IEnumerable<String> phrases);
+    }
+
+    /// <summary>识别事件参数</summary>
+    public class RecognitionEventArgs : EventArgs
+    {
+        /// <summary>获取识别器分配的值,此值表示与给定输入匹配的可能性</summary>
+        public Single Confidence { get; }
+
+        /// <summary>获取语音识别器从识别的输入生成的规范化文本</summary>
+        public String Text { get; }
+
+        /// <summary>实例化</summary>
+        /// <param name="conf"></param>
+        /// <param name="text"></param>
+        public RecognitionEventArgs(Single conf, String text)
+        {
+            Confidence = conf;
+            Text = text;
+        }
+    }
+}
\ No newline at end of file
Modified +11 -7
diff --git a/XCoder/CrazyCoder.csproj b/XCoder/CrazyCoder.csproj
index 6336bab..0dea2f4 100644
--- a/XCoder/CrazyCoder.csproj
+++ b/XCoder/CrazyCoder.csproj
@@ -24,8 +24,11 @@
     <ApplicationManifest>Properties\app.manifest</ApplicationManifest>
   </PropertyGroup>
   <ItemGroup>
+    <Compile Remove="FileEncoding\**" />
     <Compile Remove="Protocols\**" />
+    <EmbeddedResource Remove="FileEncoding\**" />
     <EmbeddedResource Remove="Protocols\**" />
+    <None Remove="FileEncoding\**" />
     <None Remove="Protocols\**" />
   </ItemGroup>
   <ItemGroup>
@@ -63,27 +66,28 @@
     <Content Include="数据库命名规范.txt" />
   </ItemGroup>
   <ItemGroup>
-    <PackageReference Include="NewLife.ModbusRTU" Version="1.1.2022.704" />
+    <PackageReference Include="NewLife.Map" Version="2.0.2022.901" />
+    <PackageReference Include="NewLife.ModbusRTU" Version="1.2.2022.901" />
     <PackageReference Include="System.Speech" Version="6.0.0" />
     <PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
     <PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
     <PackageReference Include="NewLife.Core">
-      <Version>9.2.2022.701</Version>
+      <Version>10.0.2022.901</Version>
     </PackageReference>
     <PackageReference Include="NewLife.MQTT">
-      <Version>1.0.2022.501</Version>
+      <Version>1.1.2022.901</Version>
     </PackageReference>
     <PackageReference Include="NewLife.Net">
-      <Version>4.1.2022.501</Version>
+      <Version>4.2.2022.901</Version>
     </PackageReference>
     <PackageReference Include="NewLife.Redis">
-      <Version>4.1.2022.701</Version>
+      <Version>5.0.2022.901</Version>
     </PackageReference>
     <PackageReference Include="NewLife.Stardust">
-      <Version>2.2.2022.710</Version>
+      <Version>2.3.2022.901</Version>
     </PackageReference>
     <PackageReference Include="NewLife.XCode">
-      <Version>11.2.2022.701</Version>
+      <Version>11.3.2022.901</Version>
     </PackageReference>
     <PackageReference Include="SSH.NET">
       <Version>2020.0.2</Version>
Modified +3 -3
diff --git a/XCoder/Engine/ModelConfig.cs b/XCoder/Engine/ModelConfig.cs
index c490f1e..a12f7c4 100644
--- a/XCoder/Engine/ModelConfig.cs
+++ b/XCoder/Engine/ModelConfig.cs
@@ -121,9 +121,9 @@ namespace XCoder
         [DisplayName("调试")]
         public Boolean Debug { get; set; }
 
-        /// <summary> 字典属性</summary>
-        [DisplayName("数据字典")]
-        public SerializableDictionary<String, String> Items { get; set; } = new SerializableDictionary<String, String>();
+        ///// <summary> 字典属性</summary>
+        //[DisplayName("数据字典")]
+        //public SerializableDictionary<String, String> Items { get; set; } = new SerializableDictionary<String, String>();
         #endregion
 
         #region 加载/保存
Modified +1 -1
diff --git a/XCoder/FolderInfo/FrmMain.cs b/XCoder/FolderInfo/FrmMain.cs
index ed9e9c5..428ab28 100644
--- a/XCoder/FolderInfo/FrmMain.cs
+++ b/XCoder/FolderInfo/FrmMain.cs
@@ -94,7 +94,7 @@ namespace XCoder.FolderInfo
                 {
                     tn.Nodes.Add("no");
                     //使用后台线程统计大小信息
-                    ThreadPoolX.QueueUserWorkItem(() => TongJi(tn));
+                    ThreadPool.QueueUserWorkItem(s => TongJi(tn));
                 }
             }
         }
Modified +2 -2
diff --git a/XCoder/FrmMDI.cs b/XCoder/FrmMDI.cs
index 88f6d49..aa071de 100644
--- a/XCoder/FrmMDI.cs
+++ b/XCoder/FrmMDI.cs
@@ -43,7 +43,7 @@ namespace XCoder
 
             _load.ContinueWith(t => LoadForms(t.Result));
 
-            ThreadPoolX.QueueUserWorkItem(() => CheckUpdate(true));
+            ThreadPool.QueueUserWorkItem(s => CheckUpdate(true));
         }
 
         void LoadForms(Type[] ts)
@@ -170,7 +170,7 @@ namespace XCoder
         #region 自动更新
         private void 检查更新ToolStripMenuItem_Click(Object sender, EventArgs e)
         {
-            ThreadPoolX.QueueUserWorkItem(() => CheckUpdate(false));
+            ThreadPool.QueueUserWorkItem(s => CheckUpdate(false));
         }
 
         private void CheckUpdate(Boolean auto)
Modified +2 -2
diff --git a/XCoder/Windows/FrmMain.cs b/XCoder/Windows/FrmMain.cs
index 9e13ded..988c627 100644
--- a/XCoder/Windows/FrmMain.cs
+++ b/XCoder/Windows/FrmMain.cs
@@ -222,7 +222,7 @@ namespace XCoder
             if (!DAL.ConnStrs.TryGetValue(name, out var connstr) || connstr.IsNullOrWhiteSpace()) return;
 
             // 异步加载
-            ThreadPoolX.QueueUserWorkItem(() => { var tables = DAL.Create(name).Tables; });
+            ThreadPool.QueueUserWorkItem(s => { var tables = DAL.Create(name).Tables; });
         }
 
         private void btnRefreshTable_Click(Object sender, EventArgs e)
@@ -399,7 +399,7 @@ namespace XCoder
 
         private void oracle客户端运行时检查ToolStripMenuItem1_Click(Object sender, EventArgs e)
         {
-            ThreadPoolX.QueueUserWorkItem(CheckOracle);
+            ThreadPool.QueueUserWorkItem(s => CheckOracle());
         }
         void CheckOracle()
         {
Modified +2 -2
diff --git a/XCoder/Windows/FrmQuery.cs b/XCoder/Windows/FrmQuery.cs
index 75f483b..c8b5ff2 100644
--- a/XCoder/Windows/FrmQuery.cs
+++ b/XCoder/Windows/FrmQuery.cs
@@ -46,7 +46,7 @@ namespace XCoder
             var sql = txtSQL.Text;
             if (sql.IsNullOrWhiteSpace()) return;
 
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 var sw = Stopwatch.StartNew();
 
@@ -80,7 +80,7 @@ namespace XCoder
             var sql = txtSQL.Text;
             if (sql.IsNullOrWhiteSpace()) return;
 
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 var sw = Stopwatch.StartNew();
 
Modified +2 -2
diff --git a/XCoder/Windows/FrmSchema.cs b/XCoder/Windows/FrmSchema.cs
index 9fb4b21..dfb9ff0 100644
--- a/XCoder/Windows/FrmSchema.cs
+++ b/XCoder/Windows/FrmSchema.cs
@@ -42,12 +42,12 @@ namespace XCoder
 
         private void FrmSchema_Load(Object sender, EventArgs e)
         {
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 var tables = Db.CreateMetaData().GetTables();
                 Invoke(SetList, cbTables, tables);
             });
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 var list = Db.CreateMetaData().MetaDataCollections;
                 Invoke(SetList, cbSchemas, list);
Modified +1 -1
diff --git a/XCoder/XApi/FrmMain.cs b/XCoder/XApi/FrmMain.cs
index f70a96b..74ddebc 100644
--- a/XCoder/XApi/FrmMain.cs
+++ b/XCoder/XApi/FrmMain.cs
@@ -71,7 +71,7 @@ namespace XApi
             LoadConfig();
 
             // 语音识别
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 var sp = SpeechRecognition.Current;
                 if (!sp.Enable) return;
Modified +1 -1
diff --git a/XCoder/XCom/FrmMain.cs b/XCoder/XCom/FrmMain.cs
index 6b00356..b835d57 100644
--- a/XCoder/XCom/FrmMain.cs
+++ b/XCoder/XCom/FrmMain.cs
@@ -184,7 +184,7 @@ namespace XCom
                 return;
             }
 
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 for (var i = 0; i < count; i++)
                 {
Added +142 -0
diff --git a/XCoder/XICO/FileSource.cs b/XCoder/XICO/FileSource.cs
new file mode 100644
index 0000000..95673c1
--- /dev/null
+++ b/XCoder/XICO/FileSource.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Web;
+
+namespace NewLife.IO
+{
+    /// <summary>文件资源</summary>
+    public static class FileSource
+    {
+        /// <summary>释放文件</summary>
+        /// <param name="asm"></param>
+        /// <param name="fileName"></param>
+        /// <param name="destFile"></param>
+        /// <param name="overWrite"></param>
+        public static void ReleaseFile(this Assembly asm, String fileName, String destFile = null, Boolean overWrite = false)
+        {
+            if (fileName.IsNullOrEmpty()) return;
+
+            if (asm == null) asm = Assembly.GetCallingAssembly();
+            var stream = GetFileResource(asm, fileName);
+            if (stream == null) throw new ArgumentException("filename", $"在程序集{asm.GetName().Name}中无法找到名为{fileName}的资源!");
+
+            if (destFile.IsNullOrEmpty()) destFile = fileName;
+            destFile = destFile.GetFullPath();
+
+            if (File.Exists(destFile) && !overWrite) return;
+
+            //var path = Path.GetDirectoryName(dest);
+            //if (!path.IsNullOrWhiteSpace() && !Directory.Exists(path)) Directory.CreateDirectory(path);
+            destFile.EnsureDirectory(true);
+            try
+            {
+                if (File.Exists(destFile)) File.Delete(destFile);
+
+                using var fs = File.Create(destFile);
+                //IOHelper.CopyTo(stream, fs);
+                stream.CopyTo(fs);
+            }
+            catch { }
+            finally { stream.Dispose(); }
+        }
+
+        /// <summary>释放文件夹</summary>
+        /// <param name="asm"></param>
+        /// <param name="prefix"></param>
+        /// <param name="dest"></param>
+        /// <param name="overWrite"></param>
+        public static void ReleaseFolder(this Assembly asm, String prefix, String dest, Boolean overWrite = false)
+        {
+            if (asm == null) asm = Assembly.GetCallingAssembly();
+            ReleaseFolder(asm, prefix, dest, overWrite, null);
+        }
+
+        /// <summary>释放文件夹</summary>
+        /// <param name="asm"></param>
+        /// <param name="prefix"></param>
+        /// <param name="dest"></param>
+        /// <param name="overWrite"></param>
+        /// <param name="filenameResolver"></param>
+        public static void ReleaseFolder(this Assembly asm, String prefix, String dest, Boolean overWrite = false, Func<String, String> filenameResolver = null)
+        {
+            if (asm == null) asm = Assembly.GetCallingAssembly();
+
+            // 找到符合条件的资源
+            var names = asm.GetManifestResourceNames();
+            if (names == null || names.Length <= 0) return;
+            IEnumerable<String> ns = null;
+            if (prefix.IsNullOrWhiteSpace())
+                ns = names.AsEnumerable();
+            else
+                ns = names.Where(e => e.StartsWithIgnoreCase(prefix));
+
+            if (String.IsNullOrEmpty(dest)) dest = ".".GetFullPath();
+            dest = dest.GetFullPath();
+
+            // 开始处理
+            foreach (var item in ns)
+            {
+                var stream = asm.GetManifestResourceStream(item);
+
+                // 计算filename
+                String filename = null;
+                // 去掉前缀
+                if (filenameResolver != null) filename = filenameResolver(item);
+
+                if (String.IsNullOrEmpty(filename))
+                {
+                    filename = item;
+                    if (!String.IsNullOrEmpty(prefix)) filename = filename[prefix.Length..];
+                    if (filename[0] == '.') filename = filename[1..];
+
+                    var ext = Path.GetExtension(item);
+                    filename = filename[..^ext.Length];
+                    filename = filename.Replace(".", @"\") + ext;
+                    filename = Path.Combine(dest, filename);
+                }
+
+                if (File.Exists(filename) && !overWrite) return;
+
+                //var path = Path.GetDirectoryName(filename);
+                //if (!path.IsNullOrWhiteSpace() && !Directory.Exists(path)) Directory.CreateDirectory(path);
+                filename.EnsureDirectory(true);
+                try
+                {
+                    if (File.Exists(filename)) File.Delete(filename);
+
+                    using var fs = File.Create(filename);
+                    //IOHelper.CopyTo(stream, fs);
+                    stream.CopyTo(fs);
+                }
+                catch { }
+                finally { stream.Dispose(); }
+            }
+        }
+
+        /// <summary>获取文件资源</summary>
+        /// <param name="asm"></param>
+        /// <param name="filename"></param>
+        /// <returns></returns>
+        public static Stream GetFileResource(this Assembly asm, String filename)
+        {
+            if (String.IsNullOrEmpty(filename)) return null;
+
+            var name = String.Empty;
+            if (asm == null) asm = Assembly.GetCallingAssembly();
+            var ss = asm.GetManifestResourceNames();
+            if (ss != null && ss.Length > 0)
+            {
+                //找到资源名
+                name = ss.FirstOrDefault(e => e == filename);
+                if (String.IsNullOrEmpty(name)) name = ss.FirstOrDefault(e => e.EqualIgnoreCase(filename));
+                if (String.IsNullOrEmpty(name)) name = ss.FirstOrDefault(e => e.EndsWith(filename));
+
+                if (!String.IsNullOrEmpty(name)) return asm.GetManifestResourceStream(name);
+            }
+            return null;
+        }
+    }
+}
\ No newline at end of file
Modified +1 -1
diff --git a/XCoder/XNet/FrmMain.cs b/XCoder/XNet/FrmMain.cs
index 7b1d642..ee61214 100644
--- a/XCoder/XNet/FrmMain.cs
+++ b/XCoder/XNet/FrmMain.cs
@@ -88,7 +88,7 @@ namespace XNet
             LoadConfig();
 
             // 语音识别
-            ThreadPoolX.QueueUserWorkItem(() =>
+            ThreadPool.QueueUserWorkItem(s =>
             {
                 var sp = SpeechRecognition.Current;
                 if (!sp.Enable) return;
Modified +1 -1
diff --git a/XCoder/XNet/FrmMqtt.cs b/XCoder/XNet/FrmMqtt.cs
index 3073588..4c0872d 100644
--- a/XCoder/XNet/FrmMqtt.cs
+++ b/XCoder/XNet/FrmMqtt.cs
@@ -68,7 +68,7 @@ namespace XNet
                 Password = txtPass.Text,
 
                 Log = _log,
-                LogMessage = true,
+                //LogMessage = true,
             };
             client.Received += Client_Received;
             client.Connected += (s, e) => XTrace.WriteLine("连接成功");