private static async Task <List <UserModule> > GetModulesFromDirectoriesParallelAsync(string[] directories) { var modTasks = directories.Where(dir => !dir.EndsWith("...ignore")).Select(async dir => { var files = Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories); UserModule mod = null; try { foreach (var file in files) { var asm = Assembly.LoadFrom(file); if (mod != null) { goto foundMod; } var startClasses = asm.GetTypes().Where(t => t.IsClass && t.BaseType == typeof(ModuleAPI.Module) && t.GetCustomAttribute <ApplicationHookAttribute>() != null ).ToList(); if (startClasses.Count <= 0) { continue; } var startupClass = startClasses[0]; mod = await UserModule.FromTypeAsync(startupClass); } foundMod: return(mod); } catch (Exception exc) { Logger.Log("Module loading error", exc); return(null); } }).ToList(); var foundModules = new List <UserModule>(); foreach (var modTask in modTasks) { if (modTask == null) { continue; } var um = await modTask; if (um != null) { foundModules.Add(um); } } return(foundModules); }
/* STATIC METHODS */ /// <summary> /// Find the user module responsible for handling the user input based on which Regex matched /// </summary> /// <param name="query">User input</param> /// <param name="selectedModule">Module responsible for handling the query</param> /// <param name="command">The command that was detected from user input</param> /// <param name="client">Was it a remote command?</param> /// <returns></returns> public static bool FindResponsibleUserModule(string query, out UserModule selectedModule, out Command command, TcpClient client = null) { selectedModule = null; command = null; if (string.IsNullOrWhiteSpace(query)) { return(false); } var selectedRegexKey = ""; var matchFound = false; var m = Regex.Match(query, "^(?<first>.+?)\\s+(?<rest>.+)$"); var firstWord = m.Groups["first"].Value; var rest = m.Groups["rest"].Value; var shortListModule = ModuleLoader.ModuleLoadOrder.Values.FirstOrDefault(val => val.Prefix == firstWord); if (shortListModule != null && shortListModule.Enabled) { foreach (var rgxs in shortListModule.RegisteredCommands) { if (matchFound) { break; } if (rgxs.Value.Match(rest).Success) { selectedRegexKey = rgxs.Key; selectedModule = shortListModule; matchFound = true; break; } } } //If a match is not found or the user input is invalid, select all user input text if (!matchFound || selectedModule == null || string.IsNullOrWhiteSpace(selectedRegexKey)) { return(false); } command = new Command(shortListModule.Prefix, shortListModule.RegisteredCommands[selectedRegexKey], rest, selectedRegexKey, client); return(true); }
/// <summary> /// Load all modules in the Module Directory /// </summary> public static void LoadAll() { ModuleLoadOrder = ModuleLoadOrder ?? new Dictionary <int, UserModule>(); ModuleLoadOrder?.Clear(); var sysModule = UserModule.FromType(typeof(SystemCommands)); ModuleLoadOrder.Add(ModuleLoadOrder.Count, sysModule); var directories = Directory.GetDirectories(ModuleDirectory, "*", SearchOption.TopDirectoryOnly); LoadingStarted?.Invoke(directories.Length); // Search through all directories and add user modules directories.ToList().ForEach(dir => { var um = GetModuleFromDirectory(dir); // If a module is detected, add it to the ModuleLoadOrder dictionary if (um != null) { var index = ModuleLoadOrder.Count + 1; var canUse = false; do { if (!ModuleLoadOrder.ContainsKey(index)) { canUse = true; ModuleLoadOrder.Add(index, um); ModuleLoaded?.Invoke(um); } else { index++; } } while(canUse == false); } }); LoadingEnded?.Invoke(); }
public static async Task LoadAllAsync() { ModuleLoadOrder = ModuleLoadOrder ?? new Dictionary <int, UserModule>(); ModuleLoadOrder?.Clear(); var sysModule = await UserModule.FromTypeAsync(typeof(SystemCommands)); ModuleLoadOrder.Add(ModuleLoadOrder.Count, sysModule); var directories = Directory.GetDirectories(ModuleDirectory, "*", SearchOption.TopDirectoryOnly); LoadingStarted?.Invoke(directories.Length); var foundModules = await GetModulesFromDirectoriesParallelAsync(directories); foundModules.ForEach(um => { var index = ModuleLoadOrder.Count + 1; var canUse = false; do { if (!ModuleLoadOrder.ContainsKey(index)) { canUse = true; ModuleLoadOrder.Add(index, um); ModuleLoaded?.Invoke(um); } else { index++; } } while(canUse == false); }); LoadingEnded?.Invoke(); }
/// <summary> /// Load a module anywhere inside a specific directory /// </summary> /// <param name="directory">Location of the module</param> /// <returns></returns> private static UserModule GetModuleFromDirectory(string directory) { var files = Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories); UserModule mod = null; // Load each *.dll file found in the directory files.ToList().ForEach(async file => { try { var asm = Assembly.LoadFrom(file); // Search for a type in the loaded assembly that:- // 1. Is a child of the Module class // 2. Has the ApplicationHook attribute (that can only be applied to one class) var startClasses = asm.GetTypes().Where(t => t.IsClass && t.BaseType == typeof(ModuleAPI.Module) && t.GetCustomAttribute <ApplicationHookAttribute>() != null ).ToList(); // If any class meeting these conditions is found, // Store that as the 'Startup Class' i.e. the class // which will recieve commands through Project Butler if (startClasses.Count > 0) { var startupClass = startClasses[0]; mod = await UserModule.FromTypeAsync(startupClass); } } catch (Exception exc) { Logger.Log("Module loading error", exc); } }); return(mod); }