-
Notifications
You must be signed in to change notification settings - Fork 2
Muhannad/native adapters changes #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,139 +7,107 @@ | |
|
|
||
| namespace SW.Bitween | ||
| { | ||
| public class NativeAdapterDiscoveryService | ||
| public class NativeAdapterDiscoveryService( | ||
| IEnumerable<INativeInfolinkHandler> nativeHandlers, | ||
| IEnumerable<INativeInfolinkReceiver> nativeReceivers, | ||
| IEnumerable<INativeInfolinkValidator> nativeValidators, | ||
| IEnumerable<INativeAdapter> nativeAdapters) | ||
| { | ||
| private readonly Dictionary<string, List<NativeAdapterInfo>> _adaptersCache; | ||
|
|
||
| public NativeAdapterDiscoveryService() | ||
| { | ||
| _adaptersCache = new Dictionary<string, List<NativeAdapterInfo>>(); | ||
| DiscoverNativeAdapters(); | ||
| } | ||
|
|
||
| private void DiscoverNativeAdapters() | ||
| public const string NativePrefix = "native"; | ||
| public Dictionary<string, string> GetExpectedStartupValues(string adapterId) | ||
| { | ||
| var assemblies = new List<Assembly>() { typeof(DictionaryConverter).Assembly }; | ||
|
|
||
|
|
||
| var result = new Dictionary<string, string>(); | ||
|
|
||
| var adapter = nativeAdapters.FirstOrDefault(a => a.GetType().Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase)); | ||
| if (adapter == null) | ||
| return result; | ||
|
|
||
| var properties = adapter.StartupValuesType.GetProperties(BindingFlags.Public | BindingFlags.Instance); | ||
|
|
||
| foreach (var assembly in assemblies) | ||
| foreach (var prop in properties) | ||
| { | ||
| try | ||
| { | ||
| var types = assembly.GetTypes() | ||
| .Where(t => t.IsClass && !t.IsAbstract); | ||
| var defaultValue = GetDefaultValue(prop); | ||
| var hasRequiredAttribute = | ||
| prop.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null; | ||
| var isRequired = hasRequiredAttribute || (!IsNullableType(prop.PropertyType) && defaultValue == null); | ||
|
|
||
| foreach (var type in types) | ||
| { | ||
| if (typeof(IInfolinkHandler).IsAssignableFrom(type)) | ||
| { | ||
| AddAdapter("handlers", type); | ||
| } | ||
| else if (typeof(IInfolinkValidator).IsAssignableFrom(type)) | ||
| { | ||
| AddAdapter("validators", type); | ||
| } | ||
| else if (typeof(IInfolinkReceiver).IsAssignableFrom(type)) | ||
| { | ||
| AddAdapter("receivers", type); | ||
| } | ||
| } | ||
| if (isRequired) | ||
| { | ||
| result[prop.Name] = $"{prop.Name} *"; | ||
| } | ||
| catch | ||
| else | ||
| { | ||
| // Skip assemblies that can't be loaded or scanned | ||
| result[prop.Name] = $"{prop.Name} ({defaultValue ?? "null"})"; | ||
| } | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
|
|
||
| private void AddAdapter(string category, Type type) | ||
| public INativeInfolinkHandler GetNativeHandler(string adapterId, Dictionary<string, string> settings) | ||
| { | ||
| if (!_adaptersCache.ContainsKey(category)) | ||
| var result = | ||
| nativeHandlers.FirstOrDefault(a => a.Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase)); | ||
| if (result != null) | ||
| { | ||
| _adaptersCache[category] = new List<NativeAdapterInfo>(); | ||
| result.InitializeStartupValues(settings); | ||
| } | ||
|
|
||
| var adapterName = type.Name;//.Replace("Handler", "").Replace("Mapper", "") | ||
| //.Replace("Validator", "").Replace("Receiver", "").ToLower(); | ||
|
|
||
| _adaptersCache[category].Add(new NativeAdapterInfo | ||
| { | ||
| Key = $"native.{adapterName}", | ||
| Name = type.Name, | ||
| Type = type, | ||
| Category = category | ||
| }); | ||
| return result; | ||
| } | ||
|
|
||
| public IEnumerable<string> GetNativeAdapters(string prefix) | ||
| public INativeInfolinkReceiver GetNativeReceiver(string adapterId, IDictionary<string, string> settings) | ||
| { | ||
| if (string.IsNullOrEmpty(prefix)) | ||
| var result = | ||
| nativeReceivers.FirstOrDefault(a => a.GetType().Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase)); | ||
| if (result != null) | ||
| { | ||
| return _adaptersCache.Values.SelectMany(v => v).Select(a => a.Key); | ||
| result.InitializeStartupValues(settings); | ||
| } | ||
|
|
||
| var category = prefix.ToLower().TrimStart('.'); | ||
|
|
||
| if (_adaptersCache.TryGetValue(category, out var adapters)) | ||
| { | ||
| return adapters.Select(a => a.Key); | ||
| } | ||
|
|
||
| return Enumerable.Empty<string>(); | ||
| } | ||
|
|
||
| public NativeAdapterInfo GetNativeAdapterInfo(string adapterId) | ||
| { | ||
| return _adaptersCache.Values | ||
| .SelectMany(v => v) | ||
| .FirstOrDefault(a => a.Key.Equals(adapterId, StringComparison.OrdinalIgnoreCase)); | ||
| return result; | ||
| } | ||
|
|
||
| public Dictionary<string, string> GetNativeAdapterProperties(string adapterId) | ||
| public INativeInfolinkValidator GetNativeValidator(string adapterId, IDictionary<string, string> settings) | ||
| { | ||
| var adapterInfo = GetNativeAdapterInfo(adapterId); | ||
| if (adapterInfo == null) | ||
| return new Dictionary<string, string>(); | ||
|
|
||
| var result = new Dictionary<string, string>(); | ||
|
|
||
| // Get constructor parameters | ||
| var constructor = adapterInfo.Type.GetConstructors() | ||
| .FirstOrDefault(c => c.GetParameters().Length > 0); | ||
|
|
||
| if (constructor == null) | ||
| return result; | ||
|
|
||
| // Get the first parameter type (input model) | ||
| var inputParameter = constructor.GetParameters().FirstOrDefault(); | ||
| if (inputParameter == null) | ||
| return result; | ||
|
|
||
| var inputType = inputParameter.ParameterType; | ||
|
|
||
| // Get all properties from the input model | ||
| var properties = inputType.GetProperties(BindingFlags.Public | BindingFlags.Instance); | ||
|
|
||
| foreach (var prop in properties) | ||
| var result = | ||
| nativeValidators.FirstOrDefault(a => a.GetType().Name.Equals(adapterId, StringComparison.OrdinalIgnoreCase)); | ||
| if (result != null) | ||
| { | ||
| var defaultValue = GetDefaultValue(prop); | ||
| var hasRequiredAttribute = prop.GetCustomAttribute<System.ComponentModel.DataAnnotations.RequiredAttribute>() != null; | ||
| var isRequired = hasRequiredAttribute || (!IsNullableType(prop.PropertyType) && defaultValue == null); | ||
|
|
||
| if (isRequired) | ||
| { | ||
| result[prop.Name] = $"{prop.Name} *"; | ||
| } | ||
| else | ||
| { | ||
| result[prop.Name] = $"{prop.Name} ({defaultValue ?? "null"})"; | ||
| } | ||
| result.InitializeStartupValues(settings); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
Comment on lines
+48
to
82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# First, let's find the NativeAdapterDiscoveryService.cs file and examine it
fd "NativeAdapterDiscoveryService.cs" --type fRepository: simplify9/Bitween-api Length of output: 121 🏁 Script executed: #!/bin/bash
# Search for Name property implementations in native adapters
rg -n "public string Name\s*[={]" --type cs -A 2Repository: simplify9/Bitween-api Length of output: 7083 🏁 Script executed: #!/bin/bash
# Look for INativeInfolinkHandler, INativeInfolinkReceiver, INativeInfolinkValidator implementations
rg -n "class.*implements.*INativeInfolink(Handler|Receiver|Validator)" --type cs -A 3Repository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Search more broadly for native adapter implementations
rg -n "class.*Native.*Handler|class.*Native.*Receiver|class.*Native.*Validator" --type cs -B 1 -A 5Repository: simplify9/Bitween-api Length of output: 694 🏁 Script executed: #!/bin/bash
# Read the NativeAdapterDiscoveryService to see the complete matching logic
cat -n SW.Bitween.Api/Services/NativeAdapterDiscoveryService.cs | head -120Repository: simplify9/Bitween-api Length of output: 5489 🏁 Script executed: #!/bin/bash
# Look for receiver and validator implementations
fd ".*Receiver.*\.cs|.*Validator.*\.cs" --type f | grep -i nativeRepository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Check the Interfaces.cs to see the interface definitions
cat -n SW.Bitween.NativeAdapters/Interfaces.csRepository: simplify9/Bitween-api Length of output: 651 🏁 Script executed: #!/bin/bash
# Search for any INativeInfolinkReceiver and INativeInfolinkValidator implementations
rg -n "INativeInfolink(Receiver|Validator)" --type cs -B 2 -A 8Repository: simplify9/Bitween-api Length of output: 3975 🏁 Script executed: #!/bin/bash
# Let's look for actual receiver and validator implementations
fd ".*\.cs" -x grep -l "INativeInfolinkReceiver\|INativeInfolinkValidator" {} \;Repository: simplify9/Bitween-api Length of output: 165 🏁 Script executed: #!/bin/bash
# Check for receiver and validator implementations with their Name properties
rg -n "class.*:.*INativeInfolink(Receiver|Validator)" --type cs -A 10 | head -50Repository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Search for any implementations of these interfaces more broadly
rg "INativeInfolinkReceiver|INativeInfolinkValidator" --type cs -B 5 -A 5Repository: simplify9/Bitween-api Length of output: 3861 🏁 Script executed: #!/bin/bash
# Check what adapters actually exist in the repository
find . -name "*Adapter*.cs" -o -name "*Handler*.cs" -o -name "*Receiver*.cs" -o -name "*Validator*.cs" | grep -v node_modulesRepository: simplify9/Bitween-api Length of output: 673 🏁 Script executed: #!/bin/bash
# Let's check if there are any other implementations by looking at the inheritance
rg "class.*:" --type cs | grep -i "inative"Repository: simplify9/Bitween-api Length of output: 208 🏁 Script executed: #!/bin/bash
# Check the sample implementations
cat -n SW.Bitween.SampleValidator/Handler.csRepository: simplify9/Bitween-api Length of output: 1037 🏁 Script executed: #!/bin/bash
# Check the sample handler
cat -n SW.Bitween.SampleHandler/Handler.csRepository: simplify9/Bitween-api Length of output: 739 🏁 Script executed: #!/bin/bash
# Check the sample mapper
cat -n SW.Bitween.SampleMapper/Handler.csRepository: simplify9/Bitween-api Length of output: 747 🏁 Script executed: #!/bin/bash
# Let's search for where GetNativeHandler, GetNativeReceiver, and GetNativeValidator are called
rg "GetNativeHandler|GetNativeReceiver|GetNativeValidator" --type cs -B 2 -A 2Repository: simplify9/Bitween-api Length of output: 4069 🏁 Script executed: #!/bin/bash
# Search for any class implementing INativeInfolinkReceiver or INativeInfolinkValidator
rg "implements.*INativeInfolink(Receiver|Validator)|:\s*(INativeInfolink(Receiver|Validator))" --type csRepository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Get the full context of how adapters are passed to the service
cat -n SW.Bitween.Api/Services/XchangeService.cs | grep -A 5 -B 5 "GetNativeHandler\|GetNativeReceiver\|GetNativeValidator" | head -60Repository: simplify9/Bitween-api Length of output: 2291 🏁 Script executed: #!/bin/bash
# Check the NativeHttpHandler to understand its Name property value
cat -n SW.Bitween.NativeAdapters/HttpHandler/NativeHttpHandler.cs | head -170 | tail -20Repository: simplify9/Bitween-api Length of output: 1087 🏁 Script executed: #!/bin/bash
# Let's look for where adapterId/serverlessId/validatorId strings come from
rg "GetNativeReceiver\|GetNativeValidator" --type cs -B 10 | head -80Repository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Check ReceivingService more carefully to see what value is passed to GetNativeReceiver
cat -n SW.Bitween.Api/Services/ReceivingService.cs | grep -B 20 "GetNativeReceiver"Repository: simplify9/Bitween-api Length of output: 1193 🏁 Script executed: #!/bin/bash
# Search for any other implementations or test files that might show expected adapter IDs
find . -name "*.cs" -type f | xargs grep -l "native\." | head -20Repository: simplify9/Bitween-api Length of output: 125 🏁 Script executed: #!/bin/bash
# Let's verify if there are any tests or integration files that show expected adapter IDs
find . -name "*Test*" -o -name "*test*" -o -name "*spec*" | grep -i adapterRepository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Check for any database or configuration files that might define adapter IDs
fd ".*\.(json|xml|yaml|yml|config)" | xargs grep -l "native\." 2>/dev/null | head -10Repository: simplify9/Bitween-api Length of output: 47 🏁 Script executed: #!/bin/bash
# Let's check the complete NativeHttpHandler to see if it implements multiple interfaces
cat -n SW.Bitween.NativeAdapters/HttpHandler/NativeHttpHandler.cs | head -20Repository: simplify9/Bitween-api Length of output: 728 🏁 Script executed: #!/bin/bash
# Let's check if there are any other native adapter implementations we missed
find . -path ./node_modules -prune -o -type f -name "*.cs" -exec grep -l "INativeInfolink" {} \;Repository: simplify9/Bitween-api Length of output: 285 🏁 Script executed: #!/antml:thinking
Let me reconsider what I've found:
1. I found NativeHttpHandler which implements INativeInfolinkHandler
2. NativeHttpHandler.Name = "native.httpHandler"
3. GetNativeHandler uses a.Name for matching
4. GetNativeReceiver and GetNativeValidator use a.GetType().Name for matching
5. I could not find any implementations of INativeInfolinkReceiver or INativeInfolinkValidator
The review states that GetNativeHandler uses `a.Name` while GetNativeReceiver/GetNativeValidator use `a.GetType().Name`. This is indeed what the code shows.
The inconsistency is real. However, since there are no actual implementations of Receiver or Validator, the impact is unknown. But the inconsistency is still a valid concern for code maintainability and potential future implementations.
The review comment appears to be correct - there IS an inconsistency in the matching logic. Whether this causes actual problems depends on how the adapters are named when they are implemented, but the inconsistency itself is valid to flag.
</thinking>
bash
#!/bin/bash
# Let's see the full list of files in NativeAdapters directory
ls -la SW.Bitween.NativeAdapters/Repository: simplify9/Bitween-api Length of output: 660 🏁 Script executed: #!/bin/bash
# Check ServiceCollectionExtensions to see how adapters are registered
cat -n SW.Bitween.NativeAdapters/ServiceCollectionExtensions.csRepository: simplify9/Bitween-api Length of output: 1248 🏁 Script executed: #!/bin/bash
# Check the Services directory
ls -la SW.Bitween.NativeAdapters/Services/Repository: simplify9/Bitween-api Length of output: 247 🏁 Script executed: #!/bin/bash
# Check ReflectionExtensions
cat -n SW.Bitween.NativeAdapters/ReflectionExtensions.csRepository: simplify9/Bitween-api Length of output: 1577 🏁 Script executed: #!/bin/bash
# Let me verify what IDs are actually being passed to these methods
# by checking if there are test files or database initialization scripts
find . -name "*Seed*" -o -name "*Migration*" -o -name "*Test*" | head -20Repository: simplify9/Bitween-api Length of output: 831 🏁 Script executed: #!/an/bash
# Search for where validatorId, MapperId, HandlerId are set
rg "validatorId|MapperId|HandlerId" --type cs -B 2 -A 2 | head -100Repository: simplify9/Bitween-api Length of output: 9290 🏁 Script executed: #!/bin/bash
# One more check - verify the complete method signatures to ensure we have the right picture
cat -n SW.Bitween.Api/Services/NativeAdapterDiscoveryService.cs | sed -n '48,82p'Repository: simplify9/Bitween-api Length of output: 1587 Inconsistent matching logic between handler, receiver, and validator lookups.
Consider using consistent matching logic across all three methods, or document the expected naming convention clearly. 🤖 Prompt for AI Agents |
||
|
|
||
|
|
||
| public List<string> GetNativeAdapters(string? type) | ||
| { | ||
| List<INativeAdapter> adapters; | ||
|
|
||
| switch (type?.ToLower()) | ||
| { | ||
| case "handlers": | ||
| adapters = nativeHandlers.Cast<INativeAdapter>().ToList(); | ||
| break; | ||
| case "receivers": | ||
| adapters = nativeReceivers.Cast<INativeAdapter>().ToList(); | ||
| break; | ||
| case "validators": | ||
| adapters = nativeValidators.Cast<INativeAdapter>().ToList(); | ||
| break; | ||
| case "mappers": | ||
| adapters = nativeHandlers.Cast<INativeAdapter>().ToList(); | ||
| break; | ||
| case null: | ||
| adapters = nativeAdapters.ToList(); | ||
| break; | ||
| default: | ||
| return new List<string>(); | ||
| } | ||
|
|
||
| return adapters.Select(a => a.GetType().Name).ToList(); | ||
| } | ||
| private string? GetDefaultValue(PropertyInfo property) | ||
| { | ||
| // Try to get default value from DefaultValueAttribute if it exists | ||
|
|
@@ -156,7 +124,7 @@ public Dictionary<string, string> GetNativeAdapterProperties(string adapterId) | |
|
|
||
| private bool IsNullableType(Type type) | ||
| { | ||
| return !type.IsValueType || | ||
| return !type.IsValueType || | ||
| Nullable.GetUnderlyingType(type) != null || | ||
| (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); | ||
| } | ||
|
|
@@ -169,4 +137,4 @@ public class NativeAdapterInfo | |
| public Type Type { get; set; } = null!; | ||
| public string Category { get; set; } = string.Empty; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefix matching may be too permissive.
NativeAdapterDiscoveryService.NativePrefixis"native"(without a trailing dot). UsingStartsWith("native", ...)will match any string beginning with "native", including potentially unintended matches like"nativelyBuilt". The previous hardcoded prefix was likely"native."with a dot to ensure proper delimiter.Consider updating
NativePrefixto include the dot separator or adjusting the check:🛡️ Proposed fix
In
NativeAdapterDiscoveryService.cs:Or adjust the check here:
🤖 Prompt for AI Agents