|
@@ -1,11 +1,11 @@
|
|
|
-using System.Collections.Concurrent;
|
|
|
|
|
-using System.IO.Abstractions;
|
|
|
|
|
|
|
+using System.IO.Abstractions;
|
|
|
using System.Text.Json;
|
|
using System.Text.Json;
|
|
|
using Quadarax.Foundation.Core.Collections;
|
|
using Quadarax.Foundation.Core.Collections;
|
|
|
using Quadarax.Foundation.Core.Json.Extensions;
|
|
using Quadarax.Foundation.Core.Json.Extensions;
|
|
|
using Quadarax.Foundation.Core.Logging;
|
|
using Quadarax.Foundation.Core.Logging;
|
|
|
using Quadarax.Foundation.Core.QMonitor.Interfaces;
|
|
using Quadarax.Foundation.Core.QMonitor.Interfaces;
|
|
|
using Quadarax.Foundation.Core.Object;
|
|
using Quadarax.Foundation.Core.Object;
|
|
|
|
|
+using Quadarax.Foundation.Core.Thread;
|
|
|
using Quadarax.Foundation.Core.Value.Extensions;
|
|
using Quadarax.Foundation.Core.Value.Extensions;
|
|
|
|
|
|
|
|
namespace Quadarax.Foundation.Core.QMonitor
|
|
namespace Quadarax.Foundation.Core.QMonitor
|
|
@@ -28,7 +28,9 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public bool IsLiveBroadcast {get; private set; }
|
|
public bool IsLiveBroadcast {get; private set; }
|
|
|
- public DateTime? Timestamp { get; private set; }
|
|
|
|
|
|
|
+
|
|
|
|
|
+ public DateTime? Timestamp => _currentTimestampFtUtc == null ? null : DateTime.FromFileTimeUtc(_currentTimestampFtUtc.Value);
|
|
|
|
|
+
|
|
|
public TimeSpan RefreshInterval { get => _refreshInterval; set => SetRefreshInterval(value); }
|
|
public TimeSpan RefreshInterval { get => _refreshInterval; set => SetRefreshInterval(value); }
|
|
|
public MonData[]? CurrentData { get; private set; }
|
|
public MonData[]? CurrentData { get; private set; }
|
|
|
public event ReceiverHandlerStateChanged? ReceiverHandlerStateChanged;
|
|
public event ReceiverHandlerStateChanged? ReceiverHandlerStateChanged;
|
|
@@ -44,10 +46,11 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
private string _cachePath;
|
|
private string _cachePath;
|
|
|
private ILog? _log;
|
|
private ILog? _log;
|
|
|
private IFileSystemWatcher? _watcher;
|
|
private IFileSystemWatcher? _watcher;
|
|
|
- private Timer _refreshTimer;
|
|
|
|
|
|
|
+ private LoopWorker _refreshTimer;
|
|
|
private readonly LockedList<DataCacheItem> _dataCache = new();
|
|
private readonly LockedList<DataCacheItem> _dataCache = new();
|
|
|
|
|
+ private ILogger? _logger;
|
|
|
|
|
|
|
|
- private bool _isOverlapOnRefreshTimer;
|
|
|
|
|
|
|
+ private long? _currentTimestampFtUtc;
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
|
|
#region *** Constructor ***
|
|
#region *** Constructor ***
|
|
@@ -57,7 +60,8 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
if (string.IsNullOrEmpty(cachePath)) throw new ArgumentNullException(nameof(cachePath));
|
|
if (string.IsNullOrEmpty(cachePath)) throw new ArgumentNullException(nameof(cachePath));
|
|
|
_cachePath = cachePath;
|
|
_cachePath = cachePath;
|
|
|
_log = logger?.GetLogger(nameof(QMonReceiverHandler));
|
|
_log = logger?.GetLogger(nameof(QMonReceiverHandler));
|
|
|
-
|
|
|
|
|
|
|
+ _logger = logger;
|
|
|
|
|
+
|
|
|
if(string.IsNullOrEmpty(instanceIdentifier)) throw new ArgumentNullException(nameof(instanceIdentifier));
|
|
if(string.IsNullOrEmpty(instanceIdentifier)) throw new ArgumentNullException(nameof(instanceIdentifier));
|
|
|
|
|
|
|
|
InstanceIdentifier = instanceIdentifier;
|
|
InstanceIdentifier = instanceIdentifier;
|
|
@@ -69,7 +73,7 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
_watcher.Created += Watcher_Created;
|
|
_watcher.Created += Watcher_Created;
|
|
|
_watcher.Deleted += Watcher_Deleted;
|
|
_watcher.Deleted += Watcher_Deleted;
|
|
|
RefreshInterval = refreshInterval;
|
|
RefreshInterval = refreshInterval;
|
|
|
- Timestamp = GetLastAvailableDataTimestamp();
|
|
|
|
|
|
|
+ _currentTimestampFtUtc = GetLastAvailableDataTimestamp()?.ToFileTimeUtc();
|
|
|
_state = ReceiverHandlerStateEnum.Stop;
|
|
_state = ReceiverHandlerStateEnum.Stop;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -80,16 +84,16 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
if (_dataCache.Count == 0) return null;
|
|
if (_dataCache.Count == 0) return null;
|
|
|
- var first = _dataCache.Select(x => x.Timestamp).MinBy(x => x);
|
|
|
|
|
- return first;
|
|
|
|
|
|
|
+ var first = _dataCache.Select(x => x.TimestampFtUtc).MinBy(x => x);
|
|
|
|
|
+ return DateTime.FromFileTimeUtc(first);
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
public DateTime? GetLastAvailableDataTimestamp()
|
|
public DateTime? GetLastAvailableDataTimestamp()
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
if (_dataCache.Count == 0) return null;
|
|
if (_dataCache.Count == 0) return null;
|
|
|
- var last = _dataCache.Select(x => x.Timestamp).MinBy(x => x);
|
|
|
|
|
- return last;
|
|
|
|
|
|
|
+ var last = _dataCache.Select(x => x.TimestampFtUtc).MinBy(x => x);
|
|
|
|
|
+ return DateTime.FromFileTimeUtc(last);
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -140,13 +144,13 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var findTimestamp = (Timestamp ?? DateTime.Now);
|
|
var findTimestamp = (Timestamp ?? DateTime.Now);
|
|
|
- findTimestamp = isBackward ? findTimestamp.Subtract(duration.Value) : findTimestamp.Add(duration.Value);
|
|
|
|
|
|
|
+ var findTimestampFtUtc = (isBackward ? findTimestamp.Subtract(duration.Value) : findTimestamp.Add(duration.Value)).ToFileTimeUtc();
|
|
|
int newIndex = -1;
|
|
int newIndex = -1;
|
|
|
if (isBackward)
|
|
if (isBackward)
|
|
|
{
|
|
{
|
|
|
for (var i = 0; i < _dataCache.Count; i++)
|
|
for (var i = 0; i < _dataCache.Count; i++)
|
|
|
{
|
|
{
|
|
|
- if (_dataCache[i].Timestamp >= findTimestamp)
|
|
|
|
|
|
|
+ if (_dataCache[i].TimestampFtUtc >= findTimestampFtUtc)
|
|
|
{
|
|
{
|
|
|
newIndex = i;
|
|
newIndex = i;
|
|
|
break;
|
|
break;
|
|
@@ -159,7 +163,7 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
|
|
|
|
|
for (var i = _dataCache.Count - 1; i >= 0; i--)
|
|
for (var i = _dataCache.Count - 1; i >= 0; i--)
|
|
|
{
|
|
{
|
|
|
- if (_dataCache[i].Timestamp <= findTimestamp)
|
|
|
|
|
|
|
+ if (_dataCache[i].TimestampFtUtc <= findTimestampFtUtc)
|
|
|
{
|
|
{
|
|
|
newIndex = i;
|
|
newIndex = i;
|
|
|
break;
|
|
break;
|
|
@@ -208,11 +212,11 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
|
|
|
|
|
public void RewindToChange(bool isForward)
|
|
public void RewindToChange(bool isForward)
|
|
|
{
|
|
{
|
|
|
- if (Timestamp == null) return;
|
|
|
|
|
- var timestamp = Timestamp;
|
|
|
|
|
|
|
+ if (_currentTimestampFtUtc == null) return;
|
|
|
|
|
+ var timestamp = _currentTimestampFtUtc;
|
|
|
int currentIndex = -1;
|
|
int currentIndex = -1;
|
|
|
|
|
|
|
|
- var currentItem = _dataCache.FirstOrDefault(x => x.Timestamp == timestamp);
|
|
|
|
|
|
|
+ var currentItem = _dataCache.FirstOrDefault(x => x.TimestampFtUtc == _currentTimestampFtUtc);
|
|
|
if (currentItem == null) return;
|
|
if (currentItem == null) return;
|
|
|
currentIndex = _dataCache.IndexOf(currentItem);
|
|
currentIndex = _dataCache.IndexOf(currentItem);
|
|
|
|
|
|
|
@@ -232,7 +236,7 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
if (data != null)
|
|
if (data != null)
|
|
|
{
|
|
{
|
|
|
ReceiverHandlerDataChanged?.Invoke(this, data);
|
|
ReceiverHandlerDataChanged?.Invoke(this, data);
|
|
|
- Timestamp = item.Timestamp;
|
|
|
|
|
|
|
+ _currentTimestampFtUtc = item.TimestampFtUtc;
|
|
|
CurrentData = new[] { data };
|
|
CurrentData = new[] { data };
|
|
|
result = true;
|
|
result = true;
|
|
|
}
|
|
}
|
|
@@ -242,47 +246,34 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
|
|
|
|
|
private void SetRefreshInterval(TimeSpan refreshInterval)
|
|
private void SetRefreshInterval(TimeSpan refreshInterval)
|
|
|
{
|
|
{
|
|
|
|
|
+ _refreshTimer?.Stop(true);
|
|
|
_refreshInterval = refreshInterval;
|
|
_refreshInterval = refreshInterval;
|
|
|
_refreshTimer?.Dispose();
|
|
_refreshTimer?.Dispose();
|
|
|
- _log?.Log(LogSeverityEnum.Debug, $"[{InstanceIdentifier}/{Descriptor.Name}] Refresh interval was set to {RefreshInterval.ToReadableString()}");
|
|
|
|
|
- _refreshTimer = new Timer(OnRefreshTimer, this, TimeSpan.Zero, refreshInterval);
|
|
|
|
|
|
|
+ _log?.Log(LogSeverityEnum.Debug, $"[{InstanceIdentifier}/{Descriptor.Name}] Refresh interval was set to {_refreshInterval.ToReadableString()}");
|
|
|
|
|
+ _refreshTimer = new LoopWorker("ReceiverHandler",null,async (_)=>await OnRefreshTimer(this), _logger);
|
|
|
|
|
+ _refreshTimer.Start(_refreshInterval);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
- private void OnRefreshTimer(object? state)
|
|
|
|
|
|
|
+ private async Task OnRefreshTimer(object? state)
|
|
|
{
|
|
{
|
|
|
//TODO: add overlap checking here
|
|
//TODO: add overlap checking here
|
|
|
- if (!_isOverlapOnRefreshTimer)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if (State == ReceiverHandlerStateEnum.Play)
|
|
|
{
|
|
{
|
|
|
- _isOverlapOnRefreshTimer = true;
|
|
|
|
|
- try
|
|
|
|
|
- {
|
|
|
|
|
- if (State == ReceiverHandlerStateEnum.Play)
|
|
|
|
|
- {
|
|
|
|
|
- if (_dataCache.Count == 0) return;
|
|
|
|
|
- if (Timestamp < _dataCache.Last().Timestamp)
|
|
|
|
|
- {
|
|
|
|
|
- var currentItem = _dataCache.FirstOrDefault(x => x.Timestamp == Timestamp);
|
|
|
|
|
- if (currentItem == null) return;
|
|
|
|
|
- var currentIndex = _dataCache.IndexOf(currentItem);
|
|
|
|
|
- var newChangeIndex = FindNextChangeIndex(currentIndex, true);
|
|
|
|
|
- if (newChangeIndex >= 0)
|
|
|
|
|
- SetAsCurrent(_dataCache[newChangeIndex]);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- catch (Exception ex)
|
|
|
|
|
- {
|
|
|
|
|
- _log?.Log(LogSeverityEnum.Error,
|
|
|
|
|
- $"[{InstanceIdentifier}/{Descriptor.Name}] Error on refresh timer: {ex.Message}");
|
|
|
|
|
- }
|
|
|
|
|
- finally
|
|
|
|
|
|
|
+ if (_dataCache.Count == 0) return;
|
|
|
|
|
+ if (_currentTimestampFtUtc < _dataCache.Last().TimestampFtUtc)
|
|
|
{
|
|
{
|
|
|
- _isOverlapOnRefreshTimer = false;
|
|
|
|
|
|
|
+ var currentItem = _dataCache.FirstOrDefault(x => x.TimestampFtUtc == _currentTimestampFtUtc);
|
|
|
|
|
+ if (currentItem == null) return;
|
|
|
|
|
+ var currentIndex = _dataCache.IndexOf(currentItem);
|
|
|
|
|
+ var newChangeIndex = FindNextChangeIndex(currentIndex, true);
|
|
|
|
|
+ if (newChangeIndex >= 0)
|
|
|
|
|
+ SetAsCurrent(_dataCache[newChangeIndex]);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
private void RefreshFiles()
|
|
private void RefreshFiles()
|
|
|
{
|
|
{
|
|
@@ -362,13 +353,13 @@ namespace Quadarax.Foundation.Core.QMonitor
|
|
|
|
|
|
|
|
private class DataCacheItem
|
|
private class DataCacheItem
|
|
|
{
|
|
{
|
|
|
- public DateTime Timestamp { get; set; }
|
|
|
|
|
|
|
+ public long TimestampFtUtc { get; set; }
|
|
|
public JsonDocument Data { get; set; }
|
|
public JsonDocument Data { get; set; }
|
|
|
public string FileName { get; set; }
|
|
public string FileName { get; set; }
|
|
|
|
|
|
|
|
public DataCacheItem(string fileName, MonData data)
|
|
public DataCacheItem(string fileName, MonData data)
|
|
|
{
|
|
{
|
|
|
- Timestamp = data.Timestamp;
|
|
|
|
|
|
|
+ TimestampFtUtc = data.TimestampFtUtc;
|
|
|
Data = JsonDocument.Parse(data.Data);
|
|
Data = JsonDocument.Parse(data.Data);
|
|
|
FileName = fileName;
|
|
FileName = fileName;
|
|
|
}
|
|
}
|