using System; using System.Linq; using Godot; using Microsoft.Extensions.Logging; using OwofGames.AetherBind; using OwofGames.GodotLume; namespace GodotHostTest.AetherBind; [Icon("res://addons/AetherBind/ServiceSource.svg")] public partial class ServiceSource : Node { private static readonly string RootScopeQualifiedName = typeof(RootScope).AssemblyQualifiedName!; [Export] protected Node?[] InjectedNodes = []; [Export] private string _serviceScope = RootScopeQualifiedName; internal void ResolveInjectedNodes(IProvider provider, Delegate? onScopeCreated) { var logger = provider.Get>(); // if this service source must also act as a scope, create the scope and use its service provider if (_serviceScope != RootScopeQualifiedName) { // create the scoped provider var serviceScope = ScopeTypesAndNames.GetType(_serviceScope); provider = provider.GetScopedProvider(serviceScope); // invoke onScopeCreated, if present // TODO: replace with a source code generation by turning this method private with Action argument, and every invocation site calls the necessary provider.Get<...> to build the argument list if (onScopeCreated != null) { var parameters = onScopeCreated.Method .GetParameters() .Select(parameterInfo => provider.Get(parameterInfo.ParameterType)) .ToArray(); onScopeCreated.DynamicInvoke(parameters); } OnScopeCreated(provider); } else if (onScopeCreated != null) { logger.LogWarning("onScopeCreated passed during instantiation, but no scoped provider was created."); } // resolve the injected nodes against the chosen service provider foreach (var node in InjectedNodes) { if (node == null) continue; logger.LogTrace("Injecting {Node}.", node.Name); if (node is IInjectable injectable) { injectable.Inject(provider); } // var nodeType = node.GetType(); // foreach (var field in nodeType // .GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) // { // if (field.GetCustomAttribute() == null) continue; // var fieldType = field.FieldType; // var service = provider.Get(fieldType); // field.SetValue(node, service); // } // // foreach (var method in nodeType.GetMethods(BindingFlags.Instance | BindingFlags.Public | // BindingFlags.NonPublic)) // { // if (method.GetCustomAttribute() == null) continue; // var parameters = method.GetParameters(); // var values = new object?[parameters.Length]; // var i = 0; // foreach (var parameter in parameters) // { // var parameterType = parameter.ParameterType; // var service = provider.Get(parameterType); // values[i++] = service; // } // // method.Invoke(node, values); // } } } // TODO: also add source generator to mark methods in derived classes with [OnScopeCreated] and perform parameter injection protected virtual void OnScopeCreated(IProvider serviceProvider) { } }