using System; using System.Collections.Concurrent; using System.Globalization; using System.IO; using System.Linq; using System.Threading; using Inspectron.Ringbuffer.Interfaces; namespace Inspectron.Ringbuffer { public class RingbufferPath : IFolderWritter,IDisposable { private readonly string _pathFormat; private readonly RingbufferPathConfiguration _configuration; private readonly IFileVerifier _fileVerifier; public const string PRODUCT = "$PRODUCT$"; public const string GOODBAD = "$GOODBAD$"; public const string DATE = "$date$"; public const string MONTH = "$month$"; public const string YEAR = "$year$"; private IIndex _index; ConcurrentQueue _saveQueue = new ConcurrentQueue(); object _lock = new object(); private string _ringbufferFolder; private int _productPartId; private int _goodBadPartId; private int _subPartId; public RingbufferPath(RingbufferPathConfiguration configuration, IFileVerifier fileVerifier) { _pathFormat = configuration.PathFormat; _configuration = configuration; _fileVerifier = fileVerifier; var pathFormat = configuration.PathFormat; var pathParts = Path.Combine(configuration.RootDirectory,pathFormat).Split(new char[]{ Path.DirectorySeparatorChar },StringSplitOptions.RemoveEmptyEntries); _ringbufferFolder = configuration.RootDirectory; _productPartId = -1; _goodBadPartId = -1; for (int i = 1; i < pathParts.Length; i++) { if (pathParts[i] == PRODUCT) _productPartId = i; if (pathParts[i] == GOODBAD) _goodBadPartId = i; } //if(_productPartId==-1||_goodBadPartId==-1)throw new Exception("one of the markers is missing"); EnsureDirectory(_ringbufferFolder); InitIndex(); var th1 = new Thread(RemoveLoop); th1.IsBackground = true; th1.Priority = ThreadPriority.Normal; th1.Start(); var th2 = new Thread(SaveLoop); th2.IsBackground = true; th2.Priority = ThreadPriority.Normal; th2.Start(); } private void InitIndex() { _index = new GroupIndex(_configuration.GroupPartId,_goodBadPartId); IndexFiles(); } private void IndexFiles() { var allFiles = Directory.GetFiles(_ringbufferFolder, "*.*", SearchOption.AllDirectories); var verifiedFiles = allFiles.Where(x => _fileVerifier.IsMainFile(x)).ToList(); var orderedFiles = verifiedFiles.OrderByDescending(x => new FileInfo(x).CreationTimeUtc).ToList(); orderedFiles.ForEach(_index.Track); } private void RemoveLoop() { while (!_stop) { var filesToDelete = _index.GetFilesToDelete(_configuration.MaxAmountOfGoodImages, _configuration.MaxAmountOfBadImages); filesToDelete.ForEach(x => { DeleteFile(x); _fileVerifier.LinkedFiles(x).ForEach(DeleteFile); }); Thread.Sleep(1000); } } public void DeleteFile(string fileToDelete) { var fi = new System.IO.FileInfo(fileToDelete); if (fi.Exists) { lock (_lock) { fi.Delete(); } fi.Refresh(); while (fi.Exists) { System.Threading.Thread.Sleep(10); fi.Refresh(); } } } private bool _stop = false; private void SaveLoop() { while (!_stop) { if (_saveQueue.TryDequeue(out var candidate)) { lock (_lock) { EnsureDirectory(candidate.TargetDirectory); var written = candidate.FileIdentity.WriteTo(candidate.TargetDirectory); _index.Track(written); } } else { Thread.Sleep(1); } } } private void EnsureDirectory(string directory) { if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } } public static string GOOD_DIR = "Good"; public static string BAD_DIR = "Bad"; string TransformPath(string originalPath,bool isGood,string product) { var time = DateTime.Now; var res= originalPath.Replace(PRODUCT, product) .Replace(GOODBAD, isGood ? GOOD_DIR : BAD_DIR) .Replace(MONTH,time.ToString("MMMM")) .Replace(YEAR,time.Year.ToString()) .Replace(DATE,time.ToString("dd.MM.yyyy")); return Path.Combine(_configuration.RootDirectory, res); } public void WriteGood(IFileIdentity fileIdentity, string product) { var path = TransformPath(_configuration.PathFormat, true, product); _saveQueue.Enqueue(new SaveCandidate(fileIdentity, path)); } public void WriteBad(IFileIdentity fileIdentity, string product) { var path = TransformPath(_configuration.PathFormat, false, product); _saveQueue.Enqueue(new SaveCandidate(fileIdentity, path)); } public void Dispose() { _stop = true; } } }