Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Titanium.Inspector/Services/SessionArchive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
{
ct.ThrowIfCancellationRequested();
var entry = zip.CreateEntry($"session-{index:D5}.json");
await using var stream = await entry.OpenAsync(ct);
await using var stream = entry.Open();

Check warning on line 69 in src/Titanium.Inspector/Services/SessionArchive.cs

View workflow job for this annotation

GitHub Actions / build

Await OpenAsync instead.

Check warning on line 69 in src/Titanium.Inspector/Services/SessionArchive.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Await OpenAsync instead.

See more on https://sonarcloud.io/project/issues?id=justcoding121_titanium-web-proxy&issues=AaBUkJfeZAs_M-b0hiQE&open=AaBUkJfeZAs_M-b0hiQE&pullRequest=991
await JsonSerializer.SerializeAsync(stream, session, cancellationToken: ct);
index++;
}
Expand All @@ -82,7 +82,7 @@
zipPath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
FileShare.ReadWrite | FileShare.Delete,
bufferSize: 4096,
FileOptions.Asynchronous | FileOptions.SequentialScan);
using var zip = new ZipArchive(fs, ZipArchiveMode.Read, leaveOpen: true);
Expand All @@ -94,7 +94,7 @@
continue;
}

await using var stream = await entry.OpenAsync(ct);
await using var stream = entry.Open();

Check warning on line 97 in src/Titanium.Inspector/Services/SessionArchive.cs

View workflow job for this annotation

GitHub Actions / build

Await OpenAsync instead.

Check warning on line 97 in src/Titanium.Inspector/Services/SessionArchive.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Await OpenAsync instead.

See more on https://sonarcloud.io/project/issues?id=justcoding121_titanium-web-proxy&issues=AaBUkJfeZAs_M-b0hiQF&open=AaBUkJfeZAs_M-b0hiQF&pullRequest=991
var snap = await JsonSerializer.DeserializeAsync<SessionSnapshot>(stream, cancellationToken: ct);
if (snap is not null)
{
Expand Down
46 changes: 33 additions & 13 deletions src/Titanium.Inspector/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,7 +1053,7 @@
public bool SystemProxy
{
get => _systemProxy;
set // NOSONAR S4275 -- fail paths leave _systemProxy unchanged and re-raise PropertyChanged to snap the checkbox back

Check warning on line 1056 in src/Titanium.Inspector/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build

Refactor this setter so that it actually refers to the field '_systemProxy'.
{
if (_systemProxy == value)
{
Expand Down Expand Up @@ -1142,7 +1142,7 @@
public bool DecryptHttps
{
get => _decryptHttps;
set // NOSONAR S4275 -- true path updates _decryptHttps via SetDecryptHttpsCore after async trust flow

Check warning on line 1145 in src/Titanium.Inspector/ViewModels/MainWindowViewModel.cs

View workflow job for this annotation

GitHub Actions / build

Refactor this setter so that it actually refers to the field '_decryptHttps'.
{
if (_decryptHttpsBusy || _decryptHttps == value)
{
Expand Down Expand Up @@ -1913,8 +1913,16 @@
return;
}

await SessionArchive.ExportNativeArchiveAsync(_all, path);
StatusText = $"Exported {_all.Count} sessions to {path}";
try
{
// SessionArchive runs zip IO on the thread pool; resume here on the UI sync context.
await SessionArchive.ExportNativeArchiveAsync(_all, path);
StatusText = $"Exported {_all.Count} sessions to {path}";
}
catch (Exception ex)
{
StatusText = "Export archive failed: " + Truncate(ex.Message, 160);
}
}

private async Task ExportSelectedArchiveAsync()
Expand All @@ -1933,8 +1941,15 @@
return;
}

await SessionArchive.ExportNativeArchiveAsync(sessions, path);
StatusText = $"Exported {sessions.Count} sessions to {path}";
try
{
await SessionArchive.ExportNativeArchiveAsync(sessions, path);
StatusText = $"Exported {sessions.Count} sessions to {path}";
}
catch (Exception ex)
{
StatusText = "Export archive failed: " + Truncate(ex.Message, 160);
}
}

private async Task ImportArchiveAsync()
Expand All @@ -1946,22 +1961,27 @@
return;
}

StatusText = "Importing archive…";
try
{
var imported = await SessionArchive.ImportNativeArchiveAsync(path);
foreach (var snap in imported)
// Off the UI sync context for zip IO so headless WaitUntil pumps cannot deadlock the import.
var imported = await SessionArchive.ImportNativeArchiveAsync(path).ConfigureAwait(false);
await MarshalToUiAsync(() =>
{
_registry.Add(snap);
_all.Add(snap);
}
foreach (var snap in imported)
{
_registry.Add(snap);
_all.Add(snap);
}

ApplyFilter();
RefreshSessionCountText();
StatusText = $"Appended {imported.Count} sessions from {Path.GetFileName(path)}";
ApplyFilter();
RefreshSessionCountText();
StatusText = $"Appended {imported.Count} sessions from {Path.GetFileName(path)}";
});
}
catch (Exception ex)
{
StatusText = "Import archive failed: " + Truncate(ex.Message, 160);
await MarshalToUiAsync(() => StatusText = "Import archive failed: " + Truncate(ex.Message, 160));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,21 +275,10 @@ await fx.DispatchAsync(() =>
StringAssert.Contains(fx.ViewModel.StatusText, "Exported 1 sessions");
});

// macOS runners can briefly keep the zip handle; wait until a shared read succeeds.
fx.PathPicker.OpenPath = zip;
var readableDeadline = DateTime.UtcNow.AddSeconds(10);
while (DateTime.UtcNow < readableDeadline)
{
try
{
await using var probe = new FileStream(zip, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
break;
}
catch (IOException)
{
await Task.Delay(50);
}
}
// Import from a copy so any lingering exclusive handle on the export path cannot block macOS.
var importZip = Path.Combine(Path.GetTempPath(), "twp-arch-in-" + Guid.NewGuid().ToString("N") + ".zip");
File.Copy(zip, importZip, overwrite: true);
fx.PathPicker.OpenPath = importZip;

await fx.DispatchAsync(() => fx.Robot.Click("MenuImportArchive"));

Expand All @@ -300,9 +289,13 @@ await fx.WaitUntilAsync(

await fx.DispatchAsync(() =>
{
Assert.IsTrue(fx.PathPicker.OpenCalls >= 1);
StringAssert.Contains(fx.ViewModel.StatusText, "Appended");
Assert.IsTrue(fx.PathPicker.OpenCalls >= 1, "Import path picker was not invoked");
StringAssert.Contains(
fx.ViewModel.StatusText,
"Appended",
"StatusText after import: " + fx.ViewModel.StatusText);
});
try { File.Delete(zip); } catch { /* ignore */ }
try { File.Delete(importZip); } catch { /* ignore */ }
}
}
Loading