рабочий вариант, но скороть 10 МБит
build / backend (push) Has been cancelled
build / node-agent (push) Has been cancelled
build / worker (push) Has been cancelled

This commit is contained in:
2026-05-22 21:46:49 +03:00
parent 469fa0e860
commit 20d361a886
280 changed files with 954890 additions and 18524 deletions
+2 -2
View File
@@ -125,9 +125,9 @@ through Docker context `test-ubuntu` / SSH alias `docker-test`.
## Structured Messaging
- Backend HTTP errors are parsed as structured envelopes instead of legacy raw strings.
- Backend HTTP errors are parsed as structured envelopes instead of compat raw strings.
- WebSocket envelopes may now include `event` alongside the existing `type` and `payload`.
- `BackendApiClient` preserves compatibility with legacy `"error": "..."` responses, but prefers the structured form when available.
- `BackendApiClient` preserves compatibility with compat `"error": "..."` responses, but prefers the structured form when available.
- `SessionWindowViewModel` resolves websocket event messages by `message_key` first and only then falls back to `fallback_message`.
- Runtime smoke now proves both paths against the live backend: `message_key` resolution for invalid-login errors and fallback rendering for websocket state events whose keys are intentionally not present in client resources.
@@ -619,7 +619,7 @@ public sealed class SessionWindowViewModel : ObservableObject
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] SessionWindowViewModel.DisposeAsync completed: {SessionId}");
}
private async Task ConnectGatewayAsync(AttachTokenDto attachToken, CancellationToken cancellationToken, bool forceBackendGatewayFallback = false)
private async Task ConnectGatewayAsync(AttachTokenDto attachToken, CancellationToken cancellationToken, bool forceCompatGatewayFallback = false)
{
if (_isDisposed || _isUserClosing)
{
@@ -636,7 +636,7 @@ public sealed class SessionWindowViewModel : ObservableObject
});
_connection = await _sessionGatewayClient.ConnectAsync(
attachToken.Token,
forceBackendGatewayFallback ? null : _dataPlane,
forceCompatGatewayFallback ? null : _dataPlane,
HandleEnvelopeAsync,
HandleConnectionClosedAsync,
cancellationToken);
@@ -655,7 +655,7 @@ public sealed class SessionWindowViewModel : ObservableObject
{
ConnectionStatus = Strings.Get("status.session.connection.connected");
AddEventCore(Strings.Get("events.session.gateway_connected"));
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport session_window_connected session={SessionId} transport={_connection.TransportKind} force_backend_gateway_fallback={forceBackendGatewayFallback}");
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport session_window_connected session={SessionId} transport={_connection.TransportKind} force_compat_gateway_fallback={forceCompatGatewayFallback}");
if (_attachToken?.Token == attachToken.Token)
{
_attachToken = null;
@@ -878,8 +878,8 @@ public sealed class SessionWindowViewModel : ObservableObject
}
string? closedTransportKind = _connection?.TransportKind;
bool shouldTryBackendFallback = closedTransportKind == DirectWorkerWssTransportKind;
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport closed session={SessionId} transport={closedTransportKind ?? "<unknown>"} fallback_candidate={shouldTryBackendFallback}");
bool shouldTryCompatFallback = closedTransportKind == DirectWorkerWssTransportKind;
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport closed session={SessionId} transport={closedTransportKind ?? "<unknown>"} fallback_candidate={shouldTryCompatFallback}");
await RunOnUiAsync(() =>
{
@@ -953,7 +953,7 @@ public sealed class SessionWindowViewModel : ObservableObject
if (refreshedSession?.State == "active")
{
await ReconnectAfterTransportCloseAsync(forceBackendGatewayFallback: shouldTryBackendFallback || closedTransportKind == "backend_gateway", closedTransportKind);
await ReconnectAfterTransportCloseAsync(forceCompatGatewayFallback: shouldTryCompatFallback || closedTransportKind == "backend_gateway", closedTransportKind);
}
}
@@ -1016,7 +1016,7 @@ public sealed class SessionWindowViewModel : ObservableObject
return lastSeenSession;
}
private async Task ReconnectAfterTransportCloseAsync(bool forceBackendGatewayFallback, string? closedTransportKind)
private async Task ReconnectAfterTransportCloseAsync(bool forceCompatGatewayFallback, string? closedTransportKind)
{
if (_isDisposed || _isUserClosing ||
_authenticationService.CurrentUserId is null ||
@@ -1027,7 +1027,7 @@ public sealed class SessionWindowViewModel : ObservableObject
try
{
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport reconnect_start session={SessionId} from={closedTransportKind ?? "<unknown>"} force_backend_gateway_fallback={forceBackendGatewayFallback}");
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport reconnect_start session={SessionId} from={closedTransportKind ?? "<unknown>"} force_compat_gateway_fallback={forceCompatGatewayFallback}");
SessionControlResultDto result = await _sessionService.AttachSessionAsync(
_session.ID,
_authenticationService.CurrentUserId,
@@ -1063,8 +1063,8 @@ public sealed class SessionWindowViewModel : ObservableObject
return;
}
await ConnectGatewayAsync(_attachToken, _lifetimeCancellation.Token, forceBackendGatewayFallback);
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport reconnect_success session={SessionId} force_backend_gateway_fallback={forceBackendGatewayFallback}");
await ConnectGatewayAsync(_attachToken, _lifetimeCancellation.Token, forceCompatGatewayFallback);
Trace.WriteLine($"[{DateTimeOffset.Now:O}] [T{Environment.CurrentManagedThreadId}] data_plane.transport reconnect_success session={SessionId} force_compat_gateway_fallback={forceCompatGatewayFallback}");
}
catch (OperationCanceledException) when (_lifetimeCancellation.IsCancellationRequested || _isDisposed || _isUserClosing)
{
@@ -232,7 +232,7 @@ public sealed class BackendApiClient : IBackendAuthClient, IBackendOrganizationC
{
return new LocalizedMessageDto
{
Code = "common.legacy_error",
Code = "common.compat_error",
MessageKey = "errors.common.unexpected",
FallbackMessage = errorElement.GetString() ?? "Request failed."
};
@@ -17,7 +17,7 @@ public sealed class SessionGatewayClient(BackendEndpointOptions options) : ISess
private const string DirectRuntimeTransportJsonV1 = "json_v1";
private const string DirectRenderTransportMetadataKey = "render_transport";
private const string DirectRenderTransportBinaryV1 = "binary_v1";
private const string BinaryRenderLegacyMessageType = "session.frame";
private const string BinaryRenderPreviousMessageType = "session.frame";
private const string BinaryRenderFullMessageType = "render.frame.full";
private const string BinaryRenderRegionMessageType = "render.frame.region";
private const string DirectTLSTrustModeMetadataKey = "tls_trust_mode";
@@ -857,7 +857,7 @@ public sealed class SessionGatewayClient(BackendEndpointOptions options) : ISess
private static bool IsSupportedBinaryRenderMessageType(string? messageType)
{
return string.Equals(messageType, BinaryRenderLegacyMessageType, StringComparison.OrdinalIgnoreCase) ||
return string.Equals(messageType, BinaryRenderPreviousMessageType, StringComparison.OrdinalIgnoreCase) ||
string.Equals(messageType, BinaryRenderFullMessageType, StringComparison.OrdinalIgnoreCase) ||
string.Equals(messageType, BinaryRenderRegionMessageType, StringComparison.OrdinalIgnoreCase);
}