mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2024-10-02 20:13:13 +00:00
Re-added medusa system, but untested
This commit is contained in:
parent
ea0b51d474
commit
6a7ab79446
8 changed files with 152 additions and 373 deletions
|
@ -1,65 +1,61 @@
|
|||
// using Discord;
|
||||
//
|
||||
// namespace NadekoBot.Medusa;
|
||||
//
|
||||
// public static class MedusaExtensions
|
||||
// {
|
||||
// public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
|
||||
// => ch.SendMessageAsync(msg,
|
||||
// embed: embed.Build(),
|
||||
// options: new()
|
||||
// {
|
||||
// RetryMode = RetryMode.Retry502
|
||||
// });
|
||||
//
|
||||
// // unlocalized
|
||||
// public static Task<IUserMessage> SendConfirmAsync(this IMessageChannel ch, AnyContext ctx, string msg)
|
||||
// => _sender.Response(ch).Embed(ctx.Embed().WithOkColor().WithDescription(msg)).SendAsync();
|
||||
//
|
||||
// public static Task<IUserMessage> SendPendingAsync(this IMessageChannel ch, AnyContext ctx, string msg)
|
||||
// => _sender.Response(ch).Embed(ctx.Embed().WithPendingColor().WithDescription(msg)).SendAsync();
|
||||
//
|
||||
// public static Task<IUserMessage> SendErrorAsync(this IMessageChannel ch, AnyContext ctx, string msg)
|
||||
// => _sender.Response(ch).Embed(ctx.Embed().WithErrorColor().WithDescription(msg)).SendAsync();
|
||||
//
|
||||
// // unlocalized
|
||||
// public static Task<IUserMessage> SendConfirmAsync(this AnyContext ctx, string msg)
|
||||
// => ctx.Channel.SendConfirmAsync(ctx, msg);
|
||||
//
|
||||
// public static Task<IUserMessage> SendPendingAsync(this AnyContext ctx, string msg)
|
||||
// => ctx.Channel.SendPendingAsync(ctx, msg);
|
||||
//
|
||||
// public static Task<IUserMessage> SendErrorAsync(this AnyContext ctx, string msg)
|
||||
// => ctx.Channel.SendErrorAsync(ctx, msg);
|
||||
//
|
||||
// // localized
|
||||
// public static Task ConfirmAsync(this AnyContext ctx)
|
||||
// => ctx.Message.AddReactionAsync(new Emoji("✅"));
|
||||
//
|
||||
// public static Task ErrorAsync(this AnyContext ctx)
|
||||
// => ctx.Message.AddReactionAsync(new Emoji("❌"));
|
||||
//
|
||||
// public static Task WarningAsync(this AnyContext ctx)
|
||||
// => ctx.Message.AddReactionAsync(new Emoji("⚠️"));
|
||||
//
|
||||
// public static Task WaitAsync(this AnyContext ctx)
|
||||
// => ctx.Message.AddReactionAsync(new Emoji("🤔"));
|
||||
//
|
||||
// public static Task<IUserMessage> ErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
// => ctx.SendErrorAsync(ctx.GetText(key, args));
|
||||
//
|
||||
// public static Task<IUserMessage> PendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
// => ctx.SendPendingAsync(ctx.GetText(key, args));
|
||||
//
|
||||
// public static Task<IUserMessage> ConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
// => ctx.SendConfirmAsync(ctx.GetText(key, args));
|
||||
//
|
||||
// public static Task<IUserMessage> ReplyErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
// => ctx.SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
//
|
||||
// public static Task<IUserMessage> ReplyPendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
// => ctx.SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
//
|
||||
// public static Task<IUserMessage> ReplyConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
// => ctx.SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
// }
|
||||
using Discord;
|
||||
|
||||
namespace NadekoBot.Medusa;
|
||||
|
||||
public static class MedusaExtensions
|
||||
{
|
||||
public static Task<IUserMessage> EmbedAsync(this IMessageChannel ch, EmbedBuilder embed, string msg = "")
|
||||
=> ch.SendMessageAsync(msg,
|
||||
embed: embed.Build(),
|
||||
options: new()
|
||||
{
|
||||
RetryMode = RetryMode.Retry502
|
||||
});
|
||||
|
||||
// unlocalized
|
||||
public static Task<IUserMessage> SendConfirmAsync(this AnyContext ctx, string msg)
|
||||
=> ctx.Channel.EmbedAsync(new EmbedBuilder()
|
||||
.WithColor(0, 200, 0)
|
||||
.WithDescription(msg));
|
||||
|
||||
public static Task<IUserMessage> SendPendingAsync(this AnyContext ctx, string msg)
|
||||
=> ctx.Channel.EmbedAsync(new EmbedBuilder()
|
||||
.WithColor(200, 200, 0)
|
||||
.WithDescription(msg));
|
||||
|
||||
public static Task<IUserMessage> SendErrorAsync(this AnyContext ctx, string msg)
|
||||
=> ctx.Channel.EmbedAsync(new EmbedBuilder()
|
||||
.WithColor(200, 0, 0)
|
||||
.WithDescription(msg));
|
||||
|
||||
// localized
|
||||
public static Task ConfirmAsync(this AnyContext ctx)
|
||||
=> ctx.Message.AddReactionAsync(new Emoji("✅"));
|
||||
|
||||
public static Task ErrorAsync(this AnyContext ctx)
|
||||
=> ctx.Message.AddReactionAsync(new Emoji("❌"));
|
||||
|
||||
public static Task WarningAsync(this AnyContext ctx)
|
||||
=> ctx.Message.AddReactionAsync(new Emoji("⚠️"));
|
||||
|
||||
public static Task WaitAsync(this AnyContext ctx)
|
||||
=> ctx.Message.AddReactionAsync(new Emoji("🤔"));
|
||||
|
||||
public static Task<IUserMessage> ErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendErrorAsync(ctx.GetText(key, args));
|
||||
|
||||
public static Task<IUserMessage> PendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendPendingAsync(ctx.GetText(key, args));
|
||||
|
||||
public static Task<IUserMessage> ConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendConfirmAsync(ctx.GetText(key, args));
|
||||
|
||||
public static Task<IUserMessage> ReplyErrorLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendErrorAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
|
||||
public static Task<IUserMessage> ReplyPendingLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendPendingAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
|
||||
public static Task<IUserMessage> ReplyConfirmLocalizedAsync(this AnyContext ctx, string key, params object[]? args)
|
||||
=> ctx.SendConfirmAsync($"{Format.Bold(ctx.User.ToString())} {ctx.GetText(key, args)}");
|
||||
}
|
|
@ -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();
|
||||
}
|
Loading…
Reference in a new issue