protected override void ProcessQueueEntries(List <ExceptionWrapper> entryCollection)
        {
            try
            {
                DateTime?lastFailedToLogToStoreDate = null;

                foreach (var ew in entryCollection)
                {
                    try
                    {
                        AddExceptionToDB(ew);
                    }
                    catch (Exception ee)
                    {
                        // prevent logging failures too often
                        if (!lastFailedToLogToStoreDate.HasValue || DateTime.Now.Subtract(lastFailedToLogToStoreDate.Value).TotalSeconds >= 25)
                        {
                            Log.Error(ee, $"Failed to log exception to DB store. EP={ew.EndpointKey}; sID={ew.sId};");
                            Log.Error($"Original: {ew.message}; stack=\r\n{ew.stackTrace}");

                            lastFailedToLogToStoreDate = DateTime.Now;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, "ExceptionLogger::ProcessMessagesLoop failed");
                SessionLog.Error("ExceptionLogger::ProcessMessagesLoop failed");
                SessionLog.Exception(ex);
            }
        }
Пример #2
0
        private Assembly ResolveReference(AssemblyLoadContext ctx, AssemblyName asmName)
        {
            try
            {
                // try and find relative to existing assebmlies loaded in ctx
                foreach (var asm in ctx.Assemblies)
                {
                    var fi = new FileInfo(asm.Location);

                    var path = Path.Combine(fi.DirectoryName, asmName.Name + ".dll");

                    if (File.Exists(path))
                    {
                        try
                        {
                            var loadedAsm = ctx.LoadFromAssemblyPath(path);
                            if (loadedAsm != null)
                            {
                                return(loadedAsm);
                            }
                        }
                        catch { }
                    }
                }

                SessionLog.Error($"Failed to resolve {asmName.FullName} in context {ctx.Name}");
                return(null);
            }
            catch (Exception ex)
            {
                SessionLog.Error($"(Exception) Failed to resolve {asmName.FullName} in context {ctx.Name}. {ex.ToString()}");
                return(null);
            }
        }
Пример #3
0
        private static PluginSetParameterValue GetParameterValueFromPlugins(CachedRoutine routine, string parameterName, List <ExecutionPlugin> plugins)
        {
            foreach (var plugin in plugins)
            {
                try
                {
                    var val = plugin.GetParameterValue(routine.Schema, routine.Routine, parameterName);

                    if (val != PluginSetParameterValue.DontSet)
                    {
                        return(val);
                    }
                }
                catch (Exception ex)
                {
                    SessionLog.Error("Plugin {0} GetParameterValue failed", plugin.Name);
                    SessionLog.Exception(ex);
                }
            }

            return(PluginSetParameterValue.DontSet);
        }
Пример #4
0
        private void CompileCodeIntoAssemblyContext(InlineModuleManifestEntry inlineEntry, string code)
        {
            var ctxName    = $"Inline Plugin Context {++_asmCtxCounter}";
            var pluginPath = Path.GetFullPath("plugins");
            var asmCtx     = new PluginAssemblyLoadContext(pluginPath, ctxName, true /*enable unloading*/);

            ASM_CTXES.Add(asmCtx);

            SessionLog.Info($"Created {ctxName} for {inlineEntry.Name}".PadRight(35));

            var assemblyBytes = CSharpCompilerHelper.CompileIntoAssembly(inlineEntry.Name, code, out var problems);

            if ((problems != null && problems.Count == 0))
            {
                Assembly assembly = null;

                try
                {
                    using (var ms = new MemoryStream(assemblyBytes))
                    {
                        assembly = asmCtx.LoadFromStream(ms);

                        ParseAndLoadPluginAssembly(asmCtx, assembly, inlineEntry.Id);
                    }
                }
                catch (Exception ee)
                {
                    SessionLog.Error($"Failed to load inline plugin assembly '{assembly?.FullName}' {inlineEntry.Name}/{inlineEntry.Id}. See exception that follows.");
                    SessionLog.Exception(ee);
                }
            }
            else
            {
                SessionLog.Error($"Inline plugin {inlineEntry.Name} ({inlineEntry.Id}) failed to compile with the following error(s): {string.Join(", ", problems)}");
            }
        }
Пример #5
0
        public void Run()
        {
            try
            {
                Thread.CurrentThread.Name = "WorkerThread " + this.Endpoint.Pedigree;

                this.Status = "Started";

                this.IsRunning          = true;
                this.IsOutputFilesDirty = false;

                //DateTime lastSavedDate = DateTime.Now;

                var cache = this.Endpoint.CachedRoutines;

                if (cache != null && cache.Count > 0)
                {
                    this.MaxRowDate = cache.Max(c => c.RowVer);
                }

                int connectionOpenErrorCnt = 0;

                if (this.Endpoint?.MetadataConnection?.ConnectionStringDecrypted == null)
                {
                    this.IsRunning = false;
                    this.Status    = $"Endpoint '{this.Endpoint?.Pedigree ?? "(null)"}' does not have a valid metadata connection configured.";
                    this.log.Error(this.Status);
                    SessionLog.Error(this.Status);
                    return;
                }

                var exceptionThrottler = new SortedList <DateTime, Exception>();

                while (this.IsRunning)
                {
                    // look for new instructions first
                    lock (_instructionQueue)
                    {
                        while (_instructionQueue.Count > 0)
                        {
                            var ins = _instructionQueue.Dequeue();

                            if (ins.Type == WorkerInstructionType.RegenAllFiles)
                            {
                                this.ForceGenerateAllOutputFiles(this.Endpoint);
                            }
                            else if (ins.Type == WorkerInstructionType.RegenSpecificFile)
                            {
                                this.ForceGenerateOutputFile(this.Endpoint, ins.JsFile);
                            }
                        }
                    }

                    isIterationDirty = false;

                    string connectionStringRefForLog = null;

                    try
                    {
                        if (!string.IsNullOrEmpty(Endpoint.PullMetadataFromEndpointId))
                        {
                            var ep = Settings.SettingsInstance.Instance.FindEndpointById(Endpoint.PullMetadataFromEndpointId);

                            if (ep != null)
                            {
                                this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - Metadata pulled from {ep.Pedigree}";
                            }
                            else
                            {
                                this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - ERROR. Metadata configured to pull from endpoint with Id {Endpoint.PullMetadataFromEndpointId} but source endpoint not found.";
                            }

                            this.IsRunning = false;
                            continue;
                        }
                        else if (Endpoint.DisableMetadataCapturing)
                        {
                            this.Status    = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - Metadata capturing disabled";
                            this.IsRunning = false;
                            continue;
                        }
                        else if (!Endpoint.IsOrmInstalled)
                        {
                            // try again in 3 seconds
                            this.Status = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm")} - Waiting for ORM to be installed";
                            Thread.Sleep(3000);
                            continue;
                        }

                        var csb = new SqlConnectionStringBuilder(this.Endpoint.MetadataConnection.ConnectionStringDecrypted);

                        connectionStringRefForLog = $"Data Source={csb.DataSource}; UserId={csb.UserID}; Catalog={csb.InitialCatalog}";

                        var appName = $"jsdal-server worker {this.Endpoint.Pedigree} {System.Environment.MachineName}";

                        csb.ApplicationName = appName.Left(128);

                        var connectionStringDecrypted = csb.ToString();

                        using (var con = new SqlConnection(connectionStringDecrypted))
                        {
                            try
                            {
                                con.Open();
                                connectionOpenErrorCnt = 0;
                            }
                            catch (Exception oex)
                            {
                                this.Status = "Failed to open connection to database: " + oex.Message;
                                this.log.Exception(oex, connectionStringRefForLog);
                                connectionOpenErrorCnt++;

                                int waitMS = Math.Min(3000 + (connectionOpenErrorCnt * 3000), 300000 /*Max 5mins between tries*/);

                                this.Status = $"Attempt: #{connectionOpenErrorCnt + 1} (waiting for {waitMS / 1000} secs). " + this.Status;

                                Hubs.WorkerMonitor.Instance.NotifyObservers();

                                Thread.Sleep(waitMS);
                                continue;
                            }

                            ProcessAsync(con, connectionStringDecrypted).Wait();
                        } // using connection

                        if (isIterationDirty)
                        {
                            Hubs.WorkerMonitor.Instance.NotifyObservers();
                        }

                        Thread.Sleep(SettingsInstance.Instance.Settings.DbSource_CheckForChangesInMilliseconds);
                    }
                    catch (Exception ex)
                    {
                        this.log.Exception(ex);

                        exceptionThrottler.Add(DateTime.Now, ex);

                        var thresholdDate = DateTime.Now.AddSeconds(-60);

                        var beforeThreshold = exceptionThrottler.Where(kv => kv.Key < thresholdDate).ToList();

                        // remove items outside of threshold checking window
                        for (int i = 0; i < beforeThreshold.Count; i++)
                        {
                            exceptionThrottler.Remove(beforeThreshold[i].Key);
                        }

                        // TODO: make threshold count configurable
                        if (exceptionThrottler.Count() >= 6)
                        {
                            exceptionThrottler.Clear();
                            this.Status = $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - Too many exceptions, shutting down thread for now. Last exception: {ex.Message}";
                            Hubs.WorkerMonitor.Instance.NotifyObservers();
                            break; // break out of main while loop
                        }

                        this.Status = $"{ DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} - {ex.Message}";
                        Hubs.WorkerMonitor.Instance.NotifyObservers();

                        var sleepTimeMS = 2000 + (exceptionThrottler.Count() * 400);

                        // cap at 8 secs
                        sleepTimeMS = sleepTimeMS > 8000 ? 8000 : sleepTimeMS;

                        Thread.Sleep(sleepTimeMS);
                    }
                } // while IsRunning
            }
            catch (ThreadAbortException)
            {
                // ignore TAEs
            }
            catch (Exception ex)
            {
                this.log.Exception(ex);
            }
            finally
            {
                this.IsRunning = false;
                this.winThread = null;
                Hubs.WorkerMonitor.Instance.NotifyObservers();
            }
        } // Run
Пример #6
0
        public static IWebHostBuilder BuildWebHost(string pathToContentRoot, string[] args)
        {
            var webServerSettings = SettingsInstance.Instance.Settings.WebServer;

            // var certPath = "cert.pfx";
            // var certPassPath = Path.GetFullPath("cert.pass");

            // if (!File.Exists(certPassPath))
            // {
            //     throw new Exception($"Unable to find cert path file: {certPassPath}");
            // }

            // var certPass = System.IO.File.ReadAllText(certPassPath);


            //                 var configurationBuilder = new ConfigurationBuilder();

            //                 configurationBuilder.AddJsonFile("./appsettings.json", false, true);

            // var appConfig = configurationBuilder.Build();


            return(WebHost
                   .CreateDefaultBuilder(args)
                   .UseSerilog()
                   .UseContentRoot(pathToContentRoot)
                   .UseWebRoot(Path.Combine(pathToContentRoot, "wwwroot"))
                   .UseSetting(WebHostDefaults.SuppressStatusMessagesKey, "true")
                   //   .ConfigureAppConfiguration((builderContext, config) =>
                   //   {
                   //     IHostingEnvironment env = builderContext.HostingEnvironment;

                   //     config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
                   //         //.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
                   //   })

                   .UseHttpSys(options =>
            {
                options.Authentication.Schemes = AuthenticationSchemes.None;
                options.Authentication.AllowAnonymous = true;
                options.MaxConnections = null;
                options.MaxRequestBodySize = 30000000;       //~30MB

                int interfaceCnt = 0;

                if ((webServerSettings.EnableSSL ?? false) &&
                    !string.IsNullOrWhiteSpace(webServerSettings.HttpsServerHostname) &&
                    webServerSettings.HttpsServerPort.HasValue &&
                    !string.IsNullOrWhiteSpace(webServerSettings.HttpsCertHash))
                {
                    try
                    {
                        var httpsUrl = $"https://{webServerSettings.HttpsServerHostname}:{webServerSettings.HttpsServerPort.Value}";

                        if (NetshWrapper.ValidateSSLCertBinding(webServerSettings.HttpsServerHostname, webServerSettings.HttpsServerPort.Value))
                        {
                            if (NetshWrapper.ValidateUrlAcl(true, webServerSettings.HttpsServerHostname, webServerSettings.HttpsServerPort.Value))
                            {
                                //!eventLog.Info($"Listening to {httpsUrl}");
                                options.UrlPrefixes.Add(httpsUrl);
                                interfaceCnt++;
                            }
                            else
                            {
                                if (NetshWrapper.AddUrlToACL(true, webServerSettings.HttpsServerHostname, webServerSettings.HttpsServerPort.Value))
                                {
                                    //!eventLog.Info($"Listening to {httpsUrl}");
                                    options.UrlPrefixes.Add(httpsUrl);
                                    interfaceCnt++;
                                }
                                else
                                {
                                    SessionLog.Error($"The url '{httpsUrl}' was not found in ACL list so a listener for this URL cannot be started.");
                                    Log.Error($"The url '{httpsUrl}' was not found in ACL list so a listener for this URL cannot be started.");
                                }
                            }
                        }
                        else
                        {
                            SessionLog.Error($"There is no SSL cert binding for '{httpsUrl}' so a listener for this URL cannot be started.");
                            Log.Error($"There is no SSL cert binding for '{httpsUrl}' so a listener for this URL cannot be started.");
                        }
                    }
                    catch (Exception ex)
                    {
                        SessionLog.Exception(ex);
                        Log.Error(ex, "HTTPS init failed");
                    }
                }

                if (webServerSettings.EnableBasicHttp ?? false)
                {
                    try
                    {
                        var httpUrl = $"http://{webServerSettings.HttpServerHostname}:{webServerSettings.HttpServerPort}";

                        if (NetshWrapper.ValidateUrlAcl(false, webServerSettings.HttpServerHostname, webServerSettings.HttpServerPort.Value))
                        {
                            //!eventLog.Info($"Listening to {httpUrl}");
                            options.UrlPrefixes.Add(httpUrl);
                            interfaceCnt++;
                        }
                        else
                        {
                            if (NetshWrapper.AddUrlToACL(false, webServerSettings.HttpServerHostname, webServerSettings.HttpServerPort.Value))
                            {
                                //!eventLog.Info($"Listening to {httpUrl}");
                                options.UrlPrefixes.Add(httpUrl);
                                interfaceCnt++;
                            }
                            else
                            {
                                SessionLog.Error($"The url '{httpUrl}' was not found in ACL list so a listener for this URL cannot be started.");
                                Log.Error($"The url '{httpUrl}' was not found in ACL list so a listener for this URL cannot be started.");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        SessionLog.Exception(ex);
                        Log.Error(ex, "Basic Http init failed");
                    }
                }

                if (interfaceCnt == 0)
                {
                    Log.Warning("No valid interface (http or https) found so defaulting to localhost:9086");
                    options.UrlPrefixes.Add("http://localhost:9086");
                }
            })
                   //   .UseKestrel(options =>
                   //   {
                   //       options.AddServerHeader = false;

                   //       // TODO: Allow more config here, especially the limits
                   //       //!options.Limits.MaxConcurrentConnections


                   //       if (webServerSettings.EnableSSL ?? false)
                   //       {

                   //           if (File.Exists(certPath))
                   //           {
                   //               options.Listen(System.Net.IPAddress.Any, webServerSettings.HttpsServerPort ?? 44312, listenOptions =>
                   //               {
                   //                   try
                   //                   {
                   //                       listenOptions.UseHttps(certPath, certPass);
                   //                   }
                   //                   catch (System.Exception ex)
                   //                   {
                   //                       SessionLog.Exception(ex);
                   //                       Cons ole.WriteLine(ex.ToString());
                   //                       throw;
                   //                   }
                   //               });
                   //           }
                   //           else
                   //           {
                   //               Cons ole.WriteLine("Cannot start HTTPS listener: The cert file '{0}' does not exists.", certPath);
                   //           }
                   //       }

                   //       if (webServerSettings.EnableBasicHttp ?? false)
                   //       {
                   //           options.Listen(System.Net.IPAddress.Any, webServerSettings.HttpServerPort ?? 9086); // http
                   //       }

                   //   })
                   .UseStartup <Startup>()
                   .UseSetting(WebHostDefaults.DetailedErrorsKey, "true")

                   );
            //     .UseUrls("http://localhost:9086", "https://*:4430")
        }
Пример #7
0
        public async Task InitAsync()
        {
            // load from plugin directory
            try
            {
                // AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
                // {
                //     try
                //     {
                //         var asmName = new AssemblyName(e.Name);
                //         var requestingLocation = e.RequestingAssembly.Location;
                //         var requestingDir = Path.GetDirectoryName(requestingLocation);

                //         // look for a dll in the same location as the requesting assembly
                //         var path = Path.Combine(requestingDir, asmName.Name + ".dll");

                //         if (!File.Exists(path)) return null;

                //         Assembly.LoadFrom(path);

                //         return null;
                //     }
                //     catch
                //     {
                //         return null;
                //     }
                // };

                var pluginPath = Path.GetFullPath("plugins");

                if (Directory.Exists("./plugins"))
                {
                    var dllCollection = Directory.EnumerateFiles("plugins", "*.dll", SearchOption.TopDirectoryOnly);

                    foreach (var dllPath in dllCollection)
                    {
                        // skip jsdal-plugin base
                        if (dllPath.Equals("plugins\\jsdal-plugin.dll", StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        try
                        {
                            var ctxName = $"Plugin Context {++_asmCtxCounter}";
                            var asmCtx  = new PluginAssemblyLoadContext(pluginPath, ctxName, true /*enable unloading*/);
                            ASM_CTXES.Add(asmCtx);
                            SessionLog.Info($"Created {ctxName} for {dllPath}".PadRight(35));


                            var dllFullPath    = Path.GetFullPath(dllPath);
                            var pluginAssembly = asmCtx.LoadFromAssemblyPath(dllFullPath);

                            ParseAndLoadPluginAssembly(asmCtx, pluginAssembly, null);
                        }
                        catch (Exception ee)
                        {
                            SessionLog.Error("Failed to load plugin DLL '{0}'. See exception that follows.", dllPath);
                            SessionLog.Exception(ee);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                SessionLog.Exception(ex);
            }

            // load inline assemblies
            try
            {
                foreach (var inlineEntry in InlineModuleManifest.Instance.Entries)
                {
                    var sourcePath = Path.Combine(InlinePluginSourcePath, inlineEntry.Id);

                    if (File.Exists(sourcePath))
                    {
                        var code = await File.ReadAllTextAsync(sourcePath);

                        CompileCodeIntoAssemblyContext(inlineEntry, code);
                    }
                    else
                    {
                        SessionLog.Error($"Inline module {inlineEntry.Name} not found at '{sourcePath}'");
                    }
                }
            }
            catch (Exception ex)
            {
                SessionLog.Exception(ex);
            }

            // init server-wide types
            // try
            // {
            //     InitServerWidePlugins();
            // }
            // catch (Exception ex)
            // {
            //     SessionLog.Exception(ex);
            // }
        }
Пример #8
0
        //AssemblyLoadContext, AssemblyName, Assembly?
        // private Assembly OnResolveAssembly(AssemblyLoadContext ctx, AssemblyName asmName)
        // {
        //     try
        //     {
        //         // try and find relative to existing assebmlies loaded in ctx
        //         foreach (var asm in ctx.Assemblies)
        //         {
        //             var fi = new FileInfo(asm.Location);

        //             var path = Path.Combine(fi.DirectoryName, asmName.Name + ".dll");

        //             if (File.Exists(path))
        //             {
        //                 try
        //                 {
        //                     var loadedAsm = ctx.LoadFromAssemblyPath(path);
        //                     if (loadedAsm != null) return loadedAsm;
        //                 }
        //                 catch { }
        //             }
        //         }

        //         SessionLog.Error($"Failed to resolve {asmName.FullName} in context {ctx.Name}");
        //         return null;
        //     }
        //     catch
        //     {
        //         return null;
        //     }
        // }

        // private Assembly OnResolveAssembly(object sender, ResolveEventArgs e)
        // {
        //     try
        //     {
        //         var asmName = new AssemblyName(e.Name);
        //         var requestingLocation = e.RequestingAssembly.Location;
        //         var requestingDir = Path.GetDirectoryName(requestingLocation);

        //         // look for a dll in the same location as the requesting assembly
        //         var path = Path.Combine(requestingDir, asmName.Name + ".dll");

        //         if (!File.Exists(path)) return null;

        //         Assembly.LoadFrom(path);

        //         return null;
        //     }
        //     catch
        //     {
        //         return null;
        //     }
        // }

        // private void InitServerWidePlugins()
        // {
        //     try
        //     {
        //         if (PluginAssemblies == null) return;

        //         foreach (var pluginAssembly in PluginAssemblies)
        //         {
        //             var pluginInfoCollection = pluginAssembly.Plugins.Where(p => p.Type == OM.PluginType.ServerMethod || p.Type == OM.PluginType.BackgroundThread);

        //             foreach (var pluginInfo in pluginInfoCollection)
        //             {
        //                 if (pluginInfo.Type == OM.PluginType.BackgroundThread)
        //                 {
        //                     _backgroundThreadManager.Register(pluginInfo);
        //                 }
        //                 else if (pluginInfo.Type == OM.PluginType.ServerMethod)
        //                 {
        //                     ServerMethodManager.Register(pluginAssembly.InstanceId, pluginInfo);
        //                 }
        //             }
        //         }
        //     }
        //     catch (Exception ex)
        //     {
        //         SessionLog.Exception(ex);
        //     }
        // }


        // parses an Assembly and checks for Plugin-type interface. If found each of those interfaces are tested for validity in terms of mandatory Attribute values and uniqueness
        private bool ParsePluginAssembly(Assembly pluginAssembly, out List <PluginInfo> pluginInfoList, out List <string> errorList, bool checkForConflict = true)
        {
            errorList      = new List <string>();
            pluginInfoList = new List <PluginInfo>();

            if (pluginAssembly.DefinedTypes != null)
            {
                var pluginTypeList = pluginAssembly.DefinedTypes.Where(typ => typ.IsSubclassOf(typeof(PluginBase))).ToList();

                if (pluginTypeList != null && pluginTypeList.Count > 0)
                {
                    foreach (var pluginType in pluginTypeList)
                    {
                        var pluginInfo = new PluginInfo();

                        try
                        {
                            var pluginData = pluginType.GetCustomAttribute(typeof(PluginDataAttribute)) as PluginDataAttribute;

                            if (pluginData == null)
                            {
                                errorList.Add($"Plugin '{pluginType.FullName}' from assembly '{pluginAssembly.FullName}' does not have a PluginData attribute defined on the class level. Add a jsdal_plugin.PluginDataAttribute to the class.");
                                continue;
                            }

                            if (!Guid.TryParse(pluginData.Guid, out var pluginGuid))
                            {
                                errorList.Add($"Plugin '{pluginType.FullName}' does not have a valid Guid value set on its PluginData attribute.");
                                continue;
                            }

                            if (checkForConflict)
                            {
                                var conflict = PluginAssemblies.SelectMany(a => a.Plugins).FirstOrDefault(p => p.Guid.Equals(pluginGuid));

                                if (conflict != null)
                                {
                                    errorList.Add($"Plugin '{pluginType.FullName}' has a conflicting Guid. The conflict is on assembly {conflict.TypeInfo.FullName} and plugin '{conflict.Name}' with Guid value {conflict.Guid}.");
                                    continue;
                                }
                            }

                            if (pluginType.IsSubclassOf(typeof(ExecutionPlugin)))
                            {
                                pluginInfo.Type = OM.PluginType.Execution;
                            }
                            else if (pluginType.IsSubclassOf(typeof(BackgroundThreadPlugin)))
                            {
                                pluginInfo.Type = OM.PluginType.BackgroundThread;
                            }
                            else if (pluginType.IsSubclassOf(typeof(ServerMethodPlugin)))
                            {
                                pluginInfo.Type = OM.PluginType.ServerMethod;


                                // TODO: Additional validation: Look for at least on ServerMethod? otherwise just a warning?
                                //      What about unique names of ServerMethods?
                                //      Validate Custom Namespace validity (must be JavaScript safe)
                            }
                            else
                            {
                                errorList.Add($"Unknown plugin type '{pluginType.FullName}'.");
                                continue;
                            }

                            pluginInfo.Assembly    = pluginAssembly;
                            pluginInfo.Name        = pluginData.Name;
                            pluginInfo.Description = pluginData.Description;
                            pluginInfo.TypeInfo    = pluginType;
                            pluginInfo.Guid        = pluginGuid;

                            //errorList.Add($"Plugin '{pluginInfo.Name}' ({pluginInfo.Guid}) loaded. Assembly: {pluginAssembly.FullName}");
                            pluginInfoList.Add(pluginInfo);
                        }
                        catch (Exception ex)
                        {
                            errorList.Add("Failed to instantiate type '{pluginType.FullName}'.");
                            errorList.Add(ex.ToString());

                            SessionLog.Error("Failed to instantiate type '{0}'. See the exception that follows.", pluginType.FullName);
                            SessionLog.Exception(ex);
                        }
                    }
                }
                else
                {
                    errorList.Add($"Failed to find any jsDAL Server plugins in the assembly '{pluginAssembly.Location}'. Make sure you have a public class available that derives from one of the plugin types.");
                }
            }
            else
            {
                errorList.Add($"Failed to find any jsDAL Server plugins in the assembly '{pluginAssembly.Location}'. Make sure you have a public class available that derives from one of the plugin types.");
            }

            return(errorList == null || errorList.Count == 0);
        }
Пример #9
0
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory, IHostApplicationLifetime applicationLifetime)
        {
            //app.UseDeveloperExceptionPage();

            // force instantiation on singletons

            {
                var pmInst = app.ApplicationServices.GetService <PluginLoader>();

                CommonNotificationThread.Instance = app.ApplicationServices.GetService <CommonNotificationThread>();

                BackgroundThreadPluginManager.Instance = app.ApplicationServices.GetService <BackgroundThreadPluginManager>();
                WorkerMonitor.Instance         = app.ApplicationServices.GetService <WorkerMonitor>();
                RealtimeMonitor.Instance       = app.ApplicationServices.GetService <RealtimeMonitor>();
                BackgroundTaskMonitor.Instance = app.ApplicationServices.GetService <BackgroundTaskMonitor>();

                ConnectionStringSecurity.Instance = app.ApplicationServices.GetService <ConnectionStringSecurity>();

                DotNetCoreCounterListener.Instance = app.ApplicationServices.GetService <DotNetCoreCounterListener>();
                DotNetCoreCounterListener.Instance.Start();


                {// More app startup stuff...but have a dependency on the singleton objects above. Can we move this somewhere else?
                    Log.Information("Initialising project object model");
                    // we can only initialise the Project structure once ConnectionStringSecurity exists
                    Settings.SettingsInstance.Instance.ProjectList.ForEach(p => p.AfterDeserializationInit());

                    Log.Information("Initialising plugin loader");
                    PluginLoader.Instance = pmInst;
                    PluginLoader.Instance.InitAsync().GetAwaiter().GetResult();

                    ServerMethodManager.RebuildCacheForAllApps();

                    Log.Information("Starting work spawner.");
                    WorkSpawner.Start();
                }
            }

            applicationLifetime.ApplicationStopped.Register(() =>
            {
                Log.Information("Application stopped");
            });

            applicationLifetime.ApplicationStopping.Register(() =>
            {
                Log.Information("Application is shutting down");
            });


            // app.Use(async (httpContext, next) =>
            // {
            //     //if (httpContext.Request.Path.Value.Contains("api/") && httpContext.Request.Method == "OPTIONS")
            //     if (httpContext.Request.Method.Equals("OPTIONS", StringComparison.OrdinalIgnoreCase))
            //     {
            //         httpContext.Response.Headers.Add("Access-Control-Max-Age", "600");
            //        // return;
            //     }
            //     await next();
            // });

            var webSocketOptions = new WebSocketOptions()
            {
                KeepAliveInterval = TimeSpan.FromSeconds(120),
                ReceiveBufferSize = 4 * 1024,
            };


            app.UseWebSockets(webSocketOptions);
            app.UseCors("CorsPolicy");


            // SPA (angular) route fallback
            app.Use(async(context, next) =>
            {
                await next();

                if (context.Response.StatusCode == 404 &&
                    !Path.HasExtension(context.Request.Path.Value) &&
                    !(context.Request.Path.Value?.ToLower().StartsWith("/api/") ?? false))
                {
                    context.Request.Path        = "/index.html";
                    context.Response.StatusCode = 200;

                    await next();
                }
            });


            /*****
             *          var mirrorSharpOptions = new MirrorSharpOptions()
             *          {
             *              SelfDebugEnabled = true,
             *              IncludeExceptionDetails = true,
             *              //SetOptionsFromClient = SetOptionsFromClientExtension()
             *              // CSharp = {
             *              //             MetadataReferences = ImmutableList.Create<MetadataReference>(all),
             *              //             CompilationOptions = compilationOptions
             *              //          },
             *              ExceptionLogger = new MirrorSharpExceptionLogger()
             *          }.SetupCSharp(cs =>
             *          {
             *              //cs.MetadataReferences = cs.MetadataReferences.Clear();
             *              //cs.AddMetadataReferencesFromFiles(all);
             *              cs.MetadataReferences = ImmutableList.Create<MetadataReference>(all);
             *              cs.CompilationOptions = compilationOptions;
             *
             *          });
             *
             *
             *          app.UseMirrorSharp(mirrorSharpOptions);
             */
            app.UseDefaultFiles();
            app.UseStaticFiles();

            // TODO: This outputs full request detail into log. Perhaps consider outputting this to a different detailed log
            //app.UseSerilogRequestLogging();
            app.UseSerilogRequestLogging(options =>
            {
                options.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                // Customize the message template
                //HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms
                options.MessageTemplate = "Req/Res: {ReqLen,7} {ResLen,7} {StatusCode} {Elapsed,7:0} ms {RequestMethod,4} {RequestPath}";

                //options.GetLevel = (httpContext, elapsed, ex) => Serilog.Events.LogEventLevel.Warning;


                // Attach additional properties to the request completion event
                options.EnrichDiagnosticContext = (diagnosticContext, httpContext) =>
                {
                    diagnosticContext.Set("ResLen", httpContext.Response.ContentLength ?? 0);
                    diagnosticContext.Set("ReqLen", httpContext.Request.ContentLength ?? 0);
                };
            });

            app.UseRouting();


            MetadataReference[] allMetadataReferences = null;

            try
            {
                allMetadataReferences = CSharpCompilerHelper.GetCommonMetadataReferences();

                var jsDALBasePluginPath = Path.GetFullPath("./plugins/jsdal-plugin.dll");

                if (File.Exists("./plugins/jsdal-plugin.dll"))
                {
                    Array.Resize(ref allMetadataReferences, allMetadataReferences.Length + 1);

                    allMetadataReferences[allMetadataReferences.Length - 1] = Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(jsDALBasePluginPath);
                }
                else
                {
                    Log.Error($"Failed to find base plugin assembly at {jsDALBasePluginPath}");
                    SessionLog.Error($"Failed to find base plugin assembly at {jsDALBasePluginPath}");
                }
            }
            catch (Exception mex)
            {
                Log.Error(mex, "Failed to compile collection of metadata references");
            }

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub <Hubs.HomeDashboardHub>("/main-stats");
                endpoints.MapHub <Hubs.WorkerDashboardHub>("/worker-hub");
                endpoints.MapHub <Hubs.Performance.RealtimeHub>("/performance-realtime-hub");
                endpoints.MapHub <Hubs.HeartBeat.HeartBeatHub>("/heartbeat");
                endpoints.MapHub <Hubs.BackgroundTaskHub>("/bgtasks-hub");
                endpoints.MapHub <Hubs.BackgroundPluginHub>("/bgplugin-hub");
                endpoints.MapHub <Hubs.ExecHub>("/exec-hub");

                if (allMetadataReferences?.Length > 0)
                {
                    var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,
                                                                          //            generalDiagnosticOption: ReportDiagnostic.Suppress
                                                                          specificDiagnosticOptions: new Dictionary <string, ReportDiagnostic>
                    {
                        { "CS1701", ReportDiagnostic.Suppress },                                     // Binding redirects
                        { "CS1702", ReportDiagnostic.Suppress },
                        { "CS1705", ReportDiagnostic.Suppress }
                    }
                                                                          );

                    var mirrorSharpOptions = new MirrorSharpOptions()
                    {
                        SelfDebugEnabled        = true,
                        IncludeExceptionDetails = true
                                                  //SetOptionsFromClient = SetOptionsFromClientExtension()
                                                  // CSharp = {
                                                  //             MetadataReferences = ImmutableList.Create<MetadataReference>(all),
                                                  //             CompilationOptions = compilationOptions
                                                  //          },
                                                  //   ExceptionLogger = new MirrorSharpExceptionLogger()
                    }.SetupCSharp(cs =>
                    {
                        //cs.MetadataReferences = cs.MetadataReferences.Clear();
                        //cs.AddMetadataReferencesFromFiles(all);
                        cs.MetadataReferences = ImmutableList.Create <MetadataReference>(allMetadataReferences);
                        cs.CompilationOptions = compilationOptions;
                    });

                    endpoints.MapMirrorSharp("/mirrorsharp", mirrorSharpOptions);
                }
                else
                {
                    Log.Warning("Mirrorsharp not started because of errors builiding up metadata references");
                }
            });

            app.UseAuthentication();
            app.UseWebSockets();
            app.UseCookiePolicy();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();

                // unhandled exceptions
                app.UseExceptionHandler(errorApp =>
                {
                    errorApp.Run(async context =>
                    {
                        try
                        {
                            var exceptionHandlerPathFeature = context.Features.Get <IExceptionHandlerPathFeature>();

                            var id = ExceptionLogger.LogException(exceptionHandlerPathFeature.Error, exceptionHandlerPathFeature.Path, "jsdal-server", null);

                            context.Response.StatusCode  = 500;
                            context.Response.ContentType = "text/plain";

                            await context.Response.WriteAsync($"Server error. Ref: {id}");
                            await context.Response.WriteAsync(new string(' ', 512)); // IE padding
                        }
                        catch (Exception ex)
                        {
                            Log.Error(ex, $"Failed to log unhandled exception because of:\r\n {ex.ToString()}");
                        }
                    });
                });
            }

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }