Add filters, throttling, and connection test

This commit is contained in:
Codex Agent
2026-01-13 11:15:57 +01:00
parent 8944710e22
commit 0f9fc76711
4 changed files with 226 additions and 0 deletions

View File

@@ -6,6 +6,8 @@ using System.Collections.ObjectModel;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
@@ -172,6 +174,9 @@ public partial class MainWindow : Window
BaseUrlBox.Text = _settings.BaseUrl ?? DefaultBaseUrl;
MaxUploadsBox.Text = _settings.MaxConcurrentUploads.ToString();
UploadTempoBox.SelectedIndex = ResolveUploadTempoIndex(_settings.UploadDelayMs);
IncludePatternsBox.Text = _settings.IncludePatterns ?? string.Empty;
ExcludePatternsBox.Text = _settings.ExcludePatterns ?? string.Empty;
ManualUploadUrlBox.Text = _settings.UploadUrl ?? string.Empty;
ManualUsernameBox.Text = _settings.Username ?? string.Empty;
ManualPasswordBox.Text = string.Empty;
@@ -446,6 +451,17 @@ public partial class MainWindow : Window
private bool ShouldSkipUpload(string path)
{
var fileName = Path.GetFileName(path);
if (!MatchesIncludePatterns(fileName))
{
return true;
}
if (MatchesExcludePatterns(fileName))
{
return true;
}
var signature = GetUploadSignature(path);
if (signature is null)
{
@@ -534,6 +550,9 @@ public partial class MainWindow : Window
_settings.BaseUrl = normalizedBaseUrl;
_settings.MaxConcurrentUploads = maxUploads;
_settings.UploadDelayMs = ResolveUploadDelay(UploadTempoBox.SelectedIndex);
_settings.IncludePatterns = NormalizePatternInput(IncludePatternsBox.Text);
_settings.ExcludePatterns = NormalizePatternInput(ExcludePatternsBox.Text);
if (!string.IsNullOrWhiteSpace(manualUploadUrl))
{
@@ -569,6 +588,40 @@ public partial class MainWindow : Window
UpdateStatus("Einstellungen gespeichert.");
}
private async void TestConnectionButton_Click(object? sender, RoutedEventArgs e)
{
var targetUrl = ResolveTestUrl();
if (targetUrl is null)
{
UpdateStatus("Bitte eine gültige Upload-URL oder Basis-URL speichern.");
return;
}
UpdateStatus("Verbindung wird getestet...");
try
{
using var client = new HttpClient
{
Timeout = TimeSpan.FromSeconds(8),
};
client.DefaultRequestHeaders.UserAgent.ParseAdd(_userAgent);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using var request = new HttpRequestMessage(HttpMethod.Head, targetUrl);
using var response = await client.SendAsync(request);
var status = $"{(int)response.StatusCode} {response.ReasonPhrase}".Trim();
UpdateStatus($"Server erreichbar ({status}).");
}
catch (TaskCanceledException)
{
UpdateStatus("Verbindungstest: Zeitüberschreitung.");
}
catch (HttpRequestException)
{
UpdateStatus("Verbindungstest: Netzwerkfehler.");
}
}
private async void TestUploadButton_Click(object? sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(_settings.UploadUrl))
@@ -814,4 +867,159 @@ public partial class MainWindow : Window
_settings.PendingUploads ??= new List<string>();
_settings.UploadedFiles ??= new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
private string? ResolveTestUrl()
{
var manual = NormalizeUrl(ManualUploadUrlBox.Text);
if (!string.IsNullOrWhiteSpace(manual))
{
return manual;
}
if (!string.IsNullOrWhiteSpace(_settings.UploadUrl))
{
return _settings.UploadUrl;
}
var normalizedBase = NormalizeBaseUrl(BaseUrlBox.Text);
return normalizedBase;
}
private static string? NormalizeUrl(string? value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
var trimmed = value.Trim();
if (Uri.TryCreate(trimmed, UriKind.Absolute, out _))
{
return trimmed;
}
return null;
}
private static int ResolveUploadDelay(int selectedIndex)
{
return selectedIndex switch
{
0 => 0,
2 => 1500,
_ => 500,
};
}
private static int ResolveUploadTempoIndex(int delay)
{
if (delay <= 0)
{
return 0;
}
if (delay >= 1500)
{
return 2;
}
return 1;
}
private static string NormalizePatternInput(string? input)
{
if (string.IsNullOrWhiteSpace(input))
{
return string.Empty;
}
var parts = SplitPatterns(input);
return string.Join(';', parts);
}
private bool MatchesIncludePatterns(string fileName)
{
var patterns = SplitPatterns(_settings.IncludePatterns);
if (patterns.Count == 0)
{
return true;
}
return patterns.Any(pattern => IsPatternMatch(fileName, pattern));
}
private bool MatchesExcludePatterns(string fileName)
{
var patterns = SplitPatterns(_settings.ExcludePatterns);
if (patterns.Count == 0)
{
return false;
}
return patterns.Any(pattern => IsPatternMatch(fileName, pattern));
}
private static List<string> SplitPatterns(string? input)
{
if (string.IsNullOrWhiteSpace(input))
{
return new List<string>();
}
return input
.Split(new[] { ';', ',', '\n' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Where(pattern => pattern.Length > 0)
.ToList();
}
private static bool IsPatternMatch(string fileName, string pattern)
{
var span = fileName.AsSpan();
var token = pattern.AsSpan();
return IsPatternMatch(span, token);
}
private static bool IsPatternMatch(ReadOnlySpan<char> text, ReadOnlySpan<char> pattern)
{
var textIndex = 0;
var patternIndex = 0;
var starIndex = -1;
var matchIndex = 0;
while (textIndex < text.Length)
{
if (patternIndex < pattern.Length
&& (pattern[patternIndex] == '?' || char.ToLowerInvariant(pattern[patternIndex]) == char.ToLowerInvariant(text[textIndex])))
{
textIndex++;
patternIndex++;
continue;
}
if (patternIndex < pattern.Length && pattern[patternIndex] == '*')
{
starIndex = patternIndex;
matchIndex = textIndex;
patternIndex++;
continue;
}
if (starIndex != -1)
{
patternIndex = starIndex + 1;
matchIndex++;
textIndex = matchIndex;
continue;
}
return false;
}
while (patternIndex < pattern.Length && pattern[patternIndex] == '*')
{
patternIndex++;
}
return patternIndex == pattern.Length;
}
}