@@ -108,16 +108,32 @@ public void RemovePlugin(IPlugin plugin)
108108 private IReadOnlyList < IOneWareModule > LoadModulesFromPath ( string path )
109109 {
110110 var assemblies = new List < Assembly > ( ) ;
111- foreach ( var file in Directory . GetFiles ( path , "*.dll" , SearchOption . AllDirectories ) )
111+ var loadedAssemblyNames = AppDomain . CurrentDomain . GetAssemblies ( )
112+ . Select ( static assembly => assembly . GetName ( ) . FullName )
113+ . Where ( static fullName => ! string . IsNullOrWhiteSpace ( fullName ) )
114+ . ToHashSet ( StringComparer . OrdinalIgnoreCase ) ;
115+
116+ foreach ( var file in Directory . GetFiles ( path , "*.dll" , SearchOption . AllDirectories )
117+ . Where ( file => ShouldProbePluginAssembly ( path , file ) ) )
118+ {
119+ if ( ! TryGetManagedAssemblyName ( file , out var assemblyName ) )
120+ continue ;
121+
122+ if ( assemblyName . FullName is { } fullName && loadedAssemblyNames . Contains ( fullName ) )
123+ continue ;
124+
112125 try
113126 {
114127 assemblies . Add ( Assembly . LoadFrom ( file ) ) ;
128+ if ( assemblyName . FullName is { } loadedFullName )
129+ loadedAssemblyNames . Add ( loadedFullName ) ;
115130 }
116131 catch ( Exception ex )
117132 {
118133 ContainerLocator . Container ? . Resolve < ILogger > ( )
119134 . Warning ( $ "Skipping plugin assembly '{ Path . GetFileName ( file ) } ': { ex . Message } ", ex ) ;
120135 }
136+ }
121137
122138 var added = new List < IOneWareModule > ( ) ;
123139 foreach ( var assembly in assemblies ) added . AddRange ( _moduleCatalog . AddModulesFromAssembly ( assembly ) ) ;
@@ -129,6 +145,41 @@ private IReadOnlyList<IOneWareModule> LoadModulesFromPath(string path)
129145 return added ;
130146 }
131147
148+ // Usually we can assume that all managed DLLs will be in the base dir of a plugin
149+ // Some libraries ship in runtimes/arch/lib/...
150+ private static bool ShouldProbePluginAssembly ( string pluginPath , string filePath )
151+ {
152+ var relativePath = Path . GetRelativePath ( pluginPath , filePath ) ;
153+ var pathSegments = relativePath . Split ( Path . DirectorySeparatorChar , Path . AltDirectorySeparatorChar ) ;
154+
155+ if ( pathSegments . Length < 2 || ! pathSegments [ 0 ] . Equals ( "runtimes" , StringComparison . OrdinalIgnoreCase ) )
156+ return true ;
157+
158+ if ( pathSegments . Length < 4 )
159+ return false ;
160+
161+ return pathSegments [ 1 ] . Equals ( PlatformHelper . PlatformIdentifier , StringComparison . OrdinalIgnoreCase )
162+ && pathSegments [ 2 ] . Equals ( "lib" , StringComparison . OrdinalIgnoreCase ) ;
163+ }
164+
165+ private static bool TryGetManagedAssemblyName ( string filePath , out AssemblyName assemblyName )
166+ {
167+ try
168+ {
169+ assemblyName = AssemblyName . GetAssemblyName ( filePath ) ;
170+ return true ;
171+ }
172+ catch ( BadImageFormatException )
173+ {
174+ }
175+ catch ( FileLoadException )
176+ {
177+ }
178+
179+ assemblyName = null ! ;
180+ return false ;
181+ }
182+
132183 private void SetupNativeImports ( string pluginPath )
133184 {
134185 var newAssemblies = AppDomain . CurrentDomain . GetAssemblies ( ) . Where ( x => ! _initAssemblies . Contains ( x ) ) ;
@@ -199,32 +250,4 @@ private void SetupNativeImports(string pluginPath)
199250 }
200251 }
201252 }
202-
203- private bool TryResolveSharedOnnxRuntimeLibraryPath ( string libraryName , out string fullPath )
204- {
205- fullPath = string . Empty ;
206-
207- if ( ! libraryName . Contains ( "onnxruntime" , StringComparison . OrdinalIgnoreCase ) ) return false ;
208- if ( ! Directory . Exists ( _paths . OnnxRuntimesDirectory ) ) return false ;
209-
210- var fileName = PlatformHelper . GetLibraryFileName ( libraryName ) ;
211- var rid = PlatformHelper . PlatformIdentifier ;
212- var candidatePaths = new List < string > ( ) ;
213-
214- foreach ( var runtimeDir in Directory . GetDirectories ( _paths . OnnxRuntimesDirectory ) )
215- {
216- candidatePaths . Add ( Path . Combine ( runtimeDir , fileName ) ) ;
217- candidatePaths . Add ( Path . Combine ( runtimeDir , "runtimes" , rid , "native" , fileName ) ) ;
218- candidatePaths . Add ( Path . Combine ( runtimeDir , $ "lib{ fileName } ") ) ;
219- candidatePaths . Add ( Path . Combine ( runtimeDir , "runtimes" , rid , "native" , $ "lib{ fileName } ") ) ;
220- }
221-
222- foreach ( var candidate in candidatePaths . Where ( File . Exists ) )
223- {
224- fullPath = candidate ;
225- return true ;
226- }
227-
228- return false ;
229- }
230253}
0 commit comments