mirror of
https://gitee.com/xiarenalofs/squad-rain-ops-mini.git
synced 2026-08-09 22:55:57 +08:00
222 lines
6.9 KiB
C#
222 lines
6.9 KiB
C#
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
|
||
public class FileTimestampAndSizeWatcher
|
||
{
|
||
private readonly string _filePath;
|
||
private DateTime _lastModifiedTime;
|
||
private long _lastFileSize;
|
||
public static long _lastReadPosition;
|
||
private Timer _pollingTimer;
|
||
private FileSystemWatcher _watcher;
|
||
|
||
public event Action<string> OnFileUpdated;
|
||
|
||
private readonly ConcurrentQueue<string> _logQueue = new ConcurrentQueue<string>();
|
||
private readonly AutoResetEvent _logEvent = new AutoResetEvent(false);
|
||
private bool _isConsuming = false;
|
||
private readonly int _maxQueueSize = 1000000; // 璁剧疆鏈€澶ч槦鍒楀ぇ灏?
|
||
private readonly int _maxRetries = 5; // 鏈€澶ч噸璇曟鏁?
|
||
private readonly int _retryDelay = 1000; // 閲嶈瘯闂撮殧锛屽崟浣嶏細姣
|
||
|
||
public FileTimestampAndSizeWatcher(string filePath)
|
||
{
|
||
_filePath = filePath;
|
||
_lastModifiedTime = File.GetLastWriteTime(_filePath);
|
||
_lastFileSize = new FileInfo(_filePath).Length;
|
||
|
||
// 鍚姩鏃朵粠澶村紑濮嬭鍙?
|
||
_lastReadPosition = 0;
|
||
|
||
}
|
||
|
||
|
||
public void Start()
|
||
{
|
||
// 鍚姩鏃跺垱寤哄垵濮嬬殑 FileSystemWatcher
|
||
CreateWatcher();
|
||
|
||
//鍚敤鏃ュ織娑堣垂
|
||
StartLogConsumer();
|
||
|
||
// 鍒濆璇诲彇鏂囦欢鎵€鏈夊唴瀹?
|
||
string initialContent = ReadFileContent();
|
||
ProcessLogContent(initialContent);
|
||
|
||
// 璁剧疆瀹氭椂鍣紝姣忓垎閽熷埛鏂颁竴娆?FileSystemWatcher
|
||
_pollingTimer = new Timer(RefreshWatcher, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
|
||
}
|
||
|
||
private void CreateWatcher()
|
||
{
|
||
// 鍒涘缓鏂扮殑 FileSystemWatcher 瀹炰緥
|
||
_watcher = new FileSystemWatcher(Path.GetDirectoryName(_filePath))
|
||
{
|
||
Filter = Path.GetFileName(_filePath),
|
||
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
|
||
};
|
||
|
||
// 娉ㄥ唽浜嬩欢澶勭悊绋嬪簭
|
||
_watcher.Changed += OnChanged;
|
||
|
||
// 鍚姩鐩戝惉
|
||
_watcher.EnableRaisingEvents = true;
|
||
}
|
||
|
||
private void RefreshWatcher(object state)
|
||
{
|
||
try
|
||
{
|
||
// 绂佺敤鐜版湁鐨?FileSystemWatcher锛堝彧鏄仠姝㈣Е鍙戜簨浠讹紝瀹炰緥渚濈劧瀛樺湪锛?
|
||
_watcher.EnableRaisingEvents = false;
|
||
|
||
// 閲婃斁鐜版湁鐨?FileSystemWatcher 瀹炰緥
|
||
_watcher.Dispose();
|
||
|
||
// 閲嶆柊鍒涘缓 FileSystemWatcher锛屽苟閲嶆柊娉ㄥ唽浜嬩欢澶勭悊绋嬪簭
|
||
CreateWatcher();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
RainOpsMini.Helpers.RainOpsLog.Log($"鍒锋柊 FileSystemWatcher 鏃跺彂鐢熷紓甯? {ex.Message}");
|
||
}
|
||
}
|
||
|
||
private string ReadFileContent()
|
||
{
|
||
string newContent = string.Empty;
|
||
|
||
for (int retries = 0; retries < _maxRetries; retries++)
|
||
{
|
||
try
|
||
{
|
||
// 浣跨敤 FileStream 浠ュ彧璇诲拰鍏变韩璇诲彇鍐欏叆鐨勬ā寮忔墦寮€鏂囦欢
|
||
using (var stream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||
{
|
||
stream.Seek(_lastReadPosition, SeekOrigin.Begin);
|
||
|
||
using (var reader = new StreamReader(stream))
|
||
{
|
||
newContent = reader.ReadToEnd();
|
||
_lastReadPosition = stream.Position; // 鏇存柊璇诲彇浣嶇疆
|
||
}
|
||
}
|
||
|
||
break; // 鎴愬姛璇诲彇鏂囦欢鍚庤烦鍑洪噸璇?
|
||
}
|
||
catch (IOException ex)
|
||
{
|
||
// 璁板綍姣忔閲嶈瘯澶辫触鐨勪俊鎭?
|
||
if (retries == _maxRetries - 1)
|
||
{
|
||
throw; // 濡傛灉閲嶈瘯瓒呰繃鏈€澶ф鏁帮紝鎶涘嚭寮傚父
|
||
}
|
||
Thread.Sleep(_retryDelay); // 绛夊緟涓€娈垫椂闂村悗閲嶈瘯
|
||
}
|
||
}
|
||
|
||
return newContent;
|
||
}
|
||
|
||
private void OnChanged(object sender, FileSystemEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
DateTime currentModifiedTime = File.GetLastWriteTime(_filePath);
|
||
long currentFileSize = new FileInfo(_filePath).Length;
|
||
|
||
if (currentFileSize < _lastReadPosition)
|
||
{
|
||
_lastReadPosition = 0;
|
||
}
|
||
|
||
if (currentModifiedTime != _lastModifiedTime || currentFileSize != _lastFileSize)
|
||
{
|
||
_lastModifiedTime = currentModifiedTime;
|
||
_lastFileSize = currentFileSize;
|
||
|
||
string newContent = ReadFileContent(); // 璋冪敤鏂扮殑鏂囦欢璇诲彇鏂规硶
|
||
ProcessLogContent(newContent);
|
||
}
|
||
}
|
||
catch (IOException ex)
|
||
{
|
||
}
|
||
}
|
||
|
||
private void ProcessLogContent(string content)
|
||
{
|
||
if (!string.IsNullOrWhiteSpace(content))
|
||
{
|
||
var logs = content
|
||
.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)
|
||
.ToList();
|
||
|
||
foreach (var log in logs)
|
||
{
|
||
if (_logQueue.Count >= _maxQueueSize)
|
||
{
|
||
// 涓㈠純鏈€鑰佺殑鏃ュ織
|
||
_logQueue.TryDequeue(out _);
|
||
}
|
||
_logQueue.Enqueue(log);
|
||
}
|
||
|
||
_logEvent.Set(); // 閫氱煡娑堣垂鑰呮湁鏂版暟鎹?
|
||
}
|
||
}
|
||
|
||
private void StartLogConsumer()
|
||
{
|
||
if (_isConsuming) return;
|
||
_isConsuming = true;
|
||
|
||
Thread consumerThread = new Thread(() =>
|
||
{
|
||
while (_isConsuming)
|
||
{
|
||
while (_logQueue.TryDequeue(out var log))
|
||
{
|
||
try
|
||
{
|
||
// 浣跨敤绾跨▼姹犳潵澶勭悊鍥炶皟锛岀‘淇濆洖璋冪殑澶氱嚎绋嬪鐞?
|
||
ThreadPool.QueueUserWorkItem(state =>
|
||
{
|
||
try
|
||
{
|
||
OnFileUpdated?.Invoke(log);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
}
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
}
|
||
}
|
||
|
||
// 鎵归噺澶勭悊鏃ュ織锛岄伩鍏嶉绻佸敜閱?
|
||
_logEvent.WaitOne();
|
||
}
|
||
});
|
||
|
||
consumerThread.IsBackground = true;
|
||
consumerThread.Start();
|
||
}
|
||
|
||
public void Stop()
|
||
{
|
||
_watcher?.Dispose();
|
||
_pollingTimer?.Dispose();
|
||
|
||
_isConsuming = false;
|
||
_logEvent.Set(); // 閫€鍑虹嚎绋嬮樆濉?
|
||
}
|
||
}
|
||
|