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;
        }
    }
}