commit bae09d5ba4b66a5273c1499d20f9f5a1e45e5c11 Author: Sergey Gut Date: Sun Mar 1 22:09:14 2020 +0400 :construction: Core re-init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..587fcbc --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +bin/ +obj/ +/packages/ + +.idea +.DS_Store + +appsettings.json diff --git a/Core/Core.cs b/Core/Core.cs new file mode 100644 index 0000000..3585bb8 --- /dev/null +++ b/Core/Core.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.Extensions.Configuration; + +namespace Kruzya.TelegramBot.Core +{ + public sealed class Core + { + /// + /// The Core API version. + /// + public UInt32 ApiVersion => 1; + + /// + /// The array that contains all modules instances. + /// + public Module[] Modules => _modules.ToArray(); + + /// + /// The current bot configuration. + /// + public IConfiguration Configuration => _configuration; + + #region Private properties + + /// + /// The array that contains all modules instances. + /// + private List _modules = new List(); + + /// + /// The current bot configuration. + /// + private IConfiguration _configuration; + + /// + /// The all directories for loading our module assemblies. + /// + private List _directories + { + get + { + // For start, load all assemblies in required directory. + // And register in internal temporary array. + var modulesDirectory = new List(new string[] + { + Path.Join(Assembly.GetExecutingAssembly().Location, "modules"), + Path.Join(Environment.CurrentDirectory, "modules") + }); + + // Also lookup load directories from config. + modulesDirectory.AddRange(_configuration.GetSection("ModuleDirectories").GetChildren().Select(q => q.Value) + .ToList()); + + return modulesDirectory; + } + } + + #endregion + + public Core(IConfiguration configuration) + { + _configuration = configuration; + + Start(); + } + + /// + /// Initializes all required submodules. + /// + private void Start() + { + var types = new List(); + foreach (var directory in _directories) + { + if (!Directory.Exists(directory)) + { + continue; + } + + foreach (var file in Directory.EnumerateFiles(directory, "*.dll", SearchOption.AllDirectories)) + { + var assemblyTypes = LoadAssembly(file); + if (assemblyTypes == null) + { + continue; + } + + types.AddRange(assemblyTypes); + } + } + } + + /// + /// Loads the assembly and appends all Module types to list. + /// + /// The full path to assembly file + /// if success, null otherwise. + private IEnumerable LoadAssembly(string path) + { + Assembly assembly; + try + { + assembly = Assembly.LoadFile(path); + } + catch (Exception) + { + // don't load any invalid module. + return null; + } + + return assembly.GetExportedTypes().Where(x => !x.IsAbstract && x.IsSubclassOf(typeof(Module))); + } + + /// + /// Ensures if module is loaded and started. Note that call can change module event chain. + /// + /// The Module type. + /// Module instance. + public T EnsureLoaded() + where T : Module + { + return (T) EnsureLoaded(typeof(T)); + } + + /// + /// Ensures if module is loaded and started. Note that call can change module event chain. + /// + /// The Module type. + /// Module instance. + /// The given type is not extends the Module class + public Module EnsureLoaded(Type moduleType) + { + if (!moduleType.IsSubclassOf(typeof(Module))) + { + throw new Exception("Received incorrect module type"); + } + + var module = _modules.FirstOrDefault(module => module.GetType() == moduleType); + if (module == null) + { + module = (Module) Activator.CreateInstance(moduleType, this); + _modules.Add(module); + } + + return module; + } + } +} diff --git a/Core/Core.csproj b/Core/Core.csproj new file mode 100644 index 0000000..2d8933e --- /dev/null +++ b/Core/Core.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + TelegramBot + Kruzya.TelegramBot.Core + + + + + + + diff --git a/Core/Module.cs b/Core/Module.cs new file mode 100644 index 0000000..69828d7 --- /dev/null +++ b/Core/Module.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Kruzya.TelegramBot.Core +{ + public abstract class Module + { + protected readonly Core Core; + protected IConfiguration Configuration => Core.Configuration; + + public Module(Core core) + { + Core = core; + } + + public virtual void ConfigureServices(IServiceCollection services) + { + } + + public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + } + + /// + /// Ensures if module is loaded and started. Note that call can change module event chain. + /// + /// The Module type. + /// Module instance. + protected T EnsureLoaded() where T : Module + { + return (T) Core.EnsureLoaded(typeof(T)); + } + } +} diff --git a/Core/ModuleArrayExtension.cs b/Core/ModuleArrayExtension.cs new file mode 100644 index 0000000..738804c --- /dev/null +++ b/Core/ModuleArrayExtension.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; + +namespace Kruzya.TelegramBot.Core +{ + internal static class ModuleArrayExtension + { + public static void ConfigureServices(this Module[] modules, IServiceCollection services) + { + foreach (var module in modules) module.ConfigureServices(services); + } + + public static void Configure(this Module[] modules, IApplicationBuilder app, IWebHostEnvironment env) + { + foreach (var module in modules) module.Configure(app, env); + } + } +} diff --git a/Core/Program.cs b/Core/Program.cs new file mode 100644 index 0000000..f69b4b9 --- /dev/null +++ b/Core/Program.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Kruzya.TelegramBot.Core +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } +} diff --git a/Core/Properties/launchSettings.json b/Core/Properties/launchSettings.json new file mode 100644 index 0000000..5842174 --- /dev/null +++ b/Core/Properties/launchSettings.json @@ -0,0 +1,27 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:28272", + "sslPort": 44341 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Core": { + "commandName": "Project", + "launchBrowser": false, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Core/Startup.cs b/Core/Startup.cs new file mode 100644 index 0000000..31fa4d0 --- /dev/null +++ b/Core/Startup.cs @@ -0,0 +1,36 @@ +using BotFramework; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; + +namespace Kruzya.TelegramBot.Core +{ + public class Startup + { + private Core _core; + + public Startup(IConfiguration configuration) + { + // TODO: add Core to DI. + _core = new Core(configuration); + } + + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddTelegramBot(); + services.AddLogging(builder => builder.AddConsole()); + + _core.Modules.ConfigureServices(services); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + _core.Modules.Configure(app, env); + } + } +} diff --git a/Core/appsettings.Development.json b/Core/appsettings.Development.json new file mode 100644 index 0000000..8983e0f --- /dev/null +++ b/Core/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/Kruzya.TelegramBot.sln b/Kruzya.TelegramBot.sln new file mode 100644 index 0000000..54db1d5 --- /dev/null +++ b/Kruzya.TelegramBot.sln @@ -0,0 +1,18 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{B41CB31A-641E-4079-87ED-5CE310B2D8C1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B41CB31A-641E-4079-87ED-5CE310B2D8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B41CB31A-641E-4079-87ED-5CE310B2D8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B41CB31A-641E-4079-87ED-5CE310B2D8C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B41CB31A-641E-4079-87ED-5CE310B2D8C1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + EndGlobalSection +EndGlobal