mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 00:34:26 -05:00 
			
		
		
		
	Re-added medusa system, but untested
This commit is contained in:
		@@ -132,7 +132,6 @@ public sealed class Bot : IBot
 | 
			
		||||
        foreach (var a in _loadedAssemblies)
 | 
			
		||||
        {
 | 
			
		||||
            svcs.AddConfigServices(a)
 | 
			
		||||
                .AddConfigMigrators(a)
 | 
			
		||||
                .AddLifetimeServices(a);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -157,9 +156,6 @@ public sealed class Bot : IBot
 | 
			
		||||
        Services = svcs;
 | 
			
		||||
        Services.GetRequiredService<IBehaviorHandler>().Initialize();
 | 
			
		||||
 | 
			
		||||
        if (Client.ShardId == 0)
 | 
			
		||||
            ApplyConfigMigrations();
 | 
			
		||||
 | 
			
		||||
        foreach (var a in _loadedAssemblies)
 | 
			
		||||
        {
 | 
			
		||||
            LoadTypeReaders(a);
 | 
			
		||||
@@ -169,14 +165,6 @@ public sealed class Bot : IBot
 | 
			
		||||
        Log.Information("All services loaded in {ServiceLoadTime:F2}s", sw.Elapsed.TotalSeconds);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void ApplyConfigMigrations()
 | 
			
		||||
    {
 | 
			
		||||
        // execute all migrators
 | 
			
		||||
        var migrators = Services.GetServices<IConfigMigrator>();
 | 
			
		||||
        foreach (var migrator in migrators)
 | 
			
		||||
            migrator.EnsureMigrated();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void LoadTypeReaders(Assembly assembly)
 | 
			
		||||
    {
 | 
			
		||||
        var filteredTypes = assembly.GetExportedTypes()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,27 @@
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using Ninject;
 | 
			
		||||
using Ninject.Activation;
 | 
			
		||||
using Ninject.Activation.Caching;
 | 
			
		||||
using Ninject.Modules;
 | 
			
		||||
using Ninject.Planning;
 | 
			
		||||
using DryIoc;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Text.Json;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Medusa;
 | 
			
		||||
 | 
			
		||||
public sealed class MedusaNinjectModule : NinjectModule
 | 
			
		||||
public interface IIocModule
 | 
			
		||||
{
 | 
			
		||||
    public override string Name { get; }
 | 
			
		||||
    public string Name { get; }
 | 
			
		||||
    public void Load();
 | 
			
		||||
    public void Unload();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public sealed class MedusaNinjectIocModule : IIocModule, IDisposable
 | 
			
		||||
{
 | 
			
		||||
    public string Name { get; }
 | 
			
		||||
    private volatile bool isLoaded = false;
 | 
			
		||||
    private readonly Dictionary<Type, Type[]> _types;
 | 
			
		||||
    private readonly IContainer _cont;
 | 
			
		||||
 | 
			
		||||
    public MedusaNinjectModule(Assembly assembly, string name)
 | 
			
		||||
    public MedusaNinjectIocModule(IContainer cont, Assembly assembly, string name)
 | 
			
		||||
    {
 | 
			
		||||
        Name = name;
 | 
			
		||||
        _cont = cont;
 | 
			
		||||
        _types = assembly.GetExportedTypes()
 | 
			
		||||
            .Where(t => t.IsClass)
 | 
			
		||||
            .Where(t => t.GetCustomAttribute<svcAttribute>() is not null)
 | 
			
		||||
@@ -24,7 +29,7 @@ public sealed class MedusaNinjectModule : NinjectModule
 | 
			
		||||
                type => type.GetInterfaces().ToArray());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void Load()
 | 
			
		||||
    public void Load()
 | 
			
		||||
    {
 | 
			
		||||
        if (isLoaded)
 | 
			
		||||
            return;
 | 
			
		||||
@@ -32,59 +37,27 @@ public sealed class MedusaNinjectModule : NinjectModule
 | 
			
		||||
        foreach (var (type, data) in _types)
 | 
			
		||||
        {
 | 
			
		||||
            var attribute = type.GetCustomAttribute<svcAttribute>()!;
 | 
			
		||||
            var scope = GetScope(attribute.Lifetime);
 | 
			
		||||
 | 
			
		||||
            Bind(type)
 | 
			
		||||
                .ToSelf()
 | 
			
		||||
                .InScope(scope);
 | 
			
		||||
            var reuse = attribute.Lifetime == Lifetime.Singleton
 | 
			
		||||
                ? Reuse.Singleton
 | 
			
		||||
                : Reuse.Transient;
 | 
			
		||||
            
 | 
			
		||||
            foreach (var inter in data)
 | 
			
		||||
            {
 | 
			
		||||
                Bind(inter)
 | 
			
		||||
                    .ToMethod(x => x.Kernel.Get(type))
 | 
			
		||||
                    .InScope(scope);
 | 
			
		||||
            }
 | 
			
		||||
            _cont.RegisterMany([type], reuse);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        isLoaded = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Func<IContext, object?> GetScope(Lifetime lt)
 | 
			
		||||
        => _ => lt switch
 | 
			
		||||
        {
 | 
			
		||||
            Lifetime.Singleton => this,
 | 
			
		||||
            Lifetime.Transient => null,
 | 
			
		||||
            _ => null,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    public override void Unload()
 | 
			
		||||
    public void Unload()
 | 
			
		||||
    {
 | 
			
		||||
        if (!isLoaded)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var planner = (RemovablePlanner)Kernel!.Components.Get<IPlanner>();
 | 
			
		||||
        var cache = Kernel.Components.Get<ICache>();
 | 
			
		||||
        foreach (var binding in this.Bindings)
 | 
			
		||||
        
 | 
			
		||||
        foreach (var type in _types.Keys)
 | 
			
		||||
        {
 | 
			
		||||
            Kernel.RemoveBinding(binding);
 | 
			
		||||
            _cont.Unregister(type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (var type in _types.SelectMany(x => x.Value).Concat(_types.Keys))
 | 
			
		||||
        {
 | 
			
		||||
            var binds = Kernel.GetBindings(type);
 | 
			
		||||
 | 
			
		||||
            if (!binds.Any())
 | 
			
		||||
            {
 | 
			
		||||
                Unbind(type);
 | 
			
		||||
                
 | 
			
		||||
                planner.RemovePlan(type);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Bindings.Clear();
 | 
			
		||||
 | 
			
		||||
        cache.Clear(this);
 | 
			
		||||
        
 | 
			
		||||
        _types.Clear();
 | 
			
		||||
        
 | 
			
		||||
        // in case the library uses System.Text.Json
 | 
			
		||||
@@ -95,4 +68,7 @@ public sealed class MedusaNinjectModule : NinjectModule
 | 
			
		||||
        
 | 
			
		||||
        isLoaded = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Dispose()
 | 
			
		||||
        => _types.Clear();
 | 
			
		||||
}
 | 
			
		||||
@@ -4,8 +4,6 @@ using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using Nadeko.Common.Medusa;
 | 
			
		||||
using Nadeko.Medusa.Adapters;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using Ninject;
 | 
			
		||||
using Ninject.Modules;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using System.Globalization;
 | 
			
		||||
@@ -21,7 +19,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
    private readonly IBehaviorHandler _behHandler;
 | 
			
		||||
    private readonly IPubSub _pubSub;
 | 
			
		||||
    private readonly IMedusaConfigService _medusaConfig;
 | 
			
		||||
    private readonly IContainer _kernel;
 | 
			
		||||
    private readonly IContainer _cont;
 | 
			
		||||
 | 
			
		||||
    private readonly ConcurrentDictionary<string, ResolvedMedusa> _resolved = new();
 | 
			
		||||
    private readonly SemaphoreSlim _lock = new SemaphoreSlim(1, 1);
 | 
			
		||||
@@ -35,7 +33,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
 | 
			
		||||
    public MedusaLoaderService(
 | 
			
		||||
        CommandService cmdService,
 | 
			
		||||
        IContainer kernel,
 | 
			
		||||
        IContainer cont,
 | 
			
		||||
        IBehaviorHandler behHandler,
 | 
			
		||||
        IPubSub pubSub,
 | 
			
		||||
        IMedusaConfigService medusaConfig)
 | 
			
		||||
@@ -44,7 +42,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        _behHandler = behHandler;
 | 
			
		||||
        _pubSub = pubSub;
 | 
			
		||||
        _medusaConfig = medusaConfig;
 | 
			
		||||
        _kernel = kernel;
 | 
			
		||||
        _cont = cont;
 | 
			
		||||
 | 
			
		||||
        // has to be done this way to support this feature on sharded bots
 | 
			
		||||
        _pubSub.Sub(_loadKey, async name => await InternalLoadAsync(name));
 | 
			
		||||
@@ -200,7 +198,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
            if (LoadAssemblyInternal(safeName,
 | 
			
		||||
                    out var ctx,
 | 
			
		||||
                    out var snekData,
 | 
			
		||||
                    out var kernelModule,
 | 
			
		||||
                    out var iocModule,
 | 
			
		||||
                    out var strings,
 | 
			
		||||
                    out var typeReaders))
 | 
			
		||||
            {
 | 
			
		||||
@@ -219,7 +217,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
                            await sub.Instance.InitializeAsync();
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        var module = await LoadModuleInternalAsync(name, point, strings, kernelModule);
 | 
			
		||||
                        var module = await LoadModuleInternalAsync(name, point, strings, iocModule);
 | 
			
		||||
                        moduleInfos.Add(module);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
@@ -240,7 +238,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
                    typeReaders,
 | 
			
		||||
                    execs)
 | 
			
		||||
                {
 | 
			
		||||
                    KernelModule = kernelModule
 | 
			
		||||
                    IocModule = iocModule
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -273,11 +271,11 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        var behs = new List<ICustomBehavior>();
 | 
			
		||||
        foreach (var snek in snekData)
 | 
			
		||||
        {
 | 
			
		||||
            behs.Add(new BehaviorAdapter(new(snek.Instance), strings, _kernel));
 | 
			
		||||
            behs.Add(new BehaviorAdapter(new(snek.Instance), strings, _cont));
 | 
			
		||||
 | 
			
		||||
            foreach (var sub in snek.Subsneks)
 | 
			
		||||
            {
 | 
			
		||||
                behs.Add(new BehaviorAdapter(new(sub.Instance), strings, _kernel));
 | 
			
		||||
                behs.Add(new BehaviorAdapter(new(sub.Instance), strings, _cont));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -315,7 +313,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        string safeName,
 | 
			
		||||
        [NotNullWhen(true)] out WeakReference<MedusaAssemblyLoadContext>? ctxWr,
 | 
			
		||||
        [NotNullWhen(true)] out IReadOnlyCollection<SnekInfo>? snekData,
 | 
			
		||||
        [NotNullWhen(true)] out INinjectModule? ninjectModule,
 | 
			
		||||
        [NotNullWhen(true)] out IIocModule? iocModule,
 | 
			
		||||
        out IMedusaStrings strings,
 | 
			
		||||
        out Dictionary<Type, TypeReader> typeReaders)
 | 
			
		||||
    {
 | 
			
		||||
@@ -337,18 +335,15 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        ctx.LoadDependencies(a);
 | 
			
		||||
 | 
			
		||||
        // load services
 | 
			
		||||
        ninjectModule = new MedusaNinjectModule(a, safeName);
 | 
			
		||||
        
 | 
			
		||||
        // todo medusa won't work, uncomment
 | 
			
		||||
        // _kernel.Load(ninjectModule);
 | 
			
		||||
        iocModule = new MedusaNinjectIocModule(_cont, a, safeName);
 | 
			
		||||
        iocModule.Load();
 | 
			
		||||
        
 | 
			
		||||
        var sis = LoadSneksFromAssembly(safeName, a);
 | 
			
		||||
        typeReaders = LoadTypeReadersFromAssembly(a, strings);
 | 
			
		||||
        
 | 
			
		||||
        if (sis.Count == 0)
 | 
			
		||||
        {
 | 
			
		||||
            // todo uncomment
 | 
			
		||||
            // _kernel.Unload(safeName);
 | 
			
		||||
            iocModule.Unload();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -375,12 +370,12 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        var typeReaders = new Dictionary<Type, TypeReader>();
 | 
			
		||||
        foreach (var parserType in paramParsers)
 | 
			
		||||
        {
 | 
			
		||||
            var parserObj = ActivatorUtilities.CreateInstance(_kernel, parserType);
 | 
			
		||||
            var parserObj = ActivatorUtilities.CreateInstance(_cont, parserType);
 | 
			
		||||
 | 
			
		||||
            var targetType = parserType.BaseType!.GetGenericArguments()[0];
 | 
			
		||||
            var typeReaderInstance = (TypeReader)Activator.CreateInstance(
 | 
			
		||||
                typeof(ParamParserAdapter<>).MakeGenericType(targetType),
 | 
			
		||||
                args: new[] { parserObj, strings, _kernel })!;
 | 
			
		||||
                args: new[] { parserObj, strings, _cont })!;
 | 
			
		||||
 | 
			
		||||
            typeReaders.Add(targetType, typeReaderInstance);
 | 
			
		||||
        }
 | 
			
		||||
@@ -393,7 +388,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        string medusaName,
 | 
			
		||||
        SnekInfo snekInfo,
 | 
			
		||||
        IMedusaStrings strings,
 | 
			
		||||
        INinjectModule services)
 | 
			
		||||
        IIocModule services)
 | 
			
		||||
    {
 | 
			
		||||
        var module = await _cmdService.CreateModuleAsync(snekInfo.Instance.Prefix,
 | 
			
		||||
            CreateModuleFactory(medusaName, snekInfo, strings, services));
 | 
			
		||||
@@ -406,7 +401,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        string medusaName,
 | 
			
		||||
        SnekInfo snekInfo,
 | 
			
		||||
        IMedusaStrings strings,
 | 
			
		||||
        INinjectModule kernelModule)
 | 
			
		||||
        IIocModule iocModule)
 | 
			
		||||
        => mb =>
 | 
			
		||||
        {
 | 
			
		||||
            var m = mb.WithName(snekInfo.Name);
 | 
			
		||||
@@ -427,7 +422,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach (var subInfo in snekInfo.Subsneks)
 | 
			
		||||
                m.AddModule(subInfo.Instance.Prefix, CreateModuleFactory(medusaName, subInfo, strings, kernelModule));
 | 
			
		||||
                m.AddModule(subInfo.Instance.Prefix, CreateModuleFactory(medusaName, subInfo, strings, iocModule));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    private static readonly RequireContextAttribute _reqGuild = new RequireContextAttribute(ContextType.Guild);
 | 
			
		||||
@@ -511,7 +506,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var paramObjs = ParamObjs(contextType, cmdData, parameters, context, svcs, _kernel, strings);
 | 
			
		||||
            var paramObjs = ParamObjs(contextType, cmdData, parameters, context, svcs, _cont, strings);
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
@@ -605,12 +600,11 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
            await DisposeSnekInstances(lsi);
 | 
			
		||||
 | 
			
		||||
            var lc = lsi.LoadContext;
 | 
			
		||||
            var km = lsi.KernelModule;
 | 
			
		||||
            lsi.KernelModule = null!;
 | 
			
		||||
           
 | 
			
		||||
            // todo uncomment
 | 
			
		||||
            // _kernel.Unload(km.Name);
 | 
			
		||||
            var km = lsi.IocModule;
 | 
			
		||||
            
 | 
			
		||||
            lsi.IocModule.Unload();
 | 
			
		||||
            lsi.IocModule = null!;
 | 
			
		||||
           
 | 
			
		||||
            if (km is IDisposable d)
 | 
			
		||||
                d.Dispose();
 | 
			
		||||
            
 | 
			
		||||
@@ -748,7 +742,7 @@ public sealed class MedusaLoaderService : IMedusaLoaderService, IReadyExecutor,
 | 
			
		||||
        var filters = type.GetCustomAttributes<FilterAttribute>(true)
 | 
			
		||||
                          .ToArray();
 | 
			
		||||
 | 
			
		||||
        var instance = (Snek)ActivatorUtilities.CreateInstance(_kernel, type);
 | 
			
		||||
        var instance = (Snek)ActivatorUtilities.CreateInstance(_cont, type);
 | 
			
		||||
 | 
			
		||||
        var module = new SnekInfo(instance.Name,
 | 
			
		||||
            parentData,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,4 @@
 | 
			
		||||
using NadekoBot.Medusa;
 | 
			
		||||
using Ninject.Modules;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Medusa;
 | 
			
		||||
 | 
			
		||||
@@ -13,5 +11,5 @@ public sealed record ResolvedMedusa(
 | 
			
		||||
    IReadOnlyCollection<ICustomBehavior> Execs
 | 
			
		||||
)
 | 
			
		||||
{
 | 
			
		||||
    public required INinjectModule KernelModule { get; set; }
 | 
			
		||||
    public required IIocModule IocModule { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,122 +0,0 @@
 | 
			
		||||
//-------------------------------------------------------------------------------
 | 
			
		||||
// <copyright file="Planner.cs" company="Ninject Project Contributors">
 | 
			
		||||
//   Copyright (c) 2007-2009, Enkari, Ltd.
 | 
			
		||||
//   Copyright (c) 2009-2011 Ninject Project Contributors
 | 
			
		||||
//   Authors: Nate Kohari (nate@enkari.com)
 | 
			
		||||
//            Remo Gloor (remo.gloor@gmail.com)
 | 
			
		||||
//           
 | 
			
		||||
//   Dual-licensed under the Apache License, Version 2.0, and the Microsoft Public License (Ms-PL).
 | 
			
		||||
//   you may not use this file except in compliance with one of the Licenses.
 | 
			
		||||
//   You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//   or
 | 
			
		||||
//       http://www.microsoft.com/opensource/licenses.mspx
 | 
			
		||||
//
 | 
			
		||||
//   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
//   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
//   See the License for the specific language governing permissions and
 | 
			
		||||
//   limitations under the License.
 | 
			
		||||
// </copyright>
 | 
			
		||||
//-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
// ReSharper disable all
 | 
			
		||||
#pragma warning disable
 | 
			
		||||
 | 
			
		||||
namespace Ninject.Planning;
 | 
			
		||||
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using Ninject.Components;
 | 
			
		||||
using Ninject.Infrastructure.Language;
 | 
			
		||||
using Ninject.Planning.Strategies;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Generates plans for how to activate instances.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public class RemovablePlanner : NinjectComponent, IPlanner
 | 
			
		||||
{
 | 
			
		||||
    private readonly ReaderWriterLock plannerLock = new ReaderWriterLock();
 | 
			
		||||
    private readonly Dictionary<Type, IPlan> plans = new Dictionary<Type, IPlan>();
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Initializes a new instance of the <see cref="RemovablePlanner"/> class.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="strategies">The strategies to execute during planning.</param>
 | 
			
		||||
    public RemovablePlanner(IEnumerable<IPlanningStrategy> strategies)
 | 
			
		||||
    {
 | 
			
		||||
        this.Strategies = strategies.ToList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets the strategies that contribute to the planning process.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    public IList<IPlanningStrategy> Strategies { get; private set; }
 | 
			
		||||
        
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Gets or creates an activation plan for the specified type.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="type">The type for which a plan should be created.</param>
 | 
			
		||||
    /// <returns>The type's activation plan.</returns>
 | 
			
		||||
    public IPlan GetPlan(Type type)
 | 
			
		||||
    {
 | 
			
		||||
        this.plannerLock.AcquireReaderLock(Timeout.Infinite);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            IPlan plan;
 | 
			
		||||
            return this.plans.TryGetValue(type, out plan) ? plan : this.CreateNewPlan(type);
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            this.plannerLock.ReleaseReaderLock();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Creates an empty plan for the specified type.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="type">The type for which a plan should be created.</param>
 | 
			
		||||
    /// <returns>The created plan.</returns>
 | 
			
		||||
    protected virtual IPlan CreateEmptyPlan(Type type)
 | 
			
		||||
    {
 | 
			
		||||
        return new Plan(type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Creates a new plan for the specified type.
 | 
			
		||||
    /// This method requires an active reader lock!
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="type">The type.</param>
 | 
			
		||||
    /// <returns>The newly created plan.</returns>
 | 
			
		||||
    private IPlan CreateNewPlan(Type type)
 | 
			
		||||
    {
 | 
			
		||||
        var lockCooki = this.plannerLock.UpgradeToWriterLock(Timeout.Infinite);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            IPlan plan;
 | 
			
		||||
            if (this.plans.TryGetValue(type, out plan))
 | 
			
		||||
            {
 | 
			
		||||
                return plan;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            plan = this.CreateEmptyPlan(type);
 | 
			
		||||
            this.plans.Add(type, plan);
 | 
			
		||||
            this.Strategies.Map(s => s.Execute(plan));
 | 
			
		||||
 | 
			
		||||
            return plan;
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            this.plannerLock.DowngradeFromWriterLock(ref lockCooki);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RemovePlan(Type type)
 | 
			
		||||
    {
 | 
			
		||||
        plans.Remove(type);
 | 
			
		||||
        plans.TrimExcess();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +1,13 @@
 | 
			
		||||
using DryIoc;
 | 
			
		||||
using LinqToDB.Extensions;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
using NadekoBot.Modules.Music;
 | 
			
		||||
using NadekoBot.Modules.Music.Resolvers;
 | 
			
		||||
using NadekoBot.Modules.Music.Services;
 | 
			
		||||
using Ninject.Extensions.Conventions.Syntax;
 | 
			
		||||
using StackExchange.Redis;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using Ninject.Infrastructure.Language;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Extensions;
 | 
			
		||||
 | 
			
		||||
@@ -32,63 +31,32 @@ public static class ServiceCollectionExtensions
 | 
			
		||||
        return svcs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddConfigServices(this IContainer kernel, Assembly a)
 | 
			
		||||
    public static IContainer AddConfigServices(this IContainer svcs, Assembly a)
 | 
			
		||||
    {
 | 
			
		||||
        // kernel.RegisterMany([typeof(ConfigServiceBase<>)]);
 | 
			
		||||
        
 | 
			
		||||
        foreach (var type in a.GetTypes()
 | 
			
		||||
                           .Where(x => !x.IsAbstract && x.IsAssignableToGenericType(typeof(ConfigServiceBase<>))))
 | 
			
		||||
        {
 | 
			
		||||
            kernel.RegisterMany([type],
 | 
			
		||||
            svcs.RegisterMany([type],
 | 
			
		||||
                getServiceTypes: type => type.GetImplementedTypes(ReflectionTools.AsImplementedType.SourceType),
 | 
			
		||||
                getImplFactory: type => ReflectionFactory.Of(type, Reuse.Singleton));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //
 | 
			
		||||
        // kernel.Bind(x =>
 | 
			
		||||
        // {
 | 
			
		||||
        //     var configs = x.From(a)
 | 
			
		||||
        //                    .SelectAllClasses()
 | 
			
		||||
        //                    .Where(f => f.IsAssignableToGenericType(typeof(ConfigServiceBase<>)));
 | 
			
		||||
        //
 | 
			
		||||
        //     configs.BindToSelfWithInterfaces()
 | 
			
		||||
        //            .Configure(c => c.InSingletonScope());
 | 
			
		||||
        // });
 | 
			
		||||
 | 
			
		||||
        return kernel;
 | 
			
		||||
        
 | 
			
		||||
        return svcs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddConfigMigrators(this IContainer kernel, Assembly a)
 | 
			
		||||
        => kernel.AddSealedSubclassesOf(typeof(IConfigMigrator), a);
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddMusic(this IContainer kernel)
 | 
			
		||||
    public static IContainer AddMusic(this IContainer svcs)
 | 
			
		||||
    {
 | 
			
		||||
        kernel.RegisterMany<MusicService>(Reuse.Singleton);
 | 
			
		||||
        svcs.RegisterMany<MusicService>(Reuse.Singleton);
 | 
			
		||||
 | 
			
		||||
        kernel.AddSingleton<ITrackResolveProvider, TrackResolveProvider>();
 | 
			
		||||
        kernel.AddSingleton<IYoutubeResolver, YtdlYoutubeResolver>();
 | 
			
		||||
        kernel.AddSingleton<ILocalTrackResolver, LocalTrackResolver>();
 | 
			
		||||
        kernel.AddSingleton<IRadioResolver, RadioResolver>();
 | 
			
		||||
        kernel.AddSingleton<ITrackCacher, TrackCacher>();
 | 
			
		||||
        svcs.AddSingleton<ITrackResolveProvider, TrackResolveProvider>();
 | 
			
		||||
        svcs.AddSingleton<IYoutubeResolver, YtdlYoutubeResolver>();
 | 
			
		||||
        svcs.AddSingleton<ILocalTrackResolver, LocalTrackResolver>();
 | 
			
		||||
        svcs.AddSingleton<IRadioResolver, RadioResolver>();
 | 
			
		||||
        svcs.AddSingleton<ITrackCacher, TrackCacher>();
 | 
			
		||||
 | 
			
		||||
        return kernel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddSealedSubclassesOf(this IContainer cont, Type baseType, Assembly a)
 | 
			
		||||
    {
 | 
			
		||||
        var classes = a.GetExportedTypes()
 | 
			
		||||
                       .Where(x => x.IsClass && !x.IsAbstract && x.IsPublic)
 | 
			
		||||
                       .Where(x => x.IsNested && baseType.IsAssignableFrom(x));
 | 
			
		||||
 | 
			
		||||
        foreach (var c in classes)
 | 
			
		||||
        {
 | 
			
		||||
            cont.RegisterMany([c], Reuse.Singleton);
 | 
			
		||||
            // var inters = c.GetInterfaces();
 | 
			
		||||
 | 
			
		||||
            // cont.RegisterMany(inters, c);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return cont;
 | 
			
		||||
        return svcs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddCache(this IContainer cont, IBotCredentials creds)
 | 
			
		||||
@@ -110,33 +78,31 @@ public static class ServiceCollectionExtensions
 | 
			
		||||
            .AddBotStringsServices(creds.BotCache);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddHttpClients(this IContainer kernel)
 | 
			
		||||
    public static IContainer AddHttpClients(this IContainer svcs)
 | 
			
		||||
    {
 | 
			
		||||
        IServiceCollection svcs = new ServiceCollection();
 | 
			
		||||
        svcs.AddHttpClient();
 | 
			
		||||
        svcs.AddHttpClient("memelist")
 | 
			
		||||
            .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
 | 
			
		||||
            {
 | 
			
		||||
                AllowAutoRedirect = false
 | 
			
		||||
            });
 | 
			
		||||
        IServiceCollection proxySvcs = new ServiceCollection();
 | 
			
		||||
        proxySvcs.AddHttpClient();
 | 
			
		||||
        proxySvcs.AddHttpClient("memelist")
 | 
			
		||||
                 .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
 | 
			
		||||
                 {
 | 
			
		||||
                     AllowAutoRedirect = false
 | 
			
		||||
                 });
 | 
			
		||||
 | 
			
		||||
        svcs.AddHttpClient("google:search")
 | 
			
		||||
            .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
 | 
			
		||||
            {
 | 
			
		||||
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
 | 
			
		||||
            });
 | 
			
		||||
        proxySvcs.AddHttpClient("google:search")
 | 
			
		||||
                 .ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
 | 
			
		||||
                 {
 | 
			
		||||
                     AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
 | 
			
		||||
                 });
 | 
			
		||||
 | 
			
		||||
        var prov = svcs.BuildServiceProvider();
 | 
			
		||||
        kernel.RegisterDelegate<IHttpClientFactory>(_ => prov.GetRequiredService<IHttpClientFactory>());
 | 
			
		||||
        kernel.RegisterDelegate<HttpClient>(_ => prov.GetRequiredService<HttpClient>());
 | 
			
		||||
        var prov = proxySvcs.BuildServiceProvider();
 | 
			
		||||
        
 | 
			
		||||
        svcs.RegisterDelegate<IHttpClientFactory>(_ => prov.GetRequiredService<IHttpClientFactory>());
 | 
			
		||||
        svcs.RegisterDelegate<HttpClient>(_ => prov.GetRequiredService<HttpClient>());
 | 
			
		||||
 | 
			
		||||
        return kernel;
 | 
			
		||||
        return svcs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IConfigureSyntax BindToSelfWithInterfaces(this IJoinExcludeIncludeBindSyntax matcher)
 | 
			
		||||
        => matcher.BindSelection((type, types) => types.Append(type));
 | 
			
		||||
 | 
			
		||||
    public static IContainer AddLifetimeServices(this IContainer kernel, Assembly a)
 | 
			
		||||
    public static IContainer AddLifetimeServices(this IContainer svcs, Assembly a)
 | 
			
		||||
    {
 | 
			
		||||
        Type[] types =
 | 
			
		||||
        [
 | 
			
		||||
@@ -149,27 +115,17 @@ public static class ServiceCollectionExtensions
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        foreach (var svc in a.GetTypes()
 | 
			
		||||
                           .Where(type => type.IsClass && types.Any(t => type.IsAssignableTo(t)) && !type.HasAttribute<DIIgnoreAttribute>()))
 | 
			
		||||
                           .Where(type => type.IsClass && types.Any(t => type.IsAssignableTo(t)) && !type.HasAttribute<DIIgnoreAttribute>()
 | 
			
		||||
#if GLOBAL_NADEKO
 | 
			
		||||
                            && !type.HasAttribute<NoPublicBotAttribute>()
 | 
			
		||||
#endif
 | 
			
		||||
                           ))
 | 
			
		||||
        {
 | 
			
		||||
            kernel.RegisterMany([svc],
 | 
			
		||||
            svcs.RegisterMany([svc],
 | 
			
		||||
                getServiceTypes: type => type.GetImplementedTypes(ReflectionTools.AsImplementedType.SourceType),
 | 
			
		||||
                getImplFactory: type => ReflectionFactory.Of(type, Reuse.Singleton));
 | 
			
		||||
        }
 | 
			
		||||
//
 | 
			
		||||
//         kernel.RegisterMany(
 | 
			
		||||
//             [a],
 | 
			
		||||
// #if GLOBAL_NADEKO
 | 
			
		||||
//                             && !c.HasAttribute<NoPublicBotAttribute>()
 | 
			
		||||
// #endif
 | 
			
		||||
//         ),
 | 
			
		||||
//         reuse:
 | 
			
		||||
//         Reuse.Singleton
 | 
			
		||||
//             );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // todo maybe self is missing
 | 
			
		||||
        // todo maybe attribute doesn't work
 | 
			
		||||
 | 
			
		||||
        return kernel;
 | 
			
		||||
        return svcs;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
public interface IConfigMigrator
 | 
			
		||||
{
 | 
			
		||||
    public void EnsureMigrated();
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user