Quellcode durchsuchen

修正 WeakReference 物件造成的模組實體被回收問題

0x0001F36D vor 5 Jahren
Ursprung
Commit
55419880be

+ 1 - 0
Yuuna.sln

@@ -18,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 		.gitignore = .gitignore
 		doc\plugins.md = doc\plugins.md
 		readme.md = readme.md
+		doc\todo.md = doc\todo.md
 	EndProjectSection
 EndProject
 Global

+ 1 - 0
doc/plugins.md

@@ -29,6 +29,7 @@
 1. 在模組中定義你需要做為設定的屬性,並在上面加上 ```[Field]``` 標籤且 **屬性不可以為自動屬性**。
 2. 透過 ```BuildPatterns``` 中的參數 ```config``` 存取你需要的屬性,並會在值不同時自動更新值到設定檔中。
 ```csharp
+// 範例
 [Field()]
 public string Example { get; set; }
 [Field("alias")]

+ 20 - 0
doc/todo.md

@@ -0,0 +1,20 @@
+# 願望清單
+> 以下大部分功能都需要個人用戶的帳號、密碼及 API (大部分都是逆向工程出來的版本)
+- Telegram 訊息、語音通話支援
+    > 目前研究是 訊息 部分可以整合,語音通話部分還沒找到 API。
+- Line 訊息、語音通話支援
+    > Line 的非官方(透過逆向工程得到) API 在使用上非常非常難開發,
+    > 有大量文件及我個人及前輩測試發現很容易有封鎖的可能,
+    > 尤其是語音通話這部分。
+- IoT 控制
+    > 以前開發過,這部分問題比較少。
+- Spotify
+    > 以前開發過,問題可能會比較少。
+- Uber Eats 訂餐
+    > 還沒研究,原本想串 Food Panda 不過沒有找到逆向出來的 API 能參考,Uber Eats 是已經有找到相對應的非官方 API 了。
+- 備忘錄
+    >  Any.do (無官方API)。
+- Trello
+    > 上面大部分跑過後才會考慮加入這部分的整合功能。
+- Uber
+    > 上面大部分跑過後才會考慮加入這部分的整合功能。

+ 0 - 21
readme.md

@@ -1,22 +1 @@
 # Yuuna
-
-## 功能整合願望清單
-> 以下大部分功能都需要個人用戶的帳號、密碼及 API (大部分都是逆向工程出來的版本)
-- Telegram 訊息、語音通話支援
-    > 目前研究是 訊息 部分可以整合,語音通話部分還沒找到 API。
-- Line 訊息、語音通話支援
-    > Line 的非官方(透過逆向工程得到) API 在使用上非常非常難開發,
-    > 有大量文件及我個人及前輩測試發現很容易有封鎖的可能,
-    > 尤其是語音通話這部分。
-- IoT 控制
-    > 以前開發過,這部分問題比較少。
-- Spotify
-    > 以前開發過,問題可能會比較少。
-- Uber Eats 訂餐
-    > 還沒研究,原本想串 Food Panda 不過沒有找到逆向出來的 API 能參考,Uber Eats 是已經有找到相對應的非官方 API 了。
-- 備忘錄
-    >  Any.do (無官方API)。
-- Trello
-    > 上面大部分跑過後才會考慮加入這部分的整合功能。
-- Uber
-    > 上面大部分跑過後才會考慮加入這部分的整合功能。

+ 0 - 12
src/Yuuna.Common/Logging/IHistorian.cs

@@ -1,12 +0,0 @@
-// Author: Orlys
-// Github: https://github.com/Orlys
-
-namespace Yuuna.Common.Logging
-{
-    /// <summary>
-    /// 用來記錄資訊及錯誤的歷史學家。
-    /// </summary>
-    public interface IHistorian
-    {
-    }
-}

+ 5 - 2
src/Yuuna.Contracts.Test/Fake.cs

@@ -11,6 +11,7 @@ namespace Yuuna.Contracts.Test
     using Yuuna.Contracts.Semantics;
     using Yuuna.Common.Utilities;
     using System.Diagnostics;
+    using Yuuna.Common.Configuration;
 
     public sealed class Fake : ModuleBase
     {
@@ -25,13 +26,15 @@ namespace Yuuna.Contracts.Test
             Debug.WriteLine("燈的狀態是: " + (this._lightState ? "開著的" : "關著的"));
         }
 
-        protected override void BuildPatterns(IGroupManager g, IPatternBuilder p)
+        
+
+        protected override void BuildPatterns(IGroupManager g, IPatternBuilder p, dynamic c)
         {
             g.Define("open").AppendOrCreate(new[] { "打開", "開" });
             g.Define("close").AppendOrCreate(new[] { "關上", "關" });
             g.Define("door").AppendOrCreate(new[] { "門", "房間門", "房門" });
             g.Define("light").AppendOrCreate(new[] { "燈", "檯燈" });
-
+            
             p.Build(g["open"], g["door"]).OnInvoke(score =>
             {
                 Debug.WriteLine("門的狀態是: " + (this._doorState ? "開著的" : "關著的"));

+ 10 - 1
src/Yuuna.Interaction.WinForms.Test/Form1.cs

@@ -46,7 +46,9 @@ namespace Yuuna.Interaction.WinForms.Test
             _history = new ListBox();
             _history.Dock = DockStyle.Fill;
             _history.Enabled = false;
+            
             _history.BorderStyle = BorderStyle.None;
+
             this.Controls.Add(_history);
 
             _input = new TextBox();
@@ -62,10 +64,17 @@ namespace Yuuna.Interaction.WinForms.Test
                         return;
 
                     this._history.Items.Add("Me:  " + req);
+
+                    int visibleItems = _history.ClientSize.Height / _history.ItemHeight;
+                    _history.TopIndex = Math.Max(_history.Items.Count - visibleItems + 1, 0);
+
                     if (TrySend(req, out var resp))
                         this._history.Items.Add("Bot: " + resp.message);
                     else
-                        this._history.Items.Add("Sys: " + resp.message);
+                        this._history.Items.Add("Sys: " + resp.message); 
+                    
+                    visibleItems = _history.ClientSize.Height / _history.ItemHeight;
+                    _history.TopIndex = Math.Max(_history.Items.Count - visibleItems + 1, 0);
                 }
             };
             this.Controls.Add(_input);

+ 9 - 35
src/Yuuna/EntryPoint.cs

@@ -6,56 +6,30 @@ namespace Yuuna
     using System;
     using Yuuna.Contracts.Modules;
     using Yuuna.Recognition.Speech;
-    using System.Threading.Tasks;
     using System.Reflection;
-    using System.Diagnostics; 
+    using System.Diagnostics;
     using Microsoft.AspNetCore.Routing;
     using Microsoft.Extensions.Configuration;
     using Microsoft.AspNetCore.Mvc;
-    using Microsoft.Extensions.Logging;
     using Yuuna.Contracts.Optimization;
-    using Yuuna.Interaction.AspNetCore; 
     using Yuuna.TextSegmention;
     using Yuuna.Contracts.Interaction;
     using Yuuna.Common.Serialization;
     using Yuuna.Common.Configuration;
     using System.Security.Cryptography;
     using System.Linq;
+    using System.Threading.Tasks;
+    using Yuuna.Interaction.AspNetCore;  
 
     internal class EntryPoint
-    {
-
-        public static async Task Main(string[] args)
+    { 
+        static EntryPoint()
         {
+            var dummy = ModuleManager.Instance;
+        }
 
-
-            //var canResponses = new Response[]
-            //{
-            //        (Moods.Sad, "我不清楚你想做什麼 OvQ"),
-            //        (Moods.Sad, "我不懂你想幹嘛 QAQ"),
-            //        (Moods.Sad, "我不知道你想幹嘛 OHQ"),
-            //};
-            //var r = new Actor(new JiebaTextSegmenter(), canResponses, default, ModuleManager.Instance.Modules);
-
-            //while (true)
-            //{
-            //    var x = Console.ReadLine();
-
-            //    if (x.Equals("unload-all"))
-            //    {
-            //        ModuleManager.Instance.UnloadAll();
-            //        foreach (var m in ModuleManager.Instance.Modules)
-            //            Console.WriteLine(m.Metadata.Name);
-            //    }
-            //    else if (x.Equals("reload-all"))
-            //    {
-            //        ModuleManager.Instance.ReloadAll();
-            //        foreach (var m in ModuleManager.Instance.Modules)
-            //            Console.WriteLine(m.Metadata.Name);
-            //    }
-            //    else if (r.Accept(x, out var rx))
-            //        Console.WriteLine(rx.Message);
-            //}
+        public static async Task Main()
+        {  
 
             var k = WebHost.RunAsync();
             await k;

+ 18 - 19
src/Yuuna/Interaction/Actor.cs

@@ -99,30 +99,30 @@ namespace Yuuna
         }
         public void Initialize(ITextSegmenter segmenter, IEnumerable<Response> canResponses, IStrategy strategy, IReadOnlyList<ModuleCoupler> moduleProxies)
         {
-            if (!this._initialized)
-                lock (this._lock)
-                {
-                    if (this._initialized)
-                        return;
-                    this._segmenter = segmenter ?? throw new ArgumentNullException(nameof(segmenter));
-                    this._canResponses = canResponses ?? throw new ArgumentNullException(nameof(canResponses));
-                    this._strategy = strategy ?? new Strategy();
+            //if (!this._initialized)
+            //lock (this._lock)
+            {
+                //if (this._initialized)
+                //    return;
+                this._segmenter = segmenter ?? throw new ArgumentNullException(nameof(segmenter));
+                this._canResponses = canResponses ?? throw new ArgumentNullException(nameof(canResponses));
+                this._strategy = strategy ?? new Strategy();
 
-                    this._antonyms = new[]
-                    {
+                this._antonyms = new[]
+                {
                         new Antonym("是", "不是"),
                         new Antonym("對", "不對"),
                         new Antonym("是", "否"),
                     };
 
-                    this._moduleProxies = moduleProxies;
-                    foreach (var plugin in this._moduleProxies)
-                    {
-                        plugin.Initialize(this._segmenter, new GroupManager());
+                this._moduleProxies = moduleProxies;
+                foreach (var plugin in this._moduleProxies)
+                {
+                    if (plugin.Initialize(this._segmenter, new GroupManager()))
                         Debug.WriteLine("已載入模組: " + plugin.Metadata.Name);
-                    }
-                    this._initialized = true;
                 }
+                this._initialized = true;
+            }
         }
 
         public bool Accept(string text, out Response response)
@@ -189,9 +189,8 @@ namespace Yuuna
                     }
                 }
 
-
-
-                var alternative = this._strategy.FindBest(this._moduleProxies.Select(x => x.Patterns).ToArray(), cutted);
+                var k = this._moduleProxies.Select(x => x.Patterns).ToArray(); 
+                var alternative = this._strategy.FindBest(k, cutted);
                 //Debug.WriteLine(alternative.Status);
                 switch (alternative.Status)
                 {

+ 13 - 3
src/Yuuna/Plugins/CollectibleLoader.cs

@@ -8,13 +8,23 @@ namespace Yuuna
 
     public sealed class CollectibleLoader : AssemblyLoadContext
     {
-        internal CollectibleLoader() : base(true)
-        {
+        private AssemblyDependencyResolver _resolver;
+
+        // https://docs.microsoft.com/zh-tw/dotnet/standard/assembly/unloadability
 
+        internal CollectibleLoader(string mainAssemblyToLoadPath) : base(true)
+        { 
+            this._resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath);
         }
 
-        protected override Assembly Load(AssemblyName assemblyName)
+        protected override Assembly Load(AssemblyName name)
         {
+            string assemblyPath = this._resolver.ResolveAssemblyToPath(name);
+            if (assemblyPath != null)
+            {
+                return this.LoadFromAssemblyPath(assemblyPath);
+            }
+
             return null;
         }
     }

+ 114 - 22
src/Yuuna/Plugins/ModuleCoupler.cs

@@ -11,33 +11,48 @@ namespace Yuuna
     using Yuuna.Contracts.Patterns;
     using Yuuna.Contracts.TextSegmention;
     using Yuuna.Contracts.Semantics;
+    using System.Linq;
 
     public sealed class ModuleCoupler : IDisposable
     {
-        private WeakReference<ModuleBase> _module;
+        private ModuleBase _module;
         private CollectibleLoader _loader;
-        internal ModuleCoupler(IEnumerable<FileInfo> dlls)
+        private object _lock = new object();
+
+        internal ModuleCoupler(IEnumerable<FileInfo> deps, IEnumerable<FileInfo> dlls)
         {
-            this._loader = new CollectibleLoader();
-            foreach (var dll in dlls)
+            this._loader = new CollectibleLoader(deps.First().FullName);
+            lock (this._lock)
             {
-                using (var fs = dll.OpenRead())
+
+                foreach (var dll in dlls)
                 {
-                    var asm = this._loader.LoadFromStream(fs);
-                    foreach (var t in asm.GetTypes())
+                    try
                     {
-                        if (t.IsSubclassOf(typeof(ModuleBase)))
+                        using (var fs = dll.OpenRead())
                         {
-                            this._module = new WeakReference<ModuleBase>(Activator.CreateInstance(t) as ModuleBase);
-                            if (this._module.TryGetTarget(out var m))
+                            var asm = this._loader.LoadFromStream(fs);
+                            // error:
+                            foreach (var t in asm.GetTypes())
                             {
-                                this.Metadata = m.Metadata;
-                                this.Id = m.Id;
+                                if (t.IsSubclassOf(typeof(ModuleBase)))
+                                {
+                                    var inst = Activator.CreateInstance(t) as ModuleBase;
+
+                                    this._module = (inst);
+                                    this.Metadata = this._module.Metadata;
+                                    this.Id = this._module.Id;
+
+                                    break;
+                                }
                             }
-                            break;
+
                         }
                     }
-
+                    catch (Exception e)
+                    {
+                        Console.WriteLine(e);
+                    }
                 }
             }
         }
@@ -49,17 +64,14 @@ namespace Yuuna
 
         public bool Initialize(ITextSegmenter s, IGroupManager g)
         {
+
             if (this._module is null)
                 return false;
-
-            if (this._module.TryGetTarget(out var m))
-            {
-                m.Initialize(s, g, out var v);
+             
+                this._module.Initialize(s, g, out var v);
                 this.Patterns = v;
-                return true;
-            }
-
-            return false;
+                return true; 
+             
         }
 
         public void Dispose()
@@ -68,4 +80,84 @@ namespace Yuuna
             this._loader = null;
         }
     }
+
+    //public sealed class ModuleCoupler : IDisposable
+    //{
+    //    private WeakReference<ModuleBase> _module;
+    //    private CollectibleLoader _loader;
+    //    private object _lock = new object();
+
+    //    internal ModuleCoupler(IEnumerable<FileInfo> deps, IEnumerable<FileInfo> dlls)
+    //    {
+    //        this._loader = new CollectibleLoader(deps.First().FullName);
+    //        lock (this._lock)
+    //        {
+
+    //            foreach (var dll in dlls)
+    //            {
+    //                try
+    //                {
+    //                    using (var fs = dll.OpenRead())
+    //                    {
+    //                        var asm = this._loader.LoadFromStream(fs);
+    //                        // error:
+    //                        foreach (var t in asm.GetTypes())
+    //                        {
+    //                            if (t.IsSubclassOf(typeof(ModuleBase)))
+    //                            {
+    //                                var inst = Activator.CreateInstance(t) as ModuleBase;
+
+    //                                this._module = new WeakReference<ModuleBase>(inst);
+    //                                if (this._module.TryGetTarget(out var m))
+    //                                {
+    //                                    this.Metadata = m.Metadata;
+    //                                    this.Id = m.Id;
+
+    //                                }
+    //                                break;
+    //                            }
+    //                        }
+
+    //                    }
+    //                }
+    //                catch (Exception e)
+    //                {
+    //                    Console.WriteLine(e);
+    //                }
+    //            }
+    //        }
+    //    }
+
+    //    public Guid Id { get; }
+
+    //    public IPatternSet Patterns { get; private set; }
+    //    public IModuleMetadata Metadata { get; }
+
+    //    public bool Initialize(ITextSegmenter s, IGroupManager g)
+    //    {
+
+    //        if (this._module is null)
+    //            return false;
+
+    //        if (this._module.TryGetTarget(out var m))
+    //        {
+    //            m.Initialize(s, g, out var v);
+    //            this.Patterns = v;
+    //            return true;
+    //        }
+    //        else
+    //        {
+
+    //            Console.WriteLine("???????? ");
+    //        }
+
+    //        return false;
+    //    }
+
+    //    public void Dispose()
+    //    {
+    //        this._loader.Unload();
+    //        this._loader = null;
+    //    }
+    //}
 }

+ 1 - 1
src/Yuuna/Plugins/ModuleManager.cs

@@ -59,7 +59,7 @@ namespace Yuuna
         {
             foreach (var moduleFolder in this._modulesFolder.EnumerateDirectories())
             {
-                var n = new ModuleCoupler(moduleFolder.EnumerateFiles("*.dll"));
+                var n = new ModuleCoupler(moduleFolder.EnumerateFiles("*.deps.json"), moduleFolder.EnumerateFiles("*.dll"));
                 this._modules.Add(n);
             }
         }

+ 7 - 12
src/Yuuna/TextSegmention/JiebaSegmenter.cs

@@ -8,8 +8,7 @@ namespace Yuuna.TextSegmention
     using System;
     using System.Collections.Immutable;
     using System.Diagnostics;
-    using System.Globalization;
-
+    using System.Globalization; 
     using Yuuna.Contracts.Semantics;
     using Yuuna.Contracts.TextSegmention;
 
@@ -36,13 +35,13 @@ namespace Yuuna.TextSegmention
 
             foreach (var name in manager.Keys)
             {
-                this.InternalLog("name: " + name);
+                Debug.WriteLine($"name: {name}");
                 foreach (var synonym in manager[name].ToImmutable())
                 {
                     foreach (var w in synonym.ToImmutable())
                     {
                         this._jieba.AddWord(w);
-                        this.InternalLog("  added: " + w);
+                        Debug.WriteLine($"added: {w}");
                     }
                 } 
             }
@@ -54,22 +53,18 @@ namespace Yuuna.TextSegmention
                 return;
 
             foreach (var name in manager.Keys)
-            { 
-                this.InternalLog("name: " + name);
+            {
+                Debug.WriteLine($"name: {name}");
                 foreach (var synonym in manager[name].ToImmutable())
                 {
                     foreach (var w in synonym.ToImmutable())
                     {
                         this._jieba.DeleteWord(w);
-                        this.InternalLog("  deleted: " + w);
+                        Debug.WriteLine($"deleted: {w}");
                     }
                 } 
             }
         }
-
-        private void InternalLog(string v)
-        { 
-            Debug.WriteLine(v);
-        }
+         
     }
 }

+ 0 - 1
src/Yuuna/Yuuna.csproj

@@ -13,7 +13,6 @@
 
   <ItemGroup>
     <Folder Include="Interaction\AspNetCore\Mvc\Views\" />
-    <Folder Include="Interaction\NewFolder\" />
     <Folder Include="Properties\" />
   </ItemGroup>