瀏覽代碼

Tried to fix an occasional startup concurrency error
Fixed Expression.RegisterFucntion stuff
Added better Debug and tried to resolve threading issues in report previewer

frogsoftware 1 年之前
父節點
當前提交
886637bde4

+ 135 - 66
InABox.Core/CoreExpression.cs

@@ -11,46 +11,102 @@ using System.Text.RegularExpressions;
 
 namespace InABox.Core
 {
-    using FncType = Func<IExpression[], IDictionary<string, object>, object?>;
+    //using FncType = Func<IExpression[], IDictionary<string, object>, object?>;
 
-    public class CoreExpressionFunction
-    {
-        public string Group { get; set; }
-
-        public string Name { get; set; }
+    // public class CoreExpressionFunction
+    // {
+    //     public string Group { get; set; }
+    //
+    //     public string Name { get; set; }
+    //
+    //     public string? Description { get; set; }
+    //     
+    //     public List<Parameter> Parameters { get; set; }
+    //
+    //     public FncType Function { get; set; }
+    //
+    //     public class Parameter
+    //     {
+    //         public string Name { get; set; }
+    //
+    //         public string Type { get; set; }
+    //
+    //         public Parameter(string name, string type)
+    //         {
+    //             Name = name;
+    //             Type = type;
+    //         }
+    //     }
+    //
+    //     public CoreExpressionFunction(string group, string name, FncType function, List<Parameter> parameters, string? description = null)
+    //     {
+    //         Group = group;
+    //         Name = name;
+    //         Parameters = parameters;
+    //         Function = function;
+    //         Description = description;
+    //     }
+    // }
 
-        public string? Description { get; set; }
-        
-        public List<Parameter> Parameters { get; set; }
+    public interface IExpressionModel { }
+    public interface IExpressionModel<TReturn> : IExpressionModel { }
 
-        public FncType Function { get; set; }
+    public abstract class CoreExpressionFunction : FunctionBase
+    {
+        public abstract string Group { get; }
+        public abstract string Description { get; }
+        public abstract string[] Parameters { get; }
+    }
+    
+    internal class FormatFunction : CoreExpressionFunction
+    {
+        #region IFunction Members
 
-        public class Parameter
+        public override object Evaluate(IExpression[] parameters, Context context)
         {
-            public string Name { get; set; }
+            ValidateParameterCount(parameters,-1, 2);
 
-            public string Type { get; set; }
-
-            public Parameter(string name, string type)
-            {
-                Name = name;
-                Type = type;
-            }
+            string fmt = parameters.First()?.Evaluate(Variables).ToString() ?? "";
+            object[] objects = parameters.Skip(1).Select(x => x.Evaluate(Variables)).ToArray();
+            return String.Format(fmt, objects);
         }
 
-        public CoreExpressionFunction(string group, string name, FncType function, List<Parameter> parameters, string? description = null)
-        {
-            Group = group;
-            Name = name;
-            Parameters = parameters;
-            Function = function;
-            Description = description;
-        }
+        public override string Group => "String";
+        public override string Name => "Format";
+        public override string Description => "Formats a list of objects using the specified format string";
+        public override string[] Parameters => new[] { "string format", "object[] parameters" };
+
+        #endregion
     }
 
-    public interface IExpressionModel { }
-    public interface IExpressionModel<TReturn> : IExpressionModel { }
+    internal class Client_LoadDocumentFunction : CoreExpressionFunction
+    {
+        public override object? Evaluate(IExpression[] parameters, Context context)
+        {
+            ValidateParameterCount(parameters, 1, 1);
+            
+            var id = parameters[0].Evaluate(Variables);
+            
+            if (id is null)
+                return null;
+            
+            if (!(id is Guid docID))
+                return null;
+
+            return new Client<Document>()
+                .Query(
+                    new Filter<Document>(x => x.ID).IsEqualTo(docID),
+                    new Columns<Document>(x => x.Data))
+                .Rows.FirstOrDefault()
+                ?.Get<Document, byte[]>(x => x.Data);
+        }
 
+        public override string Group => "Other";
+        public override string Name => "Client_LoadDocument";
+        public override string Description => "Retrieves a database document with the specified id";
+        public override string[] Parameters => new[] { "Guid id" };
+    }
+    
     public class CoreExpression
     {
         private Expression Expression;
@@ -75,7 +131,7 @@ namespace InABox.Core
 
         public CoreExpression(string expressionString)
         {
-            Expression = new Expression(expressionString);
+            Expression = new Expression(expressionString, _context);
             if (!IsValid)
             {
                 var expr = "\"" + expressionString + "\"";
@@ -86,10 +142,10 @@ namespace InABox.Core
                 Expression = new Expression(expr);
             }
             
-            foreach (var function in Functions)
-            {
-                Expression.RegisterFunction(function.Name, function.Function);
-            }
+            // foreach (var function in Functions)
+            // {
+            //     Expression.RegisterFunction(function.Name, function.Function);
+            // }
         }
 
         public object? Evaluate(Dictionary<string, object?>? variables)
@@ -112,45 +168,58 @@ namespace InABox.Core
         #region Static
 
         public static List<CoreExpressionFunction> Functions = new List<CoreExpressionFunction>();
-
-        static CoreExpression()
+        
+        private static Context _context = new Context(ExpressiveOptions.None);
+        
+        static void RegisterFunction<T>() where T : CoreExpressionFunction, new ()
         {
-            RegisterFunction("String", "Format", (p, v) =>
-            {
-                if (!(p[0].Evaluate(v) is string format)) throw new Exception("No format string given for Format()");
-                return string.Format(format, p.Skip(1).Select(x => x.Evaluate(v)).ToArray());
-            }, "string fmt", "...");
-
-            RegisterFunction("Other", "Client_LoadDocument", "Loads a byte array from the database Document table, with the ID {docID}.", Fnc_LoadDocument, "Guid docID");
+            var function = new T();
+            Functions.Add(function);
+            _context.RegisterFunction(function);
         }
-
-        private static object? Fnc_LoadDocument(IExpression[] p, IDictionary<string, object> v)
+        
+        static CoreExpression()
         {
-            var id = p[0].Evaluate(v);
-            if (id is null)
-                return null;
-            if (!(id is Guid docID))
-                return null;
+            
+            RegisterFunction<FormatFunction>();
+            RegisterFunction<Client_LoadDocumentFunction>();
+            
+            // RegisterFunction("String", "Format", (p, v) =>
+            // {
+            //     if (!(p[0].Evaluate(v) is string format)) throw new Exception("No format string given for Format()");
+            //     return string.Format(format, p.Skip(1).Select(x => x.Evaluate(v)).ToArray());
+            // }, "string fmt", "...");
 
-            return new Client<Document>()
-                .Query(
-                    new Filter<Document>(x => x.ID).IsEqualTo(docID),
-                    new Columns<Document>(x => x.Data))
-                .Rows.FirstOrDefault()
-                ?.Get<Document, byte[]>(x => x.Data);
+            //RegisterFunction("Other", "Client_LoadDocument", "Loads a byte array from the database Document table, with the ID {docID}.", Fnc_LoadDocument, "Guid docID");
         }
 
-        public static void RegisterFunction(string group, string name, FncType function, params string[] parameters)
-            => RegisterFunction(group, name, null, function, parameters);
+        // private static object? Fnc_LoadDocument(IExpression[] p, IDictionary<string, object> v)
+        // {
+        //     var id = p[0].Evaluate(v);
+        //     if (id is null)
+        //         return null;
+        //     if (!(id is Guid docID))
+        //         return null;
+        //
+        //     return new Client<Document>()
+        //         .Query(
+        //             new Filter<Document>(x => x.ID).IsEqualTo(docID),
+        //             new Columns<Document>(x => x.Data))
+        //         .Rows.FirstOrDefault()
+        //         ?.Get<Document, byte[]>(x => x.Data);
+        // }
 
-        public static void RegisterFunction(string group, string name, string? description, FncType function, params string[] parameters) =>
-            Functions.Add(new CoreExpressionFunction(group, name, function, parameters.Select(x =>
-            {
-                var parts = x.Split(' ');
-                if (parts.Length == 1)
-                    return new CoreExpressionFunction.Parameter(parts[0], "");
-                return new CoreExpressionFunction.Parameter(parts[1], parts[0]);
-            }).ToList(), description));
+        // public static void RegisterFunction(string group, string name, FncType function, params string[] parameters)
+        //     => RegisterFunction(group, name, null, function, parameters);
+
+        // public static void RegisterFunction(string group, string name, string? description, FncType function, params string[] parameters) =>
+        //     Functions.Add(new CoreExpressionFunction(group, name, function, parameters.Select(x =>
+        //     {
+        //         var parts = x.Split(' ');
+        //         if (parts.Length == 1)
+        //             return new CoreExpressionFunction.Parameter(parts[0], "");
+        //         return new CoreExpressionFunction.Parameter(parts[1], parts[0]);
+        //     }).ToList(), description));
 
         #endregion
     }

+ 2 - 1
inabox.client.ipc/IPCClientFactory.cs

@@ -2,6 +2,7 @@
 using InABox.Core;
 using InABox.IPC;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
@@ -11,7 +12,7 @@ namespace InABox.Client.IPC
 {
     public static class IPCClientFactory
     {
-        private static Dictionary<string, IPCClientTransport> Clients = new();
+        private static ConcurrentDictionary<string, IPCClientTransport> Clients = new();
 
         public static IPCClientTransport GetClient(string pipeName)
         {

+ 3 - 2
inabox.wpf/DynamicGrid/Editors/ExpressionEditor/ExpressionEditorWindow.xaml.cs

@@ -60,6 +60,7 @@ namespace InABox.DynamicGrid
                 }
                 return new FunctionParameter(parts[1], parts[0]);
             }).ToList<IFunctionParameter>());
+        
         private static void RegisterFunctionTemplateDesc(string group, string name, string description, params string[] parameters)
             => RegisterFunctionTemplate(group, name, description, parameters.Select(x =>
             {
@@ -143,11 +144,11 @@ namespace InABox.DynamicGrid
 
             foreach(var function in CoreExpression.Functions)
             {
-                RegisterFunctionTemplate(
+                RegisterFunctionTemplateDesc(
                     function.Group,
                     function.Name,
                     function.Description,
-                    function.Parameters.Select(x => new FunctionParameter(x.Name, x.Type)).ToList<IFunctionParameter>());
+                    function.Parameters);
             }
         }
 

+ 11 - 5
inabox.wpf/Reports/PreviewWindow.xaml.cs

@@ -24,6 +24,7 @@ using System.Drawing;
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
+using System.Windows.Threading;
 using FastReport.Design;
 
 namespace InABox.Wpf.Reports
@@ -177,6 +178,7 @@ namespace InABox.Wpf.Reports
                 }
                 catch (Exception e)
                 {
+                    Logger.Send(LogType.Error,"",$"SetupReport() returned an error!\n{e.Message}\n{e.StackTrace}");
                     return e.Message;
                 }
             }).ContinueWith((s) =>
@@ -185,18 +187,22 @@ namespace InABox.Wpf.Reports
                 {
                     if (s.Result == null)
                     {
-                        Designer.Report ??= _report;
-                        action();
-                        CloseLoading();
+                        Dispatcher.BeginInvoke(() =>
+                        {
+                            Designer.Report ??= _report;
+                            action();
+                            CloseLoading();
+                        });
                     }
                     else
                     {
-                        ShowEditor(s.Result);
+                        Dispatcher.BeginInvoke(() =>ShowEditor(s.Result));
                     }
                 }
                 catch (Exception e)
                 {
-                    ShowEditor(e.Message);
+                    Logger.Send(LogType.Error,"",$"An Error occurred while loading the report window!\n{e.Message}\n{e.StackTrace}");
+                    Dispatcher.BeginInvoke(() =>ShowEditor(e.Message));
                 }
             }, TaskScheduler.FromCurrentSynchronizationContext());
         }