https sync
This commit is contained in:
parent
cc9c5013a9
commit
fad2db46b5
@ -123,10 +123,9 @@ internal static partial class Helper20250404 {
|
||||
|
||||
internal static void KumaToGatus(ILogger<Worker> logger, List<string> args) {
|
||||
string url = args[4];
|
||||
string check = args[5];
|
||||
string fileName = args[3];
|
||||
string searchPattern = args[2];
|
||||
ParseMetrics(logger, fileName, url, check);
|
||||
ParseMetrics(logger, fileName, url);
|
||||
string sourceDirectory = Path.GetFullPath(args[0]);
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories);
|
||||
if (files.Length == 0)
|
||||
@ -135,7 +134,7 @@ internal static partial class Helper20250404 {
|
||||
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);
|
||||
HttpClient httpClient = new();
|
||||
Task<Stream> streamTask = httpClient.GetStreamAsync(url);
|
||||
@ -170,7 +169,7 @@ internal static partial class Helper20250404 {
|
||||
}
|
||||
|
||||
private static void KumaToGatus(string[] files) {
|
||||
Kuma kuma;
|
||||
Kuma? kuma;
|
||||
string json;
|
||||
string checkFile;
|
||||
foreach (string file in files) {
|
||||
|
693
ADO2025/PI5/Helper-2025-04-07.cs
Normal file
693
ADO2025/PI5/Helper-2025-04-07.cs
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -153,6 +153,8 @@ internal static class HelperDay
|
||||
ADO2025.PI5.Helper20250321.MoveToLast(logger, args);
|
||||
else if (args[1] == "Day-Helper-2025-04-04")
|
||||
ADO2025.PI5.Helper20250404.KumaToGatus(logger, args);
|
||||
else if (args[1] == "Day-Helper-2025-04-07")
|
||||
ADO2025.PI5.Helper20250407.Sync(logger, args);
|
||||
else
|
||||
throw new Exception(appSettings.Company);
|
||||
}
|
||||
|
@ -41,4 +41,31 @@ internal static class HelperDirectory
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
@ -147,7 +147,7 @@ public class Worker : BackgroundService
|
||||
_Logger.LogWarning("Must pass a argument!");
|
||||
CreateWindowsShortcut();
|
||||
}
|
||||
else if (Directory.Exists(_Args[0]))
|
||||
else if (Directory.Exists(_Args[0].Split('|')[0]) || Directory.Exists(_Args[0]))
|
||||
{
|
||||
if (!_ConsoleKeys.Contains(consoleKey))
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user