using System; using System.Collections.Generic; using Foodsoft.Alpm.Interop; namespace Foodsoft.Alpm { public sealed class Handle : IDisposable { private readonly object _eventLock = new object(); private readonly SafeAlpmHandle _handle; private EventHandler? _logEvent; public Handle(string root, string dbPath) { _handle = alpm.alpm_initialize(root, dbPath, out var err); if (_handle.IsInvalid) throw new AlpmException(err); } public Database LocalDB => ToDatabase(alpm.alpm_get_localdb(_handle)); public ICollection CacheDirs { get => EnumerableWrapper.Create(_handle, alpm.alpm_option_get_cachedirs); set => Detail.SetStringCollection(value, _handle, s => alpm.alpm_option_add_cachedir(_handle, s)); } public LogLevel LogLevel { get; set; } = LogLevel.Error; public void Dispose() { _handle.Dispose(); } private Database ToDatabase(IntPtr ptr) { // It's ok that the database pointer is kept outside atomic section, because the resource is actually // managed by the alpm handle. if (ptr == IntPtr.Zero) throw new AlpmException(_handle); return new Database(new SafeDatabaseHandle(ptr, _handle)); } public Database RegisterSyncDB(string treename, SigLevel sigLevel = 0) { return ToDatabase(alpm.alpm_register_syncdb(_handle, treename, sigLevel)); } public void AddCacheDir(string dir) { Detail.WrapError(_handle, () => alpm.alpm_option_add_cachedir(_handle, dir)); } public bool RemoveCacheDir(string dir) { return Detail.WrapErrorBool(_handle, () => alpm.alpm_option_remove_cachedir(_handle, dir)); } public bool ShouldIgnorePackage(Package pkg) { return alpm.alpm_pkg_should_ignore(_handle, pkg.Handle) == 0; } public event EventHandler Log { add { void LogCallback(LogLevel level, IntPtr format, IntPtr args) { if (level > LogLevel) return; _logEvent?.Invoke(this, new LogEventArgs {Level = level, Message = CFormatter.Format(format, args)}); } lock (_eventLock) { var wasEmpty = _logEvent == null; _logEvent += value; if (wasEmpty) alpm.alpm_option_set_logcb(_handle, LogCallback); } } remove { lock (_eventLock) { // ReSharper disable once DelegateSubtraction _logEvent -= value; if (_logEvent == null) alpm.alpm_option_set_logcb(_handle, null); } } } public struct LogEventArgs { public LogLevel Level; public string Message; } } }