// Copyright (c) 2017 schick Informatik using System; using System.Collections.Generic; using log4net; using bsmd.database; using System.ServiceModel.Activation; using System.Timers; namespace bsmd.LockingService { [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class LockingService : IService { private static ILog _log = LogManager.GetLogger(typeof(LockingService)); private static Dictionary lockDict = new Dictionary(); private static Timer staleTimer = new Timer(5000); // alle 5 Sekunden prüfen private const int staleTimeoutSeconds = 120; // wenn sie eine Anwendung 2 Minuten nicht meldet, werden die Locks freigegeben static LockingService() { staleTimer.Elapsed += StaleTimer_Elapsed; } private static void StaleTimer_Elapsed(object sender, ElapsedEventArgs e) { lock (lockDict) { List deleteList = new List(); foreach (Guid key in lockDict.Keys) if ((DateTime.Now - lockDict[key].lockAquired).TotalSeconds > staleTimeoutSeconds) deleteList.Add(key); foreach (Guid key in deleteList) { _log.WarnFormat("Stale remove message core id {0}, User {1}", key, lockDict[key].userId); lockDict.Remove(key); } } } private ILog log = LogManager.GetLogger(typeof(LockingService)); public bool Lock(Guid messageCoreId, string userId) { if (userId.IsNullOrEmpty()) return false; bool result = false; lock (lockDict) { if (!lockDict.ContainsKey(messageCoreId)) { LockEntry le = new LockEntry(); le.lockAquired = DateTime.Now; le.userId = userId; lockDict.Add(messageCoreId, le); result = true; } else { if (lockDict[messageCoreId].userId == userId) { lockDict[messageCoreId].lockAquired = DateTime.Now; result = true; } } } return result; } public void Unlock(Guid messageCoreId, string userId) { if (userId.IsNullOrEmpty()) return; lock(lockDict) { if(lockDict.ContainsKey(messageCoreId)) { if (lockDict[messageCoreId].userId == userId) lockDict.Remove(messageCoreId); } } } public void LockRefresh(List currentLocks, string userId) { foreach (Guid messageCoreId in currentLocks) this.Lock(messageCoreId, userId); } public void Log(string msg, string host, string userId) { log.Info(string.Format("{0} {1}:{2}", host, userId, msg)); } internal class LockEntry { public DateTime lockAquired = DateTime.Now; public string userId = string.Empty; } } }