git_bsmd/AIS/bsmd.AIS2Service/AISManager.cs

135 lines
4.8 KiB
C#

// Copyright (c) 2022 - schick Informatik
// bsmd.AIS2Service [AISManager.cs]: %UserDisplayName%
// Description: Manager class that holds references to all concurrant threads
// and memory storage entities
using log4net;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using Microsoft.Owin.Hosting;
using System.Net.Http;
namespace bsmd.AIS2Service
{
internal static class AISManager
{
#region fields
private static readonly List<IAISThread> _tasks = new List<IAISThread>();
private static readonly ConcurrentQueue<string> _inputLines = new ConcurrentQueue<string>();
private static readonly ConcurrentQueue<AISClass> _decodedClasses = new ConcurrentQueue<AISClass>();
private static readonly ILog _log = LogManager.GetLogger(typeof(AISManager));
private static readonly ConcurrentDictionary<int, AIS_Target> _sitRepList = new ConcurrentDictionary<int, AIS_Target>();
private static readonly ConcurrentQueue<AIS_Target> _dbSaveTargets = new ConcurrentQueue<AIS_Target>();
private static Timer _staleTargetTimer; // cleanup sitrep
private static Timer _stalePosReportTimer; // clean db
private static IDisposable _restAPISelfHost = null;
private static AIS_SQLiteStorage _sqliteStorage = null;
#endregion
#region public methods
public static async void Start()
{
_tasks.Add(new SerialTCPReader(Properties.Settings.Default.DataSourceHost, Properties.Settings.Default.DataSourcePort, _inputLines));
_tasks.Add(new AISDecoder(_inputLines, _decodedClasses));
_tasks.Add(new SitRep(_decodedClasses, _sitRepList, _dbSaveTargets));
_sqliteStorage = new AIS_SQLiteStorage(_dbSaveTargets);
_tasks.Add(_sqliteStorage);
_tasks.Add(new AISZoneMonitor(_sitRepList, _sqliteStorage));
// preload sit rep
Dictionary<int, AIS_Target> targets = await _sqliteStorage.LoadTargets();
foreach(int key in targets.Keys)
{
_sitRepList.TryAdd(key, targets[key]);
}
_log.InfoFormat("preloaded {0} targets", _sitRepList.Count);
foreach (var task in _tasks)
{
task.Start();
_log.InfoFormat("{0} started", task.Name);
task.FatalErrorOccurred += Task_FatalErrorOccurred;
}
// init timer tasks
_staleTargetTimer = new Timer(StaleTargetTimerCheck, null, 0, 60000); // check every minute, start immediately
_stalePosReportTimer = new Timer(StalePosReportCheck, _sqliteStorage, 0, 60000 * 10); // every ten minutes,
// if required start self-hosted owin endpoint
if(Properties.Settings.Default.EnableRestAPIEndpoint)
{
_restAPISelfHost = WebApp.Start<StartupWebAPI>(url: Properties.Settings.Default.RestAPIBaseAddress);
}
}
public static void Stop()
{
foreach (var task in _tasks)
{
task.Stop();
_log.InfoFormat("{0} stopped", task.Name);
}
if (Properties.Settings.Default.EnableRestAPIEndpoint && (_restAPISelfHost != null))
_restAPISelfHost.Dispose();
_staleTargetTimer.Dispose();
_stalePosReportTimer.Dispose();
}
#endregion
#region Properties
public static ConcurrentDictionary<int, AIS_Target> SitRep { get { return _sitRepList; } }
public static AIS_SQLiteStorage SQLiteStorage { get { return _sqliteStorage; } }
#endregion
#region private methods / timer callbacks
private static void Task_FatalErrorOccurred(object sender, EventArgs e)
{
throw new NotImplementedException("TBD: shutdown the whole operation?");
}
private static void StaleTargetTimerCheck(object state)
{
List<int> removeKeyList = new List<int>();
foreach (int key in _sitRepList.Keys)
{
if (!_sitRepList[key].LastUpdate.HasValue) { removeKeyList.Add(key); }
else
{
if ((DateTime.Now - _sitRepList[key].LastUpdate.Value).TotalMinutes > Properties.Settings.Default.StaleTargetTimeoutMins)
removeKeyList.Add(key);
}
}
foreach(int key in removeKeyList)
{
_sitRepList.TryRemove(key, out _);
}
}
private static void StalePosReportCheck(object state)
{
if (state is AIS_SQLiteStorage storage)
{
storage.RemoveOldPosReports();
}
}
#endregion
}
}