Ver Fonte

Merge pull request #3315 from crobibero/dashboard-update

Add MessageId to websocket message, fix ws exception
dkanada há 5 anos atrás
pai
commit
6db1878011

+ 6 - 4
Emby.Server.Implementations/HttpServer/WebSocketConnection.cs

@@ -234,10 +234,12 @@ namespace Emby.Server.Implementations.HttpServer
         private Task SendKeepAliveResponse()
         private Task SendKeepAliveResponse()
         {
         {
             LastKeepAliveDate = DateTime.UtcNow;
             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 />
         /// <inheritdoc />

+ 82 - 0
MediaBrowser.Common/Json/Converters/JsonNonStringKeyDictionaryConverter.cs

@@ -0,0 +1,82 @@
+#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)
+            {
+                if (k != null)
+                {
+                  convertedDictionary[k.ToString()] = v;
+                }
+            }
+
+            JsonSerializer.Serialize(writer, convertedDictionary, options);
+        }
+    }
+}

+ 59 - 0
MediaBrowser.Common/Json/Converters/JsonNonStringKeyDictionaryConverterFactory.cs

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

+ 1 - 0
MediaBrowser.Common/Json/JsonDefaults.cs

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

+ 1 - 0
MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs

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