using System; using System.Collections.Generic; using System.Linq; using System.Text; using DTS.Common.Classes.Locking; using DTS.Common.Import.Interfaces; using DTS.Common.SharedResource.Strings; using DTS.Common.Storage; using DTS.Common.Utilities.Logging; using DTS.SensorDB; using DTS.Slice.Users; //FB 36740 namespace DTS.Common.Import.DatabaseLocks { public class LockImportSensors : ILockImport { private readonly User _currentUser; private readonly double _strandedLockTimeoutMinutes; /// /// list of all sensors the user has locked /// private readonly List _lockedSensors = new List(); /// /// list of all sensors the user attempted to lock but another user has the lock /// private readonly List _contendedSensors = new List(); public bool Contended { get => _contendedSensors.Any(); } public LockImportSensors(User currentUser, double strandedLockTimeoutMinutes) { _currentUser = currentUser; _strandedLockTimeoutMinutes = strandedLockTimeoutMinutes; } public void FreeLock(ref ImportObject importObject) { if (!_lockedSensors.Any()) { return; } foreach (var record in _lockedSensors) { LockManager.FreeLock(record.ItemId, _currentUser.UserName, _currentUser.Id, out var lockError, record.ItemCategory); } } public void SetLock(ref ImportObject importObject, ref StringBuilder message) { var sensorLookup = SensorsCollection.SensorsList.GetAllSensors(true).ToDictionary(s => s.SerialNumber); _lockedSensors.Clear(); _contendedSensors.Clear(); foreach (var sensorSerialNumber in importObject.Sensors().Select(s => s.SerialNumber)) { if (!sensorLookup.ContainsKey(sensorSerialNumber)) { continue; } //no lock needed try { var wasAbleToLock = LockManager.LockItem(sensorSerialNumber, sensorLookup[sensorSerialNumber].DatabaseId, LockManager.ItemCategories.Sensor, _currentUser.UserName, _currentUser.Id, out var existingLock, out var lockError); if (!wasAbleToLock) { var lockOutOfDate = existingLock.LastUpdated.AddMinutes(_strandedLockTimeoutMinutes) < DateTime.Now; var IHaveTheLock = existingLock.LockingUserName == _currentUser.UserName && existingLock.LockingMachineName == Environment.MachineName; if (lockOutOfDate || IHaveTheLock) { //lock is expired (or already belongs to us), either way we can claim it LockManager.FreeLock(existingLock.ItemId, _currentUser.UserName, _currentUser.Id, out lockError, existingLock.ItemCategory); LockManager.LockItem(existingLock.ItemKey, existingLock.ItemId, LockManager.ItemCategories.Sensor, _currentUser.UserName, _currentUser.Id, out existingLock, out lockError); _lockedSensors.Add(existingLock); } else { //lock is not expired, we need admin + confirmation to steal the lock _contendedSensors.Add(existingLock); } } else { _lockedSensors.Add(existingLock); //successfully locked } } catch (Exception ex) { APILogger.Log(ex); } } if (!_contendedSensors.Any()) { return; } message.AppendLine(StringResources.ImportTestSetup_TestsLocked); foreach (var contended in _contendedSensors) { message.AppendLine($"{contended.ItemKey} by {contended.LockingUserName} on {contended.LockingMachineName}"); } } public bool StealLock(bool proceed) { if (!_contendedSensors.Any()) { return true; } if (!_currentUser.IsAdmin) { return false; } //steal locks if user oks it if (!proceed) { return false; } foreach (var contendedSensor in _contendedSensors) { LockManager.FreeLock(contendedSensor.ItemId, _currentUser.UserName, _currentUser.Id, out var lockError, contendedSensor.ItemCategory); LockManager.LockItem(contendedSensor.ItemKey, contendedSensor.ItemId, LockManager.ItemCategories.Sensor, _currentUser.UserName, _currentUser.Id, out var newLockRecord, out lockError); _lockedSensors.Add(newLockRecord); } return true; } } }