128 lines
4.3 KiB
C#
128 lines
4.3 KiB
C#
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;
|
|
|
|
#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));
|
|
AIS_SQLiteStorage sqliteStorage = new AIS_SQLiteStorage(_dbSaveTargets);
|
|
_tasks.Add(sqliteStorage);
|
|
|
|
// preload sit rep
|
|
Dictionary<int, AIS_Target> targets = await sqliteStorage.LoadTargets();
|
|
foreach(int key in targets.Keys)
|
|
{
|
|
_sitRepList.TryAdd(key, targets[key]);
|
|
}
|
|
|
|
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; }
|
|
}
|
|
|
|
#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
|
|
|
|
}
|
|
}
|