272 lines
14 KiB
C#
272 lines
14 KiB
C#
|
|
using DTS.Common.Classes.Locking;
|
|||
|
|
using DTS.Common.Utilities.Logging;
|
|||
|
|
using System;
|
|||
|
|
using System.Data;
|
|||
|
|
using System.Data.SqlClient;
|
|||
|
|
namespace DTS.Common.Storage
|
|||
|
|
{
|
|||
|
|
public class LockManager
|
|||
|
|
{
|
|||
|
|
public static bool FreeLock(int itemId, string userName, int? userId, out LockError error, int categoryId)
|
|||
|
|
{
|
|||
|
|
error = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|||
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_LockFree.ToString();
|
|||
|
|
|
|||
|
|
#region params
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@UserId", SqlDbType.Int) { Value = userId });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@UserName", SqlDbType.NVarChar, 50) { Value = userName });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@ItemId", SqlDbType.Int) { Value = itemId });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@CategoryId", SqlDbType.Int) { Value = categoryId });
|
|||
|
|
|
|||
|
|
var errorNumber = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(errorNumber);
|
|||
|
|
|
|||
|
|
var errorMessage = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(errorMessage);
|
|||
|
|
|
|||
|
|
#endregion params
|
|||
|
|
|
|||
|
|
cmd.ExecuteNonQuery();
|
|||
|
|
var errorCode = int.Parse(errorNumber.Value.ToString());
|
|||
|
|
switch (errorCode)
|
|||
|
|
{
|
|||
|
|
case 0: return true; //all cool, lock updated
|
|||
|
|
case 1: //test setup not found
|
|||
|
|
case 2: //user not found
|
|||
|
|
error = new LockError(errorCode,
|
|||
|
|
(errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
case 3: //no lock to update
|
|||
|
|
error = new LockError(3, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
default:
|
|||
|
|
error = new LockError(4, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
finally { cmd.Connection.Dispose(); }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
APILogger.Log(ex);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool UpdateLock(int itemId, int categoryId, string userName, int? userId, out LockError error)
|
|||
|
|
{
|
|||
|
|
error = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|||
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_LockUpdate.ToString();
|
|||
|
|
|
|||
|
|
#region params
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@UserId", SqlDbType.Int) { Value = userId });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@UserName", SqlDbType.NVarChar, 50) { Value = userName });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@ItemId", SqlDbType.Int) { Value = itemId });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@CategoryId", SqlDbType.Int) { Value = categoryId });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@MachineName", SqlDbType.NVarChar, 50) { Value = Environment.MachineName });
|
|||
|
|
|
|||
|
|
var errorNumber = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(errorNumber);
|
|||
|
|
|
|||
|
|
var errorMessage = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(errorMessage);
|
|||
|
|
|
|||
|
|
var lockingUser = new SqlParameter("@LockingUser", SqlDbType.NVarChar, 50) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockingUser);
|
|||
|
|
|
|||
|
|
var lockingMachine = new SqlParameter("@LockingMachine", SqlDbType.NVarChar, 50) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockingMachine);
|
|||
|
|
|
|||
|
|
var lastTimeUsed = new SqlParameter("@LastUsedTime", SqlDbType.DateTime) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lastTimeUsed);
|
|||
|
|
|
|||
|
|
var lockCreateTime = new SqlParameter("@LockCreateTime", SqlDbType.DateTime) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockCreateTime);
|
|||
|
|
|
|||
|
|
#endregion params
|
|||
|
|
|
|||
|
|
cmd.ExecuteNonQuery();
|
|||
|
|
|
|||
|
|
var errorCode = int.Parse(errorNumber.Value.ToString());
|
|||
|
|
switch (errorCode)
|
|||
|
|
{
|
|||
|
|
case 0: return true; //all cool, lock updated
|
|||
|
|
case 1: //test setup not found
|
|||
|
|
case 2: //user not found
|
|||
|
|
error = new LockError(errorCode,
|
|||
|
|
(errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
case 3: //no lock to update
|
|||
|
|
error = new LockError(LockError.LOCKDOESNTEXIST_ERROR, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
case 4: //lock stolen
|
|||
|
|
error = new LockError(LockError.LOCKSTOLEN_ERROR,
|
|||
|
|
$"Lock now belongs to user {lockingUser.Value}:{lockingMachine.Value}", (string)lockingUser.Value, (string)lockingMachine.Value);
|
|||
|
|
return false;
|
|||
|
|
default:
|
|||
|
|
error = new LockError(4, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
finally { cmd.Connection.Dispose(); }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (SqlException ex)
|
|||
|
|
{
|
|||
|
|
switch (ex.Number)
|
|||
|
|
{
|
|||
|
|
case ERROR_BAD_NETPATH:
|
|||
|
|
error = new LockError(LockError.BAD_NETPATH_ERROR, Strings.Strings.BAD_NETPATH_ERROR_MSG);
|
|||
|
|
break;
|
|||
|
|
case ERROR_SEM_TIMEOUT:
|
|||
|
|
error = new LockError(LockError.SEM_TIMEOUT_ERROR, Strings.Strings.SEM_TIME_ERROR_MSG);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
APILogger.Log("SqlException in UpdateLock", ex);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
APILogger.Log("Exception in UpdateLock", ex);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
/// <summary>
|
|||
|
|
/// The semaphore timeout period has expired
|
|||
|
|
/// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-?redirectedfrom=MSDN
|
|||
|
|
/// </summary>
|
|||
|
|
private const int ERROR_SEM_TIMEOUT = 0x00000079;
|
|||
|
|
/// <summary>
|
|||
|
|
/// network path not found, apparently also can occur during lock management?
|
|||
|
|
/// 14782 Improve lost remote db connection modal dialogs
|
|||
|
|
/// </summary>
|
|||
|
|
private const int ERROR_BAD_NETPATH = 0x00000035;
|
|||
|
|
public enum ItemCategories
|
|||
|
|
{
|
|||
|
|
TestSetup,
|
|||
|
|
Group,
|
|||
|
|
Sensor,
|
|||
|
|
SystemSettings
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool LockItem(string itemKey,
|
|||
|
|
int itemId,
|
|||
|
|
ItemCategories itemCategory,
|
|||
|
|
string userName,
|
|||
|
|
int? userId,
|
|||
|
|
out LockRecord existingLock, out
|
|||
|
|
LockError error)
|
|||
|
|
{
|
|||
|
|
error = null;
|
|||
|
|
existingLock = null;
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using (var cmd = DbOperations.GetSQLCommand(true))
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
cmd.CommandType = CommandType.StoredProcedure;
|
|||
|
|
cmd.CommandText = DbOperationsEnum.StoredProcedure.sp_LockGet.ToString();
|
|||
|
|
|
|||
|
|
#region params
|
|||
|
|
int? id = null;
|
|||
|
|
if (itemId > 0) { id = itemId; } //NOTE YOU"LL NEED THE ID TO FREE, AND THE CURRENT SP DOESN'T RETURN IT
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@UserId", SqlDbType.Int) { Value = userId });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@UserName", SqlDbType.NVarChar, 50) { Value = userName });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@ItemId", SqlDbType.Int) { Value = id });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@ItemKey", SqlDbType.NVarChar, 50) { Value = itemKey });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@ItemCategory", SqlDbType.NVarChar, 50) { Value = itemCategory.ToString() });
|
|||
|
|
cmd.Parameters.Add(new SqlParameter("@MachineName", SqlDbType.NVarChar, 50) { Value = Environment.MachineName });
|
|||
|
|
|
|||
|
|
var errorNumber = new SqlParameter("@errorNumber", SqlDbType.Int) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(errorNumber);
|
|||
|
|
|
|||
|
|
var errorMessage = new SqlParameter("@errorMessage", SqlDbType.NVarChar, 250) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(errorMessage);
|
|||
|
|
|
|||
|
|
var lockingUser = new SqlParameter("@LockingUser", SqlDbType.NVarChar, 50) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockingUser);
|
|||
|
|
|
|||
|
|
var lockingMachine = new SqlParameter("@LockingMachineName", SqlDbType.NVarChar, 50) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockingMachine);
|
|||
|
|
|
|||
|
|
var lastTimeUsed = new SqlParameter("@LastUsedTime", SqlDbType.DateTime) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lastTimeUsed);
|
|||
|
|
|
|||
|
|
var lockCreateTime = new SqlParameter("@LockCreateTime", SqlDbType.DateTime) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockCreateTime);
|
|||
|
|
|
|||
|
|
var lockItemCategory = new SqlParameter("@LockedItemCategory", SqlDbType.Int) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockItemCategory);
|
|||
|
|
|
|||
|
|
var lockedItemId = new SqlParameter("@LockedItemId", SqlDbType.Int) { Direction = ParameterDirection.Output };
|
|||
|
|
cmd.Parameters.Add(lockedItemId);
|
|||
|
|
|
|||
|
|
#endregion params
|
|||
|
|
|
|||
|
|
cmd.ExecuteNonQuery();
|
|||
|
|
|
|||
|
|
int resultItemId = itemId;
|
|||
|
|
if (itemId < 0)
|
|||
|
|
{
|
|||
|
|
if (!DBNull.Value.Equals(lockedItemId.Value))
|
|||
|
|
{
|
|||
|
|
resultItemId = Convert.ToInt32(lockedItemId.Value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var errorCode = int.Parse(errorNumber.Value.ToString());
|
|||
|
|
switch (errorCode)
|
|||
|
|
{
|
|||
|
|
case 0:
|
|||
|
|
existingLock = new LockRecord(userName, Environment.MachineName, DateTime.Now, DateTime.Now, itemKey, Convert.ToInt32(lockItemCategory.Value), resultItemId);
|
|||
|
|
return true; //all cool, locked away
|
|||
|
|
case 1: //item not found
|
|||
|
|
error = new LockError(LockError.ITEM_NOT_FOUND, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
case 2: //user not found
|
|||
|
|
error = new LockError(errorCode,
|
|||
|
|
(errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
case 3: //already locked
|
|||
|
|
existingLock = new LockRecord((string)lockingUser.Value,
|
|||
|
|
(string)lockingMachine.Value, Convert.ToDateTime(lockCreateTime.Value),
|
|||
|
|
Convert.ToDateTime(lastTimeUsed.Value), itemKey, Convert.ToInt32(lockItemCategory.Value), resultItemId);
|
|||
|
|
error = new LockError(errorCode, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
default:
|
|||
|
|
error = new LockError(LockError.UNKNOWN_ERROR, (errorMessage.Value as string) ?? $"{errorCode}");
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
finally { cmd.Connection.Dispose(); }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
APILogger.Log(ex);
|
|||
|
|
error = new LockError(LockError.UNKNOWN_ERROR, ex.Message);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
}
|