File: RemoteSerializationOptions.cs
Web Access
Project: src\src\Workspaces\Remote\Core\Microsoft.CodeAnalysis.Remote.Workspaces.csproj (Microsoft.CodeAnalysis.Remote.Workspaces)
// 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;
using System.Collections.Immutable;
using MessagePack;
using MessagePack.Formatters;
using MessagePack.Resolvers;
using Microsoft.ServiceHub.Framework;
using Nerdbank.Streams;
using Newtonsoft.Json;
using StreamJsonRpc;
 
namespace Microsoft.CodeAnalysis.Remote;
 
/// <summary>
/// Wraps MessagePack or JSON serialization options/converters.
/// </summary>
internal readonly struct RemoteSerializationOptions
{
    internal static readonly RemoteSerializationOptions Default = new([], []);
 
    // Enables remote APIs to pass Stream as parameter.
    private static readonly MultiplexingStream.Options s_multiplexingStreamOptions = new MultiplexingStream.Options
    {
        ProtocolMajorVersion = 3
    }.GetFrozenCopy();
 
    private readonly object _options;
 
    public RemoteSerializationOptions(ImmutableArray<IMessagePackFormatter> additionalFormatters, ImmutableArray<IFormatterResolver> additionalResolvers)
        => _options = StandardResolverAllowPrivate.Options
            .WithSecurity(MessagePackSecurity.UntrustedData.WithHashCollisionResistant(false))
            .WithResolver(MessagePackFormatters.CreateResolver(additionalFormatters, additionalResolvers));
 
    public RemoteSerializationOptions(ImmutableArray<JsonConverter> jsonConverters)
        => _options = jsonConverters;
 
    public RemoteSerializationOptions(ImmutableArray<System.Text.Json.Serialization.JsonConverter> jsonConverters)
        => _options = jsonConverters;
 
    public MessagePackSerializerOptions MessagePackOptions => (MessagePackSerializerOptions)_options;
    public ImmutableArray<JsonConverter> JsonConverters => (ImmutableArray<JsonConverter>)_options;
    public ImmutableArray<System.Text.Json.Serialization.JsonConverter> SystemTextJsonConverters => (ImmutableArray<System.Text.Json.Serialization.JsonConverter>)_options;
 
    public ServiceJsonRpcDescriptor.Formatters Formatter
        => _options switch
        {
            MessagePackSerializerOptions => ServiceJsonRpcDescriptor.Formatters.MessagePack,
            ImmutableArray<JsonConverter> => ServiceJsonRpcDescriptor.Formatters.UTF8,
            ImmutableArray<System.Text.Json.Serialization.JsonConverter> => ServiceJsonRpcDescriptor.Formatters.UTF8SystemTextJson,
            _ => throw new InvalidOperationException()
        };
 
    public ServiceJsonRpcDescriptor.MessageDelimiters MessageDelimiters
       => _options is MessagePackSerializerOptions
           ? ServiceJsonRpcDescriptor.MessageDelimiters.BigEndianInt32LengthHeader
           : ServiceJsonRpcDescriptor.MessageDelimiters.HttpLikeHeaders;
 
    public MultiplexingStream.Options? MultiplexingStreamOptions
        => _options is MessagePackSerializerOptions ? s_multiplexingStreamOptions : null;
 
    internal IJsonRpcMessageFormatter ConfigureFormatter(IJsonRpcMessageFormatter formatter)
    {
        if (formatter is MessagePackFormatter messagePackFormatter)
        {
            // See https://github.com/neuecc/messagepack-csharp.
            messagePackFormatter.SetMessagePackSerializerOptions(MessagePackOptions);
        }
        else if (formatter is SystemTextJsonFormatter stjFormatter)
        {
            var converters = stjFormatter.JsonSerializerOptions.Converters;
 
            foreach (var converter in SystemTextJsonConverters)
            {
                converters.Add(converter);
            }
        }
        else
        {
            var converters = ((JsonMessageFormatter)formatter).JsonSerializer.Converters;
 
            foreach (var converter in JsonConverters)
            {
                converters.Add(converter);
            }
        }
 
        return formatter;
    }
}