using Godot; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using SharpIDE.Application.Features.Analysis; using SharpIDE.Application.Features.Build; using SharpIDE.Application.Features.Evaluation; using SharpIDE.Application.Features.FilePersistence; using SharpIDE.Application.Features.FileWatching; using SharpIDE.Application.Features.NavigationHistory; using SharpIDE.Application.Features.Nuget; using SharpIDE.Application.Features.Run; using SharpIDE.Application.Features.Search; using SharpIDE.Application.Features.Testing; namespace SharpIDE.Godot; [AttributeUsage(AttributeTargets.Field)] public class InjectAttribute : Attribute; public partial class DiAutoload : Node { private ServiceProvider? _serviceProvider; private IServiceScope? _currentScope; public override void _EnterTree() { GD.Print("[Injector] _EnterTree called"); var services = new ServiceCollection(); // Register services here services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddHttpClient(); services.AddLogging(builder => { //builder.SetMinimumLevel(LogLevel.Trace); builder.AddConsole(); builder.AddOpenTelemetry(logging => { logging.IncludeFormattedMessage = true; logging.IncludeScopes = true; }); }); services.AddGodotOpenTelemetry(); _serviceProvider = services.BuildServiceProvider(); GetTree().NodeAdded += OnNodeAdded; GD.Print("[Injector] Service provider built and NodeAdded event subscribed"); } public override void _Ready() { } /// The solution has changed, so reset the scope to get new services public void ResetScope() { _currentScope?.Dispose(); _currentScope = _serviceProvider!.CreateScope(); } private void OnNodeAdded(Node node) { // Inject dependencies into every new node InjectDependencies(node); } private void InjectDependencies(object target) { var type = target.GetType(); const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; foreach (var field in type.GetFields(flags)) { if (Attribute.IsDefined(field, typeof(InjectAttribute))) { if (_currentScope is null) { GD.PrintErr("[Injector] _currentScope was null when attempting to resolve service"); GetTree().Quit(); return; } var service = _currentScope!.ServiceProvider.GetService(field.FieldType); if (service is null) { GD.PrintErr($"[Injector] No service registered for {field.FieldType}"); GetTree().Quit(); return; } field.SetValue(target, service); } } } }