< Summary

Information
Class: UIBlazor.VS.VsBridge
Assembly: UIBlazor
File(s): /home/runner/work/InvAit/InvAit/UIBlazor/VS/VsBridge.cs
Tag: 71_26091983037
Line coverage
0%
Covered lines: 0
Uncovered lines: 88
Coverable lines: 88
Total lines: 201
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 38
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
InitializeAsync()0%2040%
ExecuteToolAsync()0%620%
Convert(...)0%7280%
SendRequestAsync()0%2040%
HandleVsMessageAsync(...)0%4260%
HandleVsResponseAsync(...)0%7280%
EnsureInitializedAsync()0%620%
Dispose()0%2040%

File(s)

/home/runner/work/InvAit/InvAit/UIBlazor/VS/VsBridge.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using Microsoft.JSInterop;
 3using UIBlazor.Services;
 4using UIBlazor.Services.Settings;
 5
 6namespace UIBlazor.VS;
 7
 8public class VsBridge : IVsBridge, IDisposable
 9{
 10    private readonly IJSRuntime _jsRuntime;
 11    private readonly ICommonSettingsProvider _commonOptions;
 12    private readonly IVsCodeContextService _vsCodeContextService;
 13    private DotNetObjectReference<VsBridge> _dotNetRef;
 14    private readonly ConcurrentDictionary<string, TaskCompletionSource<VsResponse>> _pendingRequests;
 15    private bool _isInitialized;
 16
 017    public VsBridge(IJSRuntime jsRuntime,
 018         ICommonSettingsProvider commonSettingsProvider,
 019         IVsCodeContextService vsCodeContextService)
 20    {
 021        _jsRuntime = jsRuntime;
 022        _commonOptions = commonSettingsProvider;
 023        _vsCodeContextService = vsCodeContextService;
 024        _pendingRequests = new ConcurrentDictionary<string, TaskCompletionSource<VsResponse>>();
 025    }
 26
 27    public async Task InitializeAsync()
 28    {
 029        if (!_isInitialized)
 30        {
 031            _dotNetRef = DotNetObjectReference.Create(this);
 032            var result = await _jsRuntime.InvokeAsync<string>("setVsBridgeHandler", _dotNetRef);
 033            _isInitialized = result == "OK";
 34
 035            if (_isInitialized)
 36            {
 37                // Notify Host that we are ready to receive messages (e.g. initial context)
 038                await _jsRuntime.InvokeVoidAsync("postVsMessage", new VsRequest { Action = BasicEnum.UIReady });
 39            }
 40        }
 041    }
 42
 43    public async Task<VsToolResult> ExecuteToolAsync(string name, IReadOnlyDictionary<string, object>? args = null, Canc
 44    {
 045        var request = new VsRequest
 046        {
 047            Action = name,
 048            Payload = args != null ? JsonUtils.Serialize(args) : null
 049        };
 50
 051        var response = await SendRequestAsync(request, cancellationToken);
 52
 053        return Convert(request, response);
 054    }
 55
 56    private VsToolResult Convert(VsRequest vsRequest, VsResponse vsResponse)
 57    {
 058        return new VsToolResult
 059        {
 060            Args = vsRequest.Payload ?? string.Empty,
 061            ErrorMessage = vsResponse.Error ?? string.Empty,
 062            Name = vsRequest.Action,
 063            Result = vsResponse.Payload ?? vsResponse.Error ?? string.Empty,
 064            Success = vsResponse.Success
 065        };
 66    }
 67
 68    private async Task<VsResponse> SendRequestAsync(VsRequest request, CancellationToken cancellationToken)
 69    {
 070        await EnsureInitializedAsync();
 71
 072        var tcs = new TaskCompletionSource<VsResponse>();
 073        _pendingRequests.TryAdd(request.CorrelationId, tcs);
 74
 75        try
 76        {
 77            // Отправляем запрос
 078            var result = await _jsRuntime.InvokeAsync<string>("postVsMessage", cancellationToken: cancellationToken, req
 79
 080            if (result != "OK")
 81            {
 082                return new VsResponse
 083                {
 084                    Success = false,
 085                    Error = $"WebView2 API is`t find."
 086                };
 87            }
 88
 089            var timeOut = TimeSpan.FromMilliseconds(_commonOptions.Current.ToolTimeoutMs);
 90#if DEBUG
 91            // Дебаг не быстрый)
 92            timeOut = TimeSpan.FromDays(1);
 93#endif
 094            using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 095            timeoutCts.CancelAfter(timeOut);
 096            timeoutCts.Token.Register(() =>
 097                tcs.TrySetException(new TimeoutException("Request timed out")));
 98
 99            // Ждем ответа
 0100            return await tcs.Task;
 101        }
 0102        catch (Exception ex)
 103        {
 0104            return new VsResponse
 0105            {
 0106                Success = false,
 0107                Error = $"Error getting response: {ex.Message}"
 0108            };
 109        }
 110        finally
 111        {
 112            // Удаляем из ожидающих запросов
 0113            _pendingRequests.TryRemove(request.CorrelationId, out _);
 114        }
 0115    }
 116
 117    [JSInvokable("HandleVsMessage")]
 118    public Task HandleVsMessageAsync(VsMessage message)
 119    {
 0120        switch (message.Action)
 121        {
 122            case "UpdateCodeContext":
 0123                if (!string.IsNullOrEmpty(message.Payload))
 124                {
 125                    try
 126                    {
 0127                        var context = JsonUtils.Deserialize<VsCodeContext>(message.Payload);
 0128                        if (context != null)
 129                        {
 0130                            _vsCodeContextService.UpdateContext(context);
 131                        }
 0132                    }
 0133                    catch (Exception ex)
 134                    {
 0135                        Console.WriteLine($"Error deserializing VsCodeContext: {ex.Message}");
 0136                    }
 137                }
 138                break;
 139            default:
 0140                Console.WriteLine($"Unknown message action: {message.Action}");
 141                break;
 142        }
 143
 0144        return Task.CompletedTask;
 145    }
 146
 147    [JSInvokable("HandleVsResponse")]
 148    public Task HandleVsResponseAsync(VsResponse response)
 149    {
 150        try
 151        {
 0152            if (string.IsNullOrEmpty(response.CorrelationId))
 153            {
 0154                Console.WriteLine("Invalid response received");
 0155                return Task.CompletedTask;
 156            }
 157
 0158            if (_pendingRequests.TryRemove(response.CorrelationId, out var tcs))
 159            {
 0160                if (response.Success)
 161                {
 0162                    tcs.SetResult(response);
 163                }
 164                else
 165                {
 0166                    tcs.SetException(new Exception(response.Error ?? "Request failed"));
 167                }
 168            }
 169            else
 170            {
 0171                Console.WriteLine($"No pending request found for correlationId: {response.CorrelationId}");
 172            }
 0173        }
 0174        catch (Exception ex)
 175        {
 0176            Console.WriteLine($"Error handling VS response: {ex.Message}");
 0177        }
 178
 0179        return Task.CompletedTask;
 0180    }
 181
 182    private async Task EnsureInitializedAsync()
 183    {
 0184        if (!_isInitialized)
 185        {
 0186            await InitializeAsync();
 187        }
 0188    }
 189
 190    public void Dispose()
 191    {
 0192        _dotNetRef?.Dispose();
 193
 194        // Отменяем все ожидающие запросы
 0195        foreach (var tcs in _pendingRequests.Values)
 196        {
 0197            tcs.TrySetCanceled();
 198        }
 0199        _pendingRequests.Clear();
 0200    }
 201}