https sync

This commit is contained in:
Mike Phares 2025-04-10 09:16:01 -07:00
parent cc9c5013a9
commit fad2db46b5
5 changed files with 726 additions and 5 deletions

View File

@ -123,10 +123,9 @@ internal static partial class Helper20250404 {
internal static void KumaToGatus(ILogger<Worker> logger, List<string> args) { internal static void KumaToGatus(ILogger<Worker> logger, List<string> args) {
string url = args[4]; string url = args[4];
string check = args[5];
string fileName = args[3]; string fileName = args[3];
string searchPattern = args[2]; string searchPattern = args[2];
ParseMetrics(logger, fileName, url, check); ParseMetrics(logger, fileName, url);
string sourceDirectory = Path.GetFullPath(args[0]); string sourceDirectory = Path.GetFullPath(args[0]);
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories); string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
if (files.Length == 0) if (files.Length == 0)
@ -135,7 +134,7 @@ internal static partial class Helper20250404 {
KumaToGatus(files); KumaToGatus(files);
} }
private static void ParseMetrics(ILogger<Worker> logger, string fileName, string url, string check) { private static void ParseMetrics(ILogger<Worker> logger, string fileName, string url) {
FileStream fileStream = new(fileName, FileMode.Truncate); FileStream fileStream = new(fileName, FileMode.Truncate);
HttpClient httpClient = new(); HttpClient httpClient = new();
Task<Stream> streamTask = httpClient.GetStreamAsync(url); Task<Stream> streamTask = httpClient.GetStreamAsync(url);
@ -170,7 +169,7 @@ internal static partial class Helper20250404 {
} }
private static void KumaToGatus(string[] files) { private static void KumaToGatus(string[] files) {
Kuma kuma; Kuma? kuma;
string json; string json;
string checkFile; string checkFile;
foreach (string file in files) { foreach (string file in files) {

View File

@ -0,0 +1,693 @@
using System.Collections.ObjectModel;
using System.Text.Json;
using System.Text.Json.Serialization;
using File_Folder_Helper.Models;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.Logging;
#if ShellProgressBar
using ShellProgressBar;
#endif
namespace File_Folder_Helper.ADO2025.PI5;
internal static partial class Helper20250407 {
private record Record(string RelativePath,
long Size,
long Ticks);
private record Download(string Directory,
string Display,
string File,
long Size,
long Ticks,
string UniformResourceLocator);
private record Segment(Record? Left,
string? LeftDirectory,
Record? Right,
string RightDirectory,
string RootUniformResourceLocator);
private record Logic(char GreaterThan,
bool? LeftSideIsNewer,
int LeftSideIsNewerIndex,
bool? LeftSideOnly,
int LeftSideOnlyIndex,
char LessThan,
char Minus,
bool? NotEqualBut,
int NotEqualButIndex,
char Plus,
string[] Raw,
bool? RightSideIsNewer,
int RightSideIsNewerIndex,
bool? RightSideOnly,
int RightSideOnlyIndex) {
internal static Logic? Get(string[] segments) {
Logic? result;
bool check = true;
bool? notEqualBut;
bool? leftSideOnly;
bool? rightSideOnly;
bool? leftSideIsNewer;
const char plus = '+';
bool? rightSideIsNewer;
const char minus = '-';
const char lessThan = 'L';
const char greaterThan = 'G';
const int notEqualButIndex = 2;
const int leftSideOnlyIndex = 0;
const int rightSideOnlyIndex = 4;
const int leftSideIsNewerIndex = 1;
const int rightSideIsNewerIndex = 3;
if (string.IsNullOrEmpty(segments[leftSideOnlyIndex]))
leftSideOnly = null;
else if (segments[leftSideOnlyIndex][0] == plus)
leftSideOnly = true;
else if (segments[leftSideOnlyIndex][0] == minus)
leftSideOnly = false;
else {
check = false;
leftSideOnly = null;
}
if (string.IsNullOrEmpty(segments[leftSideIsNewerIndex]))
leftSideIsNewer = null;
else if (segments[leftSideIsNewerIndex][0] == greaterThan)
leftSideIsNewer = true;
else if (segments[leftSideIsNewerIndex][0] == lessThan)
leftSideIsNewer = false;
else {
check = false;
leftSideIsNewer = null;
}
if (string.IsNullOrEmpty(segments[notEqualButIndex]))
notEqualBut = null;
else if (segments[notEqualButIndex][0] == greaterThan)
notEqualBut = true;
else if (segments[notEqualButIndex][0] == lessThan)
notEqualBut = false;
else {
check = false;
notEqualBut = null;
}
if (string.IsNullOrEmpty(segments[rightSideIsNewerIndex]))
rightSideIsNewer = null;
else if (segments[rightSideIsNewerIndex][0] == greaterThan)
rightSideIsNewer = true;
else if (segments[rightSideIsNewerIndex][0] == lessThan)
rightSideIsNewer = false;
else {
check = false;
rightSideIsNewer = null;
}
if (string.IsNullOrEmpty(segments[rightSideOnlyIndex]))
rightSideOnly = null;
else if (segments[rightSideOnlyIndex][0] == plus)
rightSideOnly = true;
else if (segments[rightSideOnlyIndex][0] == minus)
rightSideOnly = false;
else {
check = false;
rightSideOnly = null;
}
result = !check ? null : new(GreaterThan: greaterThan,
LeftSideIsNewerIndex: leftSideIsNewerIndex,
LeftSideIsNewer: leftSideIsNewer,
LeftSideOnly: leftSideOnly,
LeftSideOnlyIndex: leftSideOnlyIndex,
LessThan: lessThan,
Minus: minus,
NotEqualBut: notEqualBut,
NotEqualButIndex: notEqualButIndex,
Plus: plus,
RightSideIsNewer: rightSideIsNewer,
RightSideIsNewerIndex: rightSideIsNewerIndex,
RightSideOnly: rightSideOnly,
Raw: segments,
RightSideOnlyIndex: rightSideOnlyIndex);
return result;
}
}
private record Review(Segment[]? AreEqual,
Segment[]? LeftSideIsNewer,
Segment[]? LeftSideOnly,
Segment[]? NotEqualBut,
Record[]? Records,
Segment[]? RightSideIsNewer,
Segment[]? RightSideOnly);
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(Review))]
private partial class ReviewCommonSourceGenerationContext : JsonSerializerContext {
}
internal static void Sync(ILogger<Worker> logger, List<string> args) {
Matcher matcher = new();
string fileName = $"{args[1]}.json";
string[] segments = args[5].Split('|');
string rightDirectory = Path.GetFullPath(args[0].Split('|')[0]);
Logic? logic = segments.Length != 5 ? null : Logic.Get(segments);
string includePatternsFile = Path.Combine(rightDirectory, args[2]);
string excludePatternsFile = Path.Combine(rightDirectory, args[3]);
string[] rootUniformResourceLocators = args.Count < 5 ? [] : args[4].Split('|');
matcher.AddIncludePatterns(!File.Exists(includePatternsFile) ? ["*"] : File.ReadAllLines(includePatternsFile));
matcher.AddExcludePatterns(!File.Exists(excludePatternsFile) ? ["System Volume Information"] : File.ReadAllLines(excludePatternsFile));
ReadOnlyCollection<Record> rightRecords = GetRecords(rightDirectory, matcher);
if (rightRecords.Count == 0)
logger.LogInformation("No source records");
else {
string checkFile = Path.Combine(rightDirectory, fileName);
Review review = new(AreEqual: null,
LeftSideIsNewer: null,
LeftSideOnly: null,
NotEqualBut: null,
Records: rightRecords.ToArray(),
RightSideIsNewer: null,
RightSideOnly: null);
string json = JsonSerializer.Serialize(review, ReviewCommonSourceGenerationContext.Default.Review);
WriteAllText(checkFile, json);
if (rootUniformResourceLocators.Length == 0)
logger.LogInformation("No urls");
else {
string format = NginxFileSystem.GetFormat();
TimeZoneInfo timeZoneInfo = TimeZoneInfo.Local;
Sync(logger, rightDirectory, fileName, logic, rootUniformResourceLocators, rightRecords, format, timeZoneInfo);
}
}
}
private static ReadOnlyCollection<Record> GetRecords(string rightDirectory, Matcher matcher) {
List<Record> results = [
new(RelativePath: rightDirectory,
Size: 0,
Ticks: 0)];
Record record;
FileInfo fileInfo;
string relativePath;
ReadOnlyCollection<ReadOnlyCollection<string>> collection = Helpers.HelperDirectory.GetFilesCollection(rightDirectory, "*", "*");
foreach (ReadOnlyCollection<string> c in collection) {
foreach (string f in c) {
if (!matcher.Match(rightDirectory, f).HasMatches)
continue;
fileInfo = new(f);
if (fileInfo.Length == 0)
continue;
relativePath = Path.GetRelativePath(rightDirectory, fileInfo.FullName);
record = new(RelativePath: relativePath,
Size: fileInfo.Length,
Ticks: fileInfo.LastWriteTime.ToUniversalTime().Ticks);
results.Add(record);
}
}
return results.AsReadOnly();
}
private static void WriteAllText(string path, string text) {
string check = !File.Exists(path) ? string.Empty : File.ReadAllText(path);
if (check != text)
File.WriteAllText(path, text);
}
private static void Sync(ILogger<Worker> logger, string rightDirectory, string fileName, Logic? logic, string[] rootUniformResourceLocators, ReadOnlyCollection<Record> rightRecords, string format, TimeZoneInfo timeZoneInfo) {
Review? review;
foreach (string rootUniformResourceLocator in rootUniformResourceLocators) {
if (!rootUniformResourceLocator.StartsWith("https:"))
logger.LogInformation("Not supported URL <{url}>", rootUniformResourceLocator);
else {
review = GetJsonResponse(logger, fileName, rootUniformResourceLocator, format, timeZoneInfo);
if (review?.Records is null || review.Records.Length == 0)
logger.LogInformation("No response records");
else {
ReadOnlyCollection<Record> leftRecords = review.Records.AsReadOnly();
Sync(logger, rightDirectory, fileName, logic, rightRecords, rootUniformResourceLocator, leftRecords);
}
}
}
}
private static Review? GetJsonResponse(ILogger<Worker> logger, string fileName, string rootUniformResourceLocator, string format, TimeZoneInfo timeZoneInfo) {
Review? result;
Task<string> response;
HttpClient httpClient = new();
Task<HttpResponseMessage> httpResponseMessage;
string url = new(rootUniformResourceLocator.EndsWith('/') ?
$"{rootUniformResourceLocator[..^1]}/{fileName}" :
$"{rootUniformResourceLocator}/{fileName}");
httpResponseMessage = httpClient.GetAsync(rootUniformResourceLocator);
httpResponseMessage.Wait();
if (!httpResponseMessage.Result.IsSuccessStatusCode) {
logger.LogInformation("Failed to download: <{rootUniformResourceLocator}>;", rootUniformResourceLocator);
result = null;
} else {
response = httpResponseMessage.Result.Content.ReadAsStringAsync();
response.Wait();
NginxFileSystem[]? nginxFileSystems = JsonSerializer.Deserialize(response.Result, NginxFileSystemCollectionSourceGenerationContext.Default.NginxFileSystemArray);
bool isNewest = nginxFileSystems is not null && IsNewest(fileName, format, timeZoneInfo, new(rootUniformResourceLocator), nginxFileSystems);
if (nginxFileSystems is null) {
logger.LogInformation("Failed to parse: <{rootUniformResourceLocator}>;", rootUniformResourceLocator);
result = null;
} else if (!isNewest) {
logger.LogInformation("Outdated remote file: <{rootUniformResourceLocator}>;", rootUniformResourceLocator);
result = null;
} else {
httpResponseMessage = httpClient.GetAsync(url);
httpResponseMessage.Wait();
if (!httpResponseMessage.Result.IsSuccessStatusCode) {
logger.LogInformation("Failed to download: <{url}>;", url);
result = null;
} else {
response = httpResponseMessage.Result.Content.ReadAsStringAsync();
response.Wait();
result = string.IsNullOrEmpty(response.Result) ?
null :
JsonSerializer.Deserialize(response.Result, ReviewCommonSourceGenerationContext.Default.Review);
}
}
}
return result;
}
private static bool IsNewest(string fileName, string format, TimeZoneInfo timeZoneInfo, Uri uri, NginxFileSystem[] nginxFileSystems) {
bool result;
DateTime? match = null;
NginxFileSystem nginxFileSystem;
DateTime dateTime = DateTime.MinValue;
for (int i = 0; i < nginxFileSystems.Length; i++) {
nginxFileSystem = NginxFileSystem.Get(format, timeZoneInfo, uri, nginxFileSystems[i]);
if (nginxFileSystem.LastModified is not null && nginxFileSystem.Name == fileName) {
match = nginxFileSystem.LastModified.Value;
continue;
}
if (nginxFileSystem.LastModified is null || nginxFileSystem.LastModified <= dateTime)
continue;
dateTime = nginxFileSystem.LastModified.Value;
}
result = match is not null && match.Value > dateTime;
return result;
}
private static void Sync(ILogger<Worker> logger, string rightDirectory, string fileName, Logic? l, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
string json;
string checkFile;
HttpClient httpClient = new();
checkFile = Path.Combine(rightDirectory, fileName);
if (File.Exists(checkFile))
File.Delete(checkFile);
ReadOnlyCollection<Segment> areEqual = GetAreEqual(rightDirectory, fileName, rightRecords, rootUniformResourceLocators, leftRecords);
ReadOnlyCollection<Segment> notEqualBut = GetNotEqualBut(rightDirectory, fileName, rightRecords, rootUniformResourceLocators, leftRecords);
ReadOnlyCollection<Segment> leftSideOnly = GetLeftSideOnly(rightDirectory, fileName, rightRecords, rootUniformResourceLocators, leftRecords);
ReadOnlyCollection<Segment> rightSideOnly = GetRightSideOnly(rightDirectory, fileName, rightRecords, rootUniformResourceLocators, leftRecords);
ReadOnlyCollection<Segment> leftSideIsNewer = GetLeftSideIsNewer(rightDirectory, fileName, rightRecords, rootUniformResourceLocators, leftRecords);
ReadOnlyCollection<Segment> rightSideIsNewer = GetRightSideIsNewer(rightDirectory, fileName, rightRecords, rootUniformResourceLocators, leftRecords);
Review review = new(AreEqual: areEqual.ToArray(),
LeftSideIsNewer: leftSideIsNewer.ToArray(),
LeftSideOnly: leftSideOnly.ToArray(),
NotEqualBut: notEqualBut.ToArray(),
Records: null,
RightSideIsNewer: rightSideIsNewer.ToArray(),
RightSideOnly: rightSideOnly.ToArray());
json = JsonSerializer.Serialize(review, ReviewCommonSourceGenerationContext.Default.Review);
checkFile = Path.Combine(rightDirectory, fileName);
WriteAllText(checkFile, json);
if (notEqualBut.Count > 0 && l is not null && l.NotEqualBut is not null && l.Raw[l.NotEqualButIndex][0] == l.Minus && !l.NotEqualBut.Value)
logger.LogDebug("Doing nothing with {name}", nameof(Logic.NotEqualBut));
if (leftSideOnly.Count > 0 && l is not null && l.LeftSideOnly is not null && l.Raw[l.LeftSideOnlyIndex][0] == l.Minus && !l.LeftSideOnly.Value)
throw new NotImplementedException("Not possible with https!");
if (leftSideIsNewer.Count > 0 && l is not null && l.LeftSideIsNewer is not null && l.Raw[l.LeftSideIsNewerIndex][0] == l.LessThan && !l.LeftSideIsNewer.Value)
throw new NotImplementedException("Not possible with https!");
if (rightSideIsNewer.Count > 0 && l is not null && l.RightSideIsNewer is not null && l.Raw[l.RightSideIsNewerIndex][0] == l.LessThan && !l.RightSideIsNewer.Value)
throw new NotImplementedException("Not possible with https!");
if (rightSideOnly.Count > 0 && l is not null && l.RightSideOnly is not null && l.Raw[l.RightSideOnlyIndex][0] == l.Plus && l.RightSideOnly.Value)
throw new NotImplementedException("Not possible with https!");
if (rightSideOnly.Count > 0 && l is not null && l.RightSideOnly is not null && l.Raw[l.RightSideOnlyIndex][0] == l.Minus && !l.RightSideOnly.Value)
DoWork(logger, rightDirectory, httpClient, rightSideOnly, delete: true, download: false);
if (leftSideOnly.Count > 0 && l is not null && l.LeftSideOnly is not null && l.Raw[l.LeftSideOnlyIndex][0] == l.Plus && l.LeftSideOnly.Value)
DoWork(logger, rightDirectory, httpClient, leftSideOnly, delete: false, download: true);
if (leftSideIsNewer.Count > 0 && l is not null && l.LeftSideIsNewer is not null && l.Raw[l.LeftSideIsNewerIndex][0] == l.GreaterThan && l.LeftSideIsNewer.Value)
DoWork(logger, rightDirectory, httpClient, leftSideIsNewer, delete: true, download: true);
if (notEqualBut.Count > 0 && l is not null && l.NotEqualBut is not null && l.Raw[l.NotEqualButIndex][0] == l.Plus && l.NotEqualBut.Value)
DoWork(logger, rightDirectory, httpClient, notEqualBut, delete: true, download: true);
if (rightSideIsNewer.Count > 0 && l is not null && l.RightSideIsNewer is not null && l.Raw[l.RightSideIsNewerIndex][0] == l.GreaterThan && l.RightSideIsNewer.Value)
DoWork(logger, rightDirectory, httpClient, rightSideIsNewer, delete: true, download: true);
}
private static ReadOnlyCollection<Segment> GetAreEqual(string rightDirectory, string fileName, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
List<Segment> results = [];
Record? record;
Segment segment;
double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(rightRecords);
foreach (Record r in leftRecords) {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) {
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == rightDirectory || r.RelativePath == fileName)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (record.Size != r.Size || totalSeconds is > 2 or < -2)
continue;
segment = new(Left: r,
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: rightDirectory,
RootUniformResourceLocator: rootUniformResourceLocators);
results.Add(segment);
}
return results.AsReadOnly();
}
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(ReadOnlyCollection<Record> records) {
Dictionary<string, Record> results = [];
foreach (Record record in records)
results.Add(record.RelativePath, record);
return new(results);
}
private static ReadOnlyCollection<Segment> GetNotEqualBut(string rightDirectory, string fileName, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
List<Segment> results = [];
Record? record;
Segment segment;
double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(rightRecords);
foreach (Record r in leftRecords) {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) {
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == rightDirectory || r.RelativePath == fileName)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
if (record.Size == r.Size)
continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (totalSeconds is >= 2 or <= -2)
continue;
segment = new(Left: r,
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: rightDirectory,
RootUniformResourceLocator: rootUniformResourceLocators);
results.Add(segment);
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<Segment> GetLeftSideOnly(string rightDirectory, string fileName, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
List<Segment> results = [];
Record? record;
Segment segment;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(rightRecords);
foreach (Record r in leftRecords) {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) {
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == rightDirectory || r.RelativePath == fileName)
continue;
if (keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
segment = new(Left: r,
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: rightDirectory,
RootUniformResourceLocator: rootUniformResourceLocators);
results.Add(segment);
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<Segment> GetRightSideOnly(string rightDirectory, string fileName, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
List<Segment> results = [];
Record? record;
Segment segment;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(leftRecords);
foreach (Record r in rightRecords) {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) {
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == rightDirectory || r.RelativePath == fileName)
continue;
if (keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
segment = new(Left: record,
LeftDirectory: null,
Right: r,
RightDirectory: rightDirectory,
RootUniformResourceLocator: rootUniformResourceLocators);
results.Add(segment);
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<Segment> GetLeftSideIsNewer(string rightDirectory, string fileName, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
List<Segment> results = [];
Record? record;
Segment segment;
double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(rightRecords);
foreach (Record r in leftRecords) {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) {
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == rightDirectory || r.RelativePath == fileName)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (totalSeconds is > -2)
continue;
segment = new(Left: r,
LeftDirectory: checkDirectory,
Right: record,
RightDirectory: rightDirectory,
RootUniformResourceLocator: rootUniformResourceLocators);
results.Add(segment);
}
return results.AsReadOnly();
}
private static ReadOnlyCollection<Segment> GetRightSideIsNewer(string rightDirectory, string fileName, ReadOnlyCollection<Record> rightRecords, string rootUniformResourceLocators, ReadOnlyCollection<Record> leftRecords) {
List<Segment> results = [];
Record? record;
Segment segment;
double totalSeconds;
string? checkDirectory = null;
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(leftRecords);
foreach (Record r in rightRecords) {
if (checkDirectory is null && r.Size == 0 && r.Ticks == 0) {
checkDirectory = r.RelativePath;
continue;
}
if (r.RelativePath == rightDirectory || r.RelativePath == fileName)
continue;
if (!keyValuePairs.TryGetValue(r.RelativePath, out record))
continue;
totalSeconds = new TimeSpan(record.Ticks - r.Ticks).TotalSeconds;
if (totalSeconds is > -2)
continue;
segment = new(Left: record,
LeftDirectory: null,
Right: r,
RightDirectory: rightDirectory,
RootUniformResourceLocator: rootUniformResourceLocators);
results.Add(segment);
}
return results.AsReadOnly();
}
private static void DoWork(ILogger<Worker> logger, string rightDirectory, HttpClient httpClient, ReadOnlyCollection<Segment> segments, bool delete, bool download) {
long sum;
Record[] records = (from l in segments where l.Left is not null select l.Left).ToArray();
try { sum = records.Sum(l => l.Size); } catch (Exception) { sum = 0; }
string size = GetSizeWithSuffix(sum);
if (delete) {
logger.LogInformation("Starting to delete {count} file(s) [{sum}]", segments.Count, size);
DoDeletes(logger, rightDirectory, segments);
logger.LogInformation("Deleted {count} file(s) [{sum}]", segments.Count, size);
}
if (download) {
logger.LogInformation("Starting to download {count} file(s) [{sum}]", segments.Count, size);
DoDownloads(logger, rightDirectory, segments, httpClient);
logger.LogInformation("Downloaded {count} file(s) [{sum}]", segments.Count, size);
}
}
private static string GetSizeWithSuffix(long value) {
string result;
int i = 0;
string[] SizeSuffixes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
if (value < 0) {
result = "-" + GetSizeWithSuffix(-value);
} else {
while (Math.Round(value / 1024f) >= 1) {
value /= 1024;
i++;
}
result = string.Format("{0:n1} {1}", value, SizeSuffixes[i]);
}
return result;
}
private static string GetDurationWithSuffix(long ticks) {
string result;
TimeSpan timeSpan = new(DateTime.Now.Ticks - ticks);
if (timeSpan.TotalMilliseconds < 1000)
result = $"{timeSpan.Milliseconds} ms";
else if (timeSpan.TotalMilliseconds < 60000)
result = $"{Math.Floor(timeSpan.TotalSeconds)} s";
else if (timeSpan.TotalMilliseconds < 3600000)
result = $"{Math.Floor(timeSpan.TotalMinutes)} m";
else
result = $"{Math.Floor(timeSpan.TotalHours)} h";
return result;
}
private static void DoDeletes(ILogger<Worker> logger, string rightDirectory, ReadOnlyCollection<Segment> segments) {
Record? record;
string size;
string count = segments.Count.ToString("000000");
#if ShellProgressBar
ProgressBar progressBar = new(segments.Count, $"Deleting: {count};", new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true });
#endif
for (int i = 0; i < segments.Count; i++) {
#if ShellProgressBar
progressBar.Tick();
#endif
record = segments[i].Right;
if (record is null)
continue;
size = GetSizeWithSuffix(record.Size);
try {
File.Delete(Path.Combine(rightDirectory, record.RelativePath));
logger.LogInformation("{i} of {count} - Deleted: <{RelativePath}> - {size};", i.ToString("000000"), count, record.RelativePath, size);
} catch (Exception) {
logger.LogInformation("Failed to delete: <{RelativePath}> - {size};", record.RelativePath, size);
}
}
#if ShellProgressBar
progressBar.Dispose();
#endif
}
private static void DoDownloads(ILogger<Worker> logger, string rightDirectory, ReadOnlyCollection<Segment> segments, HttpClient httpClient) {
int i = 0;
long ticks;
string size;
string duration;
DateTime dateTime;
Task<string> response;
string count = segments.Count.ToString("000000");
ReadOnlyCollection<Download> downloads = GetDownloads(rightDirectory, segments);
Task<HttpResponseMessage> httpResponseMessage;
#if ShellProgressBar
ProgressBar progressBar = new(downloads.Count, $"Downloading: {count};", new ProgressBarOptions() { ProgressCharacter = '─', ProgressBarOnBottom = true, DisableBottomPercentage = true });
#endif
foreach (Download download in downloads) {
#if ShellProgressBar
progressBar.Tick();
#endif
i += 1;
ticks = DateTime.Now.Ticks;
size = GetSizeWithSuffix(download.Size);
httpResponseMessage = httpClient.GetAsync(download.UniformResourceLocator);
httpResponseMessage.Wait(-1);
if (!httpResponseMessage.Result.IsSuccessStatusCode)
logger.LogInformation("Failed to download: <{checkURL}> - {size};", download.UniformResourceLocator, size);
else {
response = httpResponseMessage.Result.Content.ReadAsStringAsync();
response.Wait();
try {
File.WriteAllText(download.File, response.Result);
duration = GetDurationWithSuffix(ticks);
dateTime = new DateTime(download.Ticks).ToLocalTime();
File.SetLastWriteTime(download.File, dateTime);
logger.LogInformation("{i} of {count} - Downloaded: <{checkURL}> - {size} - {timeSpan};",
i.ToString("000000"),
count,
download.Display,
size,
duration);
} catch (Exception) {
logger.LogInformation("Failed to download: <{checkURL}> - {size};", download.UniformResourceLocator, size);
}
}
}
#if ShellProgressBar
progressBar.Dispose();
#endif
}
private static ReadOnlyCollection<Download> GetDownloads(string rightDirectory, ReadOnlyCollection<Segment> segments) {
List<Download> results = [];
string checkFile;
Download download;
string? checkDirectory;
List<Download> collection = [];
string? checkUniformResourceLocator;
foreach (Segment segment in segments) {
if (segment.Left is null)
continue;
checkFile = Path.Combine(rightDirectory, segment.Left.RelativePath);
checkDirectory = Path.GetDirectoryName(checkFile);
if (string.IsNullOrEmpty(checkDirectory))
continue;
if (!Directory.Exists(checkDirectory))
_ = Directory.CreateDirectory(checkDirectory);
if (File.Exists(checkFile) && new FileInfo(checkFile).Length == 0)
File.Delete(checkFile);
checkUniformResourceLocator = ConvertTo(segment.RootUniformResourceLocator, segment.Left.RelativePath);
if (string.IsNullOrEmpty(checkUniformResourceLocator))
continue;
download = new(Directory: checkDirectory,
Display: checkUniformResourceLocator[segment.RootUniformResourceLocator.Length..],
File: checkFile,
Size: segment.Left.Size,
Ticks: segment.Left.Ticks,
UniformResourceLocator: checkUniformResourceLocator);
collection.Add(download);
}
Download[] sorted = (from l in collection orderby l.Size select l).ToArray();
int stop = sorted.Length < 100 ? sorted.Length : 100;
for (int i = 0; i < stop; i++)
results.Add(sorted[i]);
for (int i = sorted.Length - 1; i > stop - 1; i--)
results.Add(sorted[i]);
if (collection.Count != results.Count)
throw new Exception();
return results.AsReadOnly();
}
private static string? ConvertTo(string rootURL, string relativePath) {
string? result = rootURL.EndsWith('/') ? rootURL[..^1] : rootURL;
string windowsRoot = "c:\\";
string windowsMock = $"{windowsRoot}{relativePath}";
string fileName = Path.GetFileName(windowsMock);
ReadOnlyCollection<string> directoryNames = Helpers.HelperDirectory.GetDirectoryNames(windowsMock);
foreach (string directoryName in directoryNames) {
if (directoryName == windowsRoot || directoryName == fileName)
continue;
result = $"{result}/{directoryName}";
}
result = result == rootURL ? null : $"{result}/{fileName}";
return result;
}
}

View File

@ -153,6 +153,8 @@ internal static class HelperDay
ADO2025.PI5.Helper20250321.MoveToLast(logger, args); ADO2025.PI5.Helper20250321.MoveToLast(logger, args);
else if (args[1] == "Day-Helper-2025-04-04") else if (args[1] == "Day-Helper-2025-04-04")
ADO2025.PI5.Helper20250404.KumaToGatus(logger, args); ADO2025.PI5.Helper20250404.KumaToGatus(logger, args);
else if (args[1] == "Day-Helper-2025-04-07")
ADO2025.PI5.Helper20250407.Sync(logger, args);
else else
throw new Exception(appSettings.Company); throw new Exception(appSettings.Company);
} }

View File

@ -41,4 +41,31 @@ internal static class HelperDirectory
return new(results); return new(results);
} }
internal static ReadOnlyCollection<ReadOnlyCollection<string>> GetFilesCollection(string directory, string directorySearchFilter, string fileSearchFilter)
{
List<ReadOnlyCollection<string>> results = [];
string[] files;
if (!fileSearchFilter.Contains('*'))
fileSearchFilter = string.Concat('*', fileSearchFilter);
if (!directorySearchFilter.Contains('*'))
directorySearchFilter = string.Concat('*', directorySearchFilter);
if (!Directory.Exists(directory))
_ = Directory.CreateDirectory(directory);
results.Add(Directory.GetFiles(directory, fileSearchFilter, SearchOption.TopDirectoryOnly).AsReadOnly());
string[] directories = Directory.GetDirectories(directory, directorySearchFilter, SearchOption.TopDirectoryOnly);
foreach (string innerDirectory in directories)
{
try
{
files = Directory.GetFiles(innerDirectory, fileSearchFilter, SearchOption.AllDirectories);
if (files.Length == 0)
continue;
results.Add(files.AsReadOnly());
}
catch (UnauthorizedAccessException)
{ continue; }
}
return results.AsReadOnly();
}
} }

View File

@ -147,7 +147,7 @@ public class Worker : BackgroundService
_Logger.LogWarning("Must pass a argument!"); _Logger.LogWarning("Must pass a argument!");
CreateWindowsShortcut(); CreateWindowsShortcut();
} }
else if (Directory.Exists(_Args[0])) else if (Directory.Exists(_Args[0].Split('|')[0]) || Directory.Exists(_Args[0]))
{ {
if (!_ConsoleKeys.Contains(consoleKey)) if (!_ConsoleKeys.Contains(consoleKey))
{ {