File: BrokeredServices\WrappedServiceBroker.cs
Web Access
Project: src\src\LanguageServer\Microsoft.CodeAnalysis.LanguageServer\Microsoft.CodeAnalysis.LanguageServer.csproj (Microsoft.CodeAnalysis.LanguageServer)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.IO.Pipelines;
using Microsoft.ServiceHub.Framework;
using Microsoft.VisualStudio.Shell.ServiceBroker;
 
namespace Microsoft.CodeAnalysis.LanguageServer.BrokeredServices;
 
/// <summary>
/// Implements a wrapper around <see cref="IServiceBroker"/> that will wait for the service broker to be available before invoking the requested method.
/// </summary>
internal sealed class WrappedServiceBroker : IServiceBroker
{
    private readonly Task<IServiceBroker> _serviceBrokerTask;
 
    public WrappedServiceBroker(Task<IBrokeredServiceContainer> containerTask)
    {
        _serviceBrokerTask = containerTask.ContinueWith(
            t =>
            {
                var serviceBroker = t.Result.GetFullAccessServiceBroker();
                serviceBroker.AvailabilityChanged += (s, e) => AvailabilityChanged?.Invoke(this, e);
                return serviceBroker;
            },
            CancellationToken.None,
            TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.RunContinuationsAsynchronously,
            TaskScheduler.Default);
    }
 
    public event EventHandler<BrokeredServicesChangedEventArgs>? AvailabilityChanged;
 
    public async ValueTask<IDuplexPipe?> GetPipeAsync(ServiceMoniker serviceMoniker, ServiceActivationOptions options = default, CancellationToken cancellationToken = default)
    {
        var serviceBroker = await _serviceBrokerTask;
        return await serviceBroker.GetPipeAsync(serviceMoniker, options, cancellationToken);
    }
 
    public async ValueTask<T?> GetProxyAsync<T>(ServiceRpcDescriptor serviceDescriptor, ServiceActivationOptions options = default, CancellationToken cancellationToken = default) where T : class
    {
        var serviceBroker = await _serviceBrokerTask;
#pragma warning disable ISB001 // Dispose of proxies - caller is responsible for disposing the proxy.
        return await serviceBroker.GetProxyAsync<T>(serviceDescriptor, options, cancellationToken);
#pragma warning restore ISB001 // Dispose of proxies
    }
}