0x0001F36D 5 vuotta sitten
vanhempi
commit
7812b70186

+ 203 - 0
src/Yuuna.Common/Configuration/ConfigManager.cs

@@ -0,0 +1,203 @@
+
+namespace Yuuna.Common.Configuration
+{
+    using Newtonsoft.Json;
+    using Newtonsoft.Json.Linq;
+    using System;
+    using System.Collections.Generic;
+    using System.ComponentModel;
+    using System.Dynamic;
+    using System.IO;
+    using System.Reflection;
+    using System.Security.Cryptography;
+    using System.Text;
+    using Yuuna.Common.Serialization;
+    
+
+    public sealed class ConfigData<T> : DynamicObject, INotifyPropertyChanged
+    {
+        public override IEnumerable<string> GetDynamicMemberNames()
+        {
+            return this._list.Keys;
+        }
+
+        public override bool TryGetMember(GetMemberBinder binder, out object result)
+        {
+            if (this._list.TryGetValue(binder.Name, out var accessor))
+            {
+                result = accessor.Get();
+                return true;
+            }
+            throw new KeyNotFoundException(binder.Name);
+        }
+
+        public override bool TrySetMember(SetMemberBinder binder, object value)
+        {
+            if(this._list.TryGetValue(binder.Name, out var o))
+            {
+                var re = o.Get();
+                if (re is null && value is null)
+                    return true;
+
+                if (!re?.Equals(value) ?? !value?.Equals(re) ?? !re.Equals(value))
+                {
+                    this._list[binder.Name].Set(value);
+                    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(binder.Name));
+                }
+                return true;
+            }
+            throw new KeyNotFoundException(binder.Name);
+        }
+
+        private readonly IDictionary<string, Accessor> _list;
+
+        private static string GetName(Type type)
+        {
+            return type.Name + ".meta";
+        }
+
+        private readonly FileInfo _meta;
+        
+        public void Load()
+        {
+
+            using (var reader = new StreamReader(this._meta.OpenRead()))
+            {
+                var jObj = JsonConvert.DeserializeObject<JObject>(reader.ReadToEnd());
+                foreach (var jProp in jObj)
+                {
+                    if (this._list.TryGetValue(jProp.Key, out var a))
+                    {
+                        a.Set(jProp.Value.ToObject(a.Type));
+                    }
+                }
+            }
+        }
+
+        public void Save()
+        {
+            using (var writer = new StreamWriter(this._meta.OpenWrite()))
+            {
+                var j = new JObject();
+
+
+                foreach (var accessor in this._list)
+                {
+                    j.Add(new JProperty(accessor.Key, accessor.Value.Get()));
+                }
+
+                var json = JsonConvert.SerializeObject(j, Formatting.Indented);
+                writer.Write(json);
+            }
+        }
+        
+        public ConfigData(T graph)
+        {
+            var type = graph?.GetType() ?? throw new ArgumentNullException(nameof(graph));
+            this._list = new Dictionary<string, Accessor>();
+            this._meta = new FileInfo(GetName(type));
+
+
+            foreach (var pinfo in type.GetProperties((BindingFlags)52))
+                if (pinfo.GetCustomAttribute<FieldAttribute>() != null &&
+
+                    pinfo.GetGetMethod(true) is MethodInfo getter &&
+                    pinfo.GetSetMethod(true) is MethodInfo setter)
+                {
+                    var getDele = Delegate.CreateDelegate(typeof(Func<>).MakeGenericType(getter.ReturnType), graph, getter);
+                    var setDele = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(setter.GetParameters()[0].ParameterType), graph, setter);
+                    this._list.Add(pinfo.Name, new Accessor(pinfo.PropertyType , getDele, setDele));
+                }
+
+            // metadata not found, create and serialize object to file.
+            if (!this._meta.Exists)
+            {
+                this.Save();
+            }
+            else
+            {
+                this.Load();
+            }
+        }
+
+        private struct Accessor
+        {
+            private readonly Delegate _get;
+            private readonly Delegate _set;
+
+            public Accessor(Type type,Delegate get, Delegate set)
+            {
+                this.Type = type;
+                this._get = get;
+                this._set = set;
+            }
+
+            public Type Type { get; }
+
+            public object Get() => this._get.DynamicInvoke();
+            public void Set(object value) => this._set.DynamicInvoke(value);
+            
+        }
+
+        public IEnumerable<string> Names => this._list.Keys;
+
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
+        {
+            if (indexes.Length.Equals(1) &&
+                indexes[0] is string name)
+            {
+                if (this._list.TryGetValue(name, out var o))
+                {
+                    var re = o.Get();
+                    if (re is null && value is null)
+                        return true;
+
+                    if (!re?.Equals(value) ?? !value?.Equals(re) ?? !re.Equals(value))
+                    {
+                        this._list[name].Set(value);
+                        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
+                    }
+
+                    return true;
+                }
+                throw new KeyNotFoundException(name);
+            }
+            throw new ArgumentOutOfRangeException();
+        }
+        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
+        {
+            if(indexes.Length.Equals(1) && 
+                indexes[0] is string name )
+            {
+                if(this._list.TryGetValue(name, out var o))
+                {
+                    result = o.Get();
+                    return true;
+                }
+                throw new KeyNotFoundException(name);
+            }
+            throw new ArgumentOutOfRangeException();
+        }
+    }
+
+    public static class ConfigExtension
+    {
+        public static dynamic Bind<T>(this T obj, PropertyChangedEventHandler onPropertyChnaged = null, bool autoSave = true)
+        {
+            var p = new ConfigData<T>(obj);
+            if (onPropertyChnaged != null)
+                p.PropertyChanged += onPropertyChnaged;
+            if (autoSave)
+                p.PropertyChanged += delegate { p.Save(); };
+            return p;
+        }
+    }
+
+    [AttributeUsage(AttributeTargets.Property)]
+    public sealed class FieldAttribute : Attribute
+    {
+    }
+}

