Add MessageId to websocket message, add JsonNonStringKeyDictionaryConverter

pull/3317/head
crobibero 4 years ago
parent 55610f8359
commit 30609c848b

@ -234,10 +234,12 @@ namespace Emby.Server.Implementations.HttpServer
private Task SendKeepAliveResponse()
{
LastKeepAliveDate = DateTime.UtcNow;
return SendAsync(new WebSocketMessage<string>
{
MessageType = "KeepAlive"
}, CancellationToken.None);
return SendAsync(
new WebSocketMessage<string>
{
MessageId = Guid.NewGuid(),
MessageType = "KeepAlive"
}, CancellationToken.None);
}
/// <inheritdoc />

@ -0,0 +1,79 @@
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MediaBrowser.Common.Json.Converters
{
/// <summary>
/// Converter for Dictionaries without string key.
/// TODO This can be removed when System.Text.Json supports Dictionaries with non-string keys.
/// </summary>
/// <typeparam name="TKey">Type of key.</typeparam>
/// <typeparam name="TValue">Type of value.</typeparam>
internal sealed class JsonNonStringKeyDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
{
/// <summary>
/// Read JSON.
/// </summary>
/// <param name="reader">The Utf8JsonReader.</param>
/// <param name="typeToConvert">The type to convert.</param>
/// <param name="options">The json serializer options.</param>
/// <returns>Typed dictionary.</returns>
/// <exception cref="NotSupportedException">Not supported.</exception>
public override IDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var convertedType = typeof(Dictionary<,>).MakeGenericType(typeof(string), typeToConvert.GenericTypeArguments[1]);
var value = JsonSerializer.Deserialize(ref reader, convertedType, options);
var instance = (Dictionary<TKey, TValue>)Activator.CreateInstance(
typeToConvert,
BindingFlags.Instance | BindingFlags.Public,
null,
null,
CultureInfo.CurrentCulture);
var enumerator = (IEnumerator)convertedType.GetMethod("GetEnumerator")!.Invoke(value, null);
var parse = typeof(TKey).GetMethod(
"Parse",
0,
BindingFlags.Public | BindingFlags.Static,
null,
CallingConventions.Any,
new[] { typeof(string) },
null);
if (parse == null)
{
throw new NotSupportedException($"{typeof(TKey)} as TKey in IDictionary<TKey, TValue> is not supported.");
}
while (enumerator.MoveNext())
{
var element = (KeyValuePair<string?, TValue>)enumerator.Current;
instance.Add((TKey)parse.Invoke(null, new[] { (object?)element.Key }), element.Value);
}
return instance;
}
/// <summary>
/// Write dictionary as Json.
/// </summary>
/// <param name="writer">The Utf8JsonWriter.</param>
/// <param name="value">The dictionary value.</param>
/// <param name="options">The Json serializer options.</param>
public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializerOptions options)
{
var convertedDictionary = new Dictionary<string?, TValue>(value.Count);
foreach (var (k, v) in value)
{
convertedDictionary[k?.ToString()] = v;
}
JsonSerializer.Serialize(writer, convertedDictionary, options);
}
}
}

@ -0,0 +1,59 @@
#nullable enable
using System;
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace MediaBrowser.Common.Json.Converters
{
/// <summary>
/// https://github.com/dotnet/runtime/issues/30524#issuecomment-524619972.
/// TODO This can be removed when System.Text.Json supports Dictionaries with non-string keys.
/// </summary>
internal sealed class JsonNonStringKeyDictionaryConverterFactory : JsonConverterFactory
{
/// <summary>
/// Only convert objects that implement IDictionary and do not have string keys.
/// </summary>
/// <param name="typeToConvert">Type convert.</param>
/// <returns>Conversion ability.</returns>
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
// Let built in converter handle string keys
if (typeToConvert.GenericTypeArguments[0] == typeof(string))
{
return false;
}
// Only support objects that implement IDictionary
return typeToConvert.GetInterface(nameof(IDictionary)) != null;
}
/// <summary>
/// Create converter for generic dictionary type.
/// </summary>
/// <param name="typeToConvert">Type to convert.</param>
/// <param name="options">Json serializer options.</param>
/// <returns>JsonConverter for given type.</returns>
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var converterType = typeof(JsonNonStringKeyDictionaryConverter<,>)
.MakeGenericType(typeToConvert.GenericTypeArguments[0], typeToConvert.GenericTypeArguments[1]);
var converter = (JsonConverter)Activator.CreateInstance(
converterType,
BindingFlags.Instance | BindingFlags.Public,
null,
null,
CultureInfo.CurrentCulture);
return converter;
}
}
}

@ -23,6 +23,7 @@ namespace MediaBrowser.Common.Json
options.Converters.Add(new JsonGuidConverter());
options.Converters.Add(new JsonStringEnumConverter());
options.Converters.Add(new JsonNonStringKeyDictionaryConverterFactory());
return options;
}

@ -156,6 +156,7 @@ namespace MediaBrowser.Controller.Net
await connection.SendAsync(
new WebSocketMessage<TReturnDataType>
{
MessageId = Guid.NewGuid(),
MessageType = Name,
Data = data
},

Loading…
Cancel
Save