214 lines
7.3 KiB
C#
214 lines
7.3 KiB
C#
// Copyright (c) 2017 schick Informatik
|
|
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using log4net;
|
|
using bsmd.database;
|
|
using System.ServiceModel.Activation;
|
|
using System.ServiceProcess;
|
|
using System.Timers;
|
|
using System.IO;
|
|
|
|
namespace bsmd.LockingService
|
|
{
|
|
|
|
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
|
|
public class LockingService : IService
|
|
{
|
|
private static readonly ILog _log = LogManager.GetLogger(typeof(LockingService));
|
|
private static readonly Dictionary<Guid, LockEntry> lockDict = new Dictionary<Guid, LockEntry>();
|
|
private static readonly 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<Guid> deleteList = new List<Guid>();
|
|
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 readonly ILog log = LogManager.GetLogger(typeof(LockingService));
|
|
|
|
#region Implementation IService
|
|
|
|
public Guid Lock(Guid messageCoreId, Guid userId)
|
|
{
|
|
Guid result = Guid.Empty;
|
|
|
|
lock (lockDict)
|
|
{
|
|
if (!lockDict.ContainsKey(messageCoreId))
|
|
{
|
|
LockEntry le = new LockEntry();
|
|
le.lockAquired = DateTime.Now;
|
|
le.userId = userId;
|
|
lockDict.Add(messageCoreId, le);
|
|
}
|
|
else
|
|
{
|
|
if (lockDict[messageCoreId].userId == userId)
|
|
{
|
|
// this means "refresh"
|
|
lockDict[messageCoreId].lockAquired = DateTime.Now;
|
|
}
|
|
else
|
|
{
|
|
// lock taken by somebody else..
|
|
result = lockDict[messageCoreId].userId;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
public void Unlock(Guid messageCoreId, Guid userId)
|
|
{
|
|
lock(lockDict)
|
|
{
|
|
if(lockDict.ContainsKey(messageCoreId))
|
|
{
|
|
if (lockDict[messageCoreId].userId == userId)
|
|
lockDict.Remove(messageCoreId);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void LockRefresh(List<Guid> currentLocks, Guid userId)
|
|
{
|
|
foreach (Guid messageCoreId in currentLocks)
|
|
this.Lock(messageCoreId, userId);
|
|
}
|
|
|
|
|
|
public void Log(string msg, string host, Guid userId)
|
|
{
|
|
log.Info(string.Format("{0} {1}:{2}", host, userId, msg));
|
|
}
|
|
|
|
public List<CoreLock> GetLocks()
|
|
{
|
|
List<CoreLock> result = new List<CoreLock>();
|
|
lock (lockDict)
|
|
{
|
|
foreach (Guid messageCoreId in lockDict.Keys)
|
|
{
|
|
CoreLock coreLock = new CoreLock();
|
|
coreLock.CoreId = messageCoreId;
|
|
coreLock.UserId = lockDict[messageCoreId].userId;
|
|
result.Add(coreLock);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public ServerStatus GetStatus()
|
|
{
|
|
ServerStatus serverStatus = new ServerStatus();
|
|
|
|
// Test if processes are running
|
|
ServiceController[] services = ServiceController.GetServices();
|
|
|
|
foreach (ServiceController serviceController in services)
|
|
{
|
|
switch (serviceController.ServiceName)
|
|
{
|
|
case "NSW Report Generator":
|
|
serverStatus.Report = (int)serviceController.Status;
|
|
break;
|
|
case "NSWSendService":
|
|
serverStatus.Transmitter = (int)serviceController.Status;
|
|
break;
|
|
case "ExcelReadService":
|
|
serverStatus.Excel = (int)serviceController.Status;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// collect file Names
|
|
// TODO: evtl. könnte es Sinn ergeben, wenn man diese Daten z.B. nur alle 10 Sekunden erzeugt und
|
|
// dann allen Aufrufern liefert.
|
|
|
|
serverStatus.IMPFiles = new List<string>();
|
|
string impPath = Path.Combine(Properties.Settings.Default.TransmitterRoot, "IMP");
|
|
if(Directory.Exists(impPath))
|
|
{
|
|
foreach(string file in Directory.GetFiles(impPath))
|
|
serverStatus.IMPFiles.Add(Path.GetFileNameWithoutExtension(file));
|
|
}
|
|
|
|
serverStatus.READYFiles = new List<string>();
|
|
string readyPath = Path.Combine(Properties.Settings.Default.TransmitterRoot, "READY");
|
|
if (Directory.Exists(readyPath))
|
|
{
|
|
foreach (string file in Directory.GetFiles(readyPath))
|
|
serverStatus.READYFiles.Add(Path.GetFileNameWithoutExtension(file));
|
|
}
|
|
|
|
serverStatus.CORRUPTFiles = new List<string>();
|
|
string corruptPath = Path.Combine(Properties.Settings.Default.TransmitterRoot, "CORRUPT");
|
|
if (Directory.Exists(corruptPath))
|
|
{
|
|
foreach (string file in Directory.GetFiles(corruptPath))
|
|
serverStatus.CORRUPTFiles.Add(Path.GetFileNameWithoutExtension(file));
|
|
}
|
|
|
|
return serverStatus;
|
|
}
|
|
|
|
public bool RestoreFromFile(string filename)
|
|
{
|
|
bool result = false;
|
|
string readyPath = Path.Combine(Properties.Settings.Default.TransmitterRoot, "READY");
|
|
string filePath = string.Format("{0}\\{1}.xml", readyPath, filename);
|
|
if(File.Exists(filePath))
|
|
{
|
|
_log.InfoFormat("Restoring declaraction class from {0}", filePath);
|
|
|
|
// TBD
|
|
|
|
result = true;
|
|
}
|
|
else
|
|
{
|
|
_log.ErrorFormat("Restore file {0} does not exist", filePath);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region class LockEntry
|
|
|
|
internal class LockEntry
|
|
{
|
|
public DateTime lockAquired = DateTime.Now;
|
|
public Guid userId;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
}
|