+ 1 - 0
src/Yuuna.Contracts/Modules/ModuleBase.cs

@@ -24,6 +24,7 @@ namespace Yuuna.Contracts.Modules
             var t = this.GetType();
             this.Id = t.GUID;// Guid.NewGuid();
             this.Metadata = ModuleMetadataAttribute.GetMetadata(t);
+           // this.ConfigData = Yuuna.Common.Configuration.ConfigManager.Load(this);
         }
 
         private bool _initialized;

+ 38 - 23
src/Yuuna.Interaction.WinForms.Test/Form1.cs

@@ -18,19 +18,21 @@ namespace Yuuna.Interaction.WinForms.Test
     {
         private readonly ListBox _history;
         private readonly TextBox _input;
+        private readonly RestClient client;
+
         public Form1()
         {
             this.InitializeComponent();
             this.Text = "Yuuna's Debugger Form";
             this.MaximizeBox = false;
             this.MinimizeBox = false;
-            this.MaximumSize = new Size( 320, 640);
+            this.MaximumSize = new Size(320, 640);
             this.Opacity = 0.8;
             this.DoubleBuffered = true;
             this.BackColor = Color.White;
 
-            var rx = Screen.PrimaryScreen.WorkingArea; 
-            this.Location = new Point(rx.Width - this.Size.Width, rx.Height - this.Size.Height); 
+            var rx = Screen.PrimaryScreen.WorkingArea;
+            this.Location = new Point(rx.Width - this.Size.Width, rx.Height - this.Size.Height);
             this.StartPosition = FormStartPosition.Manual;
 
             this.Move += delegate
@@ -49,40 +51,53 @@ namespace Yuuna.Interaction.WinForms.Test
 
             _input = new TextBox();
             _input.Dock = DockStyle.Bottom;
-            _input.KeyDown += (sender, e) => 
+            _input.KeyDown += (sender, e) =>
             {
                 if (e.KeyCode == Keys.Enter)
                 {
-                    var req = this._input.Text; 
+                    var req = this._input.Text;
                     this._input.Clear();
 
                     if (string.IsNullOrWhiteSpace(req))
                         return;
 
-                    this._history.Items.Add("我:  " + req);
-                    var resp = Send(req);
-                    this._history.Items.Add("Bot: " + resp.message);
+                    this._history.Items.Add("Me:  " + req);
+                    if (TrySend(req, out var resp))
+                        this._history.Items.Add("Bot: " + resp.message);
+                    else
+                        this._history.Items.Add("Sys: " + resp.message);
                 }
-            }; 
+            };
             this.Controls.Add(_input);
+
+
+            this.client = new RestClient("http://localhost:5000/");
+            client.Timeout = 3000;
         }
 
-        private static (string mood, string message) Send(string text)
+        private bool TrySend(string text, out (string mood, string message) m)
         {
-            var client = new RestClient("http://localhost:5000/");
-            client.Timeout = 3000;
-            var request = new RestRequest(Method.POST);
-            request.AddHeader("Content-Type", "application/json");
-            request.AddParameter("application/json", "{\n    \"text\": \"" + text + "\"\n}", ParameterType.RequestBody);
-            var response = client.Execute(request);
-            var result = JsonConvert.DeserializeAnonymousType(response.Content, new
+            try
+            {
+                var request = new RestRequest(Method.POST);
+                request.AddHeader("Content-Type", "application/json");
+                request.AddParameter("application/json", "{\n    \"text\": \"" + text + "\"\n}", ParameterType.RequestBody);
+                var response = client.Execute(request);
+                var result = JsonConvert.DeserializeAnonymousType(response.Content, new
+                {
+                    Success = default(bool),
+                    Message = default(string),
+                    Mood = default(string),
+                    Text = default(string),
+                });
+                m = (result.Mood, result.Message);
+                return true;
+            }
+            catch
             {
-                Success = default(bool),
-                Message = default(string),
-                Mood = default(string),
-                Text = default(string),
-            });
-            return (result.Mood, result.Message); 
+                m = ("Sad", "無法處理請求");
+            }
+            return false;
         }
     }
 }

+ 19 - 0
src/Yuuna/EntryPoint.cs

@@ -18,11 +18,30 @@ namespace Yuuna
     using Yuuna.TextSegmention;
     using Yuuna.Contracts.Interaction;
     using Yuuna.Common.Serialization;
+    using Yuuna.Common.Configuration;
 
     internal class EntryPoint
     {
+        public class MyClass
+        {
+            [Field]
+            public string Value1 { get; set; }
+        }
+
         public static async Task Main(string[] args)
         {
+            var v = new MyClass();
+            var proxy = v.Bind((sender, e) => Console.WriteLine("<:" + e.PropertyName));
+
+            Console.WriteLine(v.Value1);
+            Console.ReadKey();
+            proxy.Value1 = "4567";
+
+            Console.WriteLine(v.Value1);
+
+            //proxy.Save();
+            Console.ReadKey();
+            return;
 
             //var canResponses = new Response[]
             //{