mirror of
https://github.com/AlexMacocian/ServerManagementUtils.git
synced 2026-07-15 15:19:58 +00:00
132 lines
4.2 KiB
C#
132 lines
4.2 KiB
C#
using System.Extensions;
|
|
using System.Extensions.Core;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using Robin.Options;
|
|
using Robin.Services.Persistence;
|
|
|
|
namespace Robin.Services.Monitoring;
|
|
|
|
public sealed class MonitoringService(
|
|
PositionPersistenceService persistenceService,
|
|
IOptions<MonitorOptions> options,
|
|
ILogger<MonitoringService> logger
|
|
) : IHostedLifecycleService
|
|
{
|
|
private readonly PositionPersistenceService persistenceService = persistenceService;
|
|
private readonly MonitorOptions options = options.Value;
|
|
private readonly CancellationTokenSource cancellationTokenSource = new();
|
|
private readonly ILogger<MonitoringService> logger = logger;
|
|
private readonly List<Task> watchers = [];
|
|
|
|
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
|
|
public Task StartedAsync(CancellationToken cancellationToken) =>
|
|
this.MonitorFiles(cancellationToken);
|
|
|
|
public Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken) => this.CancelMonitors();
|
|
|
|
public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
|
|
public Task StoppingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
|
|
public Task CancelMonitors()
|
|
{
|
|
this.cancellationTokenSource.Cancel();
|
|
return Task.WhenAll(this.watchers);
|
|
}
|
|
|
|
public async Task MonitorFiles(CancellationToken cancellationToken)
|
|
{
|
|
var scopedLogger = this.logger.CreateScopedLogger();
|
|
scopedLogger.LogDebug(
|
|
"Starting file monitoring service. Parsing provided paths {paths}",
|
|
string.Join(", ", this.options.Paths)
|
|
);
|
|
var expandedPaths = ExpandPaths(this.options.Paths);
|
|
scopedLogger.LogInformation(
|
|
"Monitoring the following files: {files}",
|
|
string.Join(", ", expandedPaths)
|
|
);
|
|
|
|
var cts = CancellationTokenSource.CreateLinkedTokenSource(
|
|
cancellationToken,
|
|
this.cancellationTokenSource.Token
|
|
);
|
|
foreach (var filePath in expandedPaths)
|
|
{
|
|
this.watchers.Add(Task.Run(() => this.MonitorFile(filePath, cts.Token), cts.Token));
|
|
}
|
|
}
|
|
|
|
private async Task MonitorFile(string filePath, CancellationToken cancellationToken)
|
|
{
|
|
var scopedLogger = this.logger.CreateScopedLogger();
|
|
if (!File.Exists(filePath))
|
|
{
|
|
scopedLogger.LogWarning("File does not exist: {filePath}", filePath);
|
|
return;
|
|
}
|
|
|
|
scopedLogger.LogInformation("Starting to monitor file: {filePath}", filePath);
|
|
var previousPosition = this.persistenceService.GetPosition(filePath);
|
|
using var fs = new FileStream(
|
|
filePath,
|
|
FileMode.Open,
|
|
FileAccess.Read,
|
|
FileShare.ReadWrite | FileShare.Delete
|
|
);
|
|
|
|
if (fs.Length < previousPosition)
|
|
{
|
|
previousPosition = 0;
|
|
}
|
|
|
|
if (previousPosition > 0)
|
|
{
|
|
fs.Seek(previousPosition, SeekOrigin.Begin);
|
|
}
|
|
|
|
using var reader = new StreamReader(fs);
|
|
while (
|
|
(await reader.ReadLineAsync(cancellationToken)) is string line
|
|
&& !line.IsNullOrEmpty()
|
|
)
|
|
{
|
|
scopedLogger.LogDebug("Read line: {line}", line);
|
|
//TODO: Publish to IPublishingService
|
|
await this.persistenceService.SavePositionAsync(
|
|
filePath,
|
|
fs.Position,
|
|
cancellationToken
|
|
);
|
|
}
|
|
}
|
|
|
|
private static List<string> ExpandPaths(List<string>? patterns)
|
|
{
|
|
if (patterns is null || patterns.Count == 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var results = new List<string>();
|
|
foreach (var pattern in patterns)
|
|
{
|
|
var directory = Path.GetDirectoryName(pattern);
|
|
var filePattern = Path.GetFileName(pattern);
|
|
if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
results.AddRange(Directory.GetFiles(directory, filePattern));
|
|
}
|
|
|
|
return results;
|
|
}
|
|
}
|