using System; using System.IO; using System.Runtime.InteropServices; using System.Threading; using SQLitePCL; namespace Mrleo1nid.SwarmAssistent; /// /// SwarmUI loads extensions in an isolated AssemblyLoadContext — Microsoft.Data.Sqlite /// does not auto-init native SQLite there. Native libs ship under the extension dir /// (runtimes/linux-x64/native/libe_sqlite3.so), but the loader searches the host /// base dir unless we preload from the extension assembly location. /// internal static class AssistentSqliteBootstrap { static int _ready; internal static void EnsureInitialized() { if (Interlocked.CompareExchange(ref _ready, 1, 0) != 0) { return; } PreloadNativeLibrary(); Batteries_V2.Init(); } static void PreloadNativeLibrary() { string extDir = Path.GetDirectoryName(typeof(AssistentSqliteBootstrap).Assembly.Location) ?? AppContext.BaseDirectory ?? ""; if (string.IsNullOrWhiteSpace(extDir)) { return; } foreach (string rel in CandidatePaths()) { string path = Path.Combine(extDir, rel); if (!File.Exists(path)) { continue; } try { IntPtr handle = NativeLibrary.Load(path); RegisterResolver(handle); return; } catch (Exception ex) { SwarmUI.Utils.Logs.Debug($"AssistentSqliteBootstrap: NativeLibrary.Load({path}): {ex.Message}"); } } } /// Native e_sqlite3 locations for the current OS / arch, most specific first. static string[] CandidatePaths() { string arch = RuntimeInformation.ProcessArchitecture switch { Architecture.Arm64 => "arm64", Architecture.X86 => "x86", Architecture.Arm => "arm", _ => "x64", }; if (OperatingSystem.IsWindows()) { return [Path.Combine("runtimes", $"win-{arch}", "native", "e_sqlite3.dll"), "e_sqlite3.dll"]; } if (OperatingSystem.IsMacOS()) { return [Path.Combine("runtimes", $"osx-{arch}", "native", "libe_sqlite3.dylib"), "libe_sqlite3.dylib"]; } return [ Path.Combine("runtimes", $"linux-{arch}", "native", "libe_sqlite3.so"), Path.Combine("runtimes", $"linux-{arch}", "native", "e_sqlite3.so"), "libe_sqlite3.so", "e_sqlite3.so", ]; } /// The provider's [DllImport("e_sqlite3")] would otherwise probe the host dir, not the extension dir. static void RegisterResolver(IntPtr handle) { try { NativeLibrary.SetDllImportResolver(typeof(SQLite3Provider_e_sqlite3).Assembly, (name, _, _) => name.Contains("e_sqlite3", StringComparison.OrdinalIgnoreCase) ? handle : IntPtr.Zero); } catch (InvalidOperationException) { // A resolver is already set for this assembly — the preloaded handle still helps on Windows. } } }