Esempio n. 1
0
        public static async Task <List <T> > LoadSingle <T>(string file, ILogger logger, IConfiguration config, bool isInDevMode)
        {
            var list = new List <T>();

            try
            {
                var fileInfo = new FileInfo(file);
                var folder   = fileInfo.DirectoryName;
                logger.LogDebug($"Loading file {file} and check for interfaces");

                AssemblyLoader loader;
                if (isInDevMode)
                {
                    loader = new AssemblyLoader(folder,
                                                new FileInfo(Assembly.GetCallingAssembly().Location).DirectoryName, folder);
                }
                else
                {
                    loader = new AssemblyLoader(folder, folder);
                }

                Func <AssemblyLoadContext, AssemblyName, Assembly> assemblyLoader = (context, name) =>
                {
                    logger.LogDebug($"Try to load assembly {name} for {file}");
                    // avoid loading *.resources dll, because of: https://github.com/dotnet/coreclr/issues/8416
                    if (name.Name.EndsWith("resources"))
                    {
                        return(null);
                    }

                    logger.LogDebug($"try to load assembly from {folder}");
                    var foundDll =
                        Directory.GetFileSystemEntries(folder, name.Name + ".dll", SearchOption.AllDirectories);
                    if (foundDll.Any())
                    {
                        return(context.LoadFromAssemblyPath(foundDll[0]));
                    }

                    var secondPath = new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName;
                    logger.LogDebug($"try to load assembly from second path: {secondPath}");
                    foundDll = Directory.GetFileSystemEntries(secondPath, name.Name + ".dll",
                                                              SearchOption.AllDirectories);
                    if (foundDll.Any())
                    {
                        return(context.LoadFromAssemblyPath(foundDll[0]));
                    }

                    var dependencies = DependencyContext.Default.RuntimeLibraries;
                    foreach (var library in dependencies)
                    {
                        if (IsCandidateLibrary(library, name))
                        {
                            return(loader.LoadAssembly(name));
                        }
                    }


                    return(context.LoadFromAssemblyName(name));
                };
                AssemblyLoadContext.Default.Resolving += assemblyLoader;

                Assembly assembly;
                try
                {
                    assembly = Assembly.LoadFrom(file);
                }
                catch (Exception e)
                {
                    logger.LogError(e, $"Could not load assembly {file}");
                    return(list);
                }
                finally
                {
                    AssemblyLoadContext.Default.Resolving -= assemblyLoader;
                }

                var resources = assembly.GetManifestResourceNames()
                                .SingleOrDefault(a => a.EndsWith("automatica-manifest.json"));

                if (resources == null)
                {
                    logger.LogWarning($"{file} does not contain a manifest files");
                    throw new NoManifestFoundException();
                }

                var manifest = Common.Update.Plugin.GetEmbeddedPluginManifest(logger, assembly);
                await using var database = new AutomaticaContext(config);

                var plugin = database.Plugins.SingleOrDefault(a => a.PluginGuid == manifest.Automatica.PluginGuid);
                if (plugin == null)
                {
                    plugin = new Plugin
                    {
                        ObjId         = Guid.NewGuid(),
                        Name          = manifest.Automatica.Name,
                        ComponentName = manifest.Automatica.ComponentName,
                        PluginGuid    = manifest.Automatica.PluginGuid,
                        PluginType    = manifest.Automatica.Type == "driver" ? PluginType.Driver : PluginType.Logic,
                        Version       = manifest.Automatica.PluginVersion.ToString(),
                        Loaded        = true
                    };
                    database.Plugins.Add(plugin);
                }
                else
                {
                    plugin.Version = manifest.Automatica.PluginVersion.ToString();
                    plugin.Loaded  = true;
                    database.Plugins.Update(plugin);
                }

                await database.SaveChangesAsync();

                foreach (var ti in assembly.ExportedTypes)
                {
                    if (ti.IsSubclassOf(typeof(T)))
                    {
                        if (ti.IsAbstract)
                        {
                            continue;
                        }

                        if (assembly.CreateInstance(ti.FullName ?? throw new InvalidOperationException()) is T factory)
                        {
                            logger.LogDebug($"Found {typeof(T)} in {ti}...");
                            list.Add(factory);
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException e)
            {
                var builder = new StringBuilder();
                foreach (var ex in e.LoaderExceptions)
                {
                    builder.Append($"{ex}");
                }

                logger.LogError(e.InnerException, $"Could not load {typeof(T)} from {file}...{builder}\n");
            }
            catch (NoManifestFoundException)
            {
                // ignore
            }
            catch (Exception e)
            {
                logger.LogError(e, $"Could not load {typeof(T)}...{e}");
            }
            return(list);
        }
Esempio n. 2
0
        internal async Task <IEnumerable <RulePage> > Save(List <RulePage> data)
        {
            await using var dbContext = new AutomaticaContext(_config);
            {
                var transaction = await dbContext.Database.BeginTransactionAsync();

                try
                {
                    foreach (var page in data)
                    {
                        var isNewPage = false;
                        var dbPage    = dbContext.RulePages.SingleOrDefault(a => a.ObjId == page.ObjId);

                        if (dbPage == null)
                        {
                            dbPage    = page;
                            isNewPage = true;
                        }
                        else
                        {
                            dbContext.Entry(dbPage).State = EntityState.Detached;
                        }

                        if (page.Description == null)
                        {
                            page.Description = "";
                        }

                        foreach (var ruleInstance in page.RuleInstance)
                        {
                            if (ruleInstance.Description == null)
                            {
                                ruleInstance.Description = "";
                            }

                            foreach (var ruleInterface in ruleInstance.RuleInterfaceInstance)
                            {
                                ruleInterface.This2RuleInterfaceTemplateNavigation = null;

                                if (dbContext.RuleInterfaceInstances.AsNoTracking()
                                    .SingleOrDefault(a => a.ObjId == ruleInterface.ObjId) != null)
                                {
                                    dbContext.Entry(ruleInterface).State = EntityState.Modified;
                                    dbContext.RuleInterfaceInstances.Update(ruleInterface);
                                }
                                else
                                {
                                    dbContext.RuleInterfaceInstances.Add(ruleInterface);
                                    dbContext.Entry(ruleInterface).State = EntityState.Added;
                                }
                            }

                            ruleInstance.This2RulePage = page.ObjId;

                            ruleInstance.This2RuleTemplate           = ruleInstance.This2RuleTemplateNavigation.ObjId;
                            ruleInstance.This2RuleTemplateNavigation = null;

                            if (dbContext.RuleInstances.AsNoTracking()
                                .SingleOrDefault(a => a.ObjId == ruleInstance.ObjId) == null)
                            {
                                dbContext.RuleInstances.Add(ruleInstance);
                                dbContext.Entry(ruleInstance).State = EntityState.Added;
                            }
                            else
                            {
                                dbContext.Entry(ruleInstance).State = EntityState.Modified;
                                dbContext.RuleInstances.Update(ruleInstance);
                            }
                        }

                        foreach (var node in page.NodeInstance2RulePage)
                        {
                            if (dbContext.NodeInstance2RulePages.AsNoTracking()
                                .SingleOrDefault(a => a.ObjId == node.ObjId) == null)
                            {
                                node.This2NodeInstanceNavigation = null;
                                await dbContext.AddAsync(node);

                                dbContext.Entry(node).State = EntityState.Added;
                            }
                            else
                            {
                                dbContext.Entry(node).State = EntityState.Modified;
                                dbContext.NodeInstance2RulePages.Update(node);
                            }
                        }

                        foreach (var link in page.Link)
                        {
                            link.This2RulePage = dbPage.ObjId;


                            link.This2RuleInterfaceInstanceOutputNavigation = null;
                            link.This2RuleInterfaceInstanceInputNavigation  = null;
                            link.This2NodeInstance2RulePageInputNavigation  = null;
                            link.This2NodeInstance2RulePageOutputNavigation = null;

                            if (dbContext.Links.AsNoTracking().SingleOrDefault(a => a.ObjId == link.ObjId) == null)
                            {
                                await dbContext.AddAsync(link);

                                dbContext.Entry(link).State = EntityState.Added;
                            }
                            else
                            {
                                dbContext.Update(link);
                                dbContext.Entry(link).State = EntityState.Modified;
                            }
                        }

                        if (isNewPage)
                        {
                            dbContext.Entry(page).State = EntityState.Added;
                            await dbContext.RulePages.AddAsync(page);
                        }
                        else
                        {
                            dbContext.Entry(page).State = EntityState.Modified;
                            dbContext.RulePages.Update(page);
                        }
                    }

                    await dbContext.SaveChangesAsync(true);

                    foreach (var page in data)
                    {
                        var removedRules = from c in dbContext.RuleInstances
                                           where !(from o in page.RuleInstance select o.ObjId).Contains(c.ObjId) &&
                                           c.This2RulePage == page.ObjId
                                           select c;

                        var removedRulesList = removedRules.ToList();
                        dbContext.RuleInstances.RemoveRange(removedRulesList);


                        var removedLinks = from c in dbContext.Links
                                           where !(from o in page.Link select o.ObjId).Contains(c.ObjId) &&
                                           c.This2RulePage == page.ObjId
                                           select c;

                        dbContext.Links.RemoveRange(removedLinks);



                        var removedNodes = (from c in dbContext.NodeInstance2RulePages
                                            where !(from o in page.NodeInstance2RulePage select o.ObjId).Contains(c.ObjId) &&
                                            c.This2RulePage == page.ObjId
                                            select c).ToList();

                        dbContext.NodeInstance2RulePages.RemoveRange(removedNodes);
                    }

                    var removedPages = (from c in dbContext.RulePages
                                        where !(from o in data select o.ObjId).Contains(c.ObjId)
                                        select c).ToList();

                    foreach (var removedPage in removedPages)
                    {
                        var removedRules = from c in dbContext.RuleInstances
                                           where c.This2RulePage == removedPage.ObjId
                                           select c;
                        dbContext.RuleInstances.RemoveRange(removedRules);

                        var removedLinks = from c in dbContext.Links
                                           where c.This2RulePage == removedPage.ObjId
                                           select c;

                        dbContext.Links.RemoveRange(removedLinks);

                        var removedNodes = (from c in dbContext.NodeInstance2RulePages
                                            where c.This2RulePage == removedPage.ObjId
                                            select c).ToList();

                        dbContext.NodeInstance2RulePages.RemoveRange(removedNodes);
                    }

                    dbContext.RemoveRange(removedPages);

                    await dbContext.SaveChangesAsync(true);

                    await transaction.CommitAsync();

                    _logicCacheFacade.ClearInstances();
                }
                catch (Exception e)
                {
                    SystemLogger.Instance.LogError(e, "Could not save data");
                    await transaction.RollbackAsync();

                    throw;
                }
            }
            return(GetPages());
        }