1
Fork 0
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:
Kwoth 2024-05-04 08:08:13 +00:00
parent ea0b51d474
commit 6a7ab79446
8 changed files with 152 additions and 373 deletions

View file

@ -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)}");
}

View file

@ -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()

View file

@ -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();
}

View file

@ -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,

View file

@ -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; }
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -1,7 +0,0 @@
#nullable disable
namespace NadekoBot.Services;
public interface IConfigMigrator
{
public void EnsureMigrated();
}