diff --git a/MediaBrowser.Server.Implementations/Serialization/JsonSerializer.cs b/Emby.Common.Implementations/Serialization/JsonSerializer.cs similarity index 99% rename from MediaBrowser.Server.Implementations/Serialization/JsonSerializer.cs rename to Emby.Common.Implementations/Serialization/JsonSerializer.cs index b9a03242c0..c9db336890 100644 --- a/MediaBrowser.Server.Implementations/Serialization/JsonSerializer.cs +++ b/Emby.Common.Implementations/Serialization/JsonSerializer.cs @@ -4,7 +4,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; -namespace MediaBrowser.Server.Implementations.Serialization +namespace Emby.Common.Implementations.Serialization { /// /// Provides a wrapper around third party json serialization. diff --git a/Emby.Common.Implementations/project.json b/Emby.Common.Implementations/project.json index 2b2357e383..dd304606b8 100644 --- a/Emby.Common.Implementations/project.json +++ b/Emby.Common.Implementations/project.json @@ -2,7 +2,7 @@ "version": "1.0.0-*", "dependencies": { - + }, "frameworks": { @@ -19,46 +19,49 @@ "System.Text.Encoding": "4.0.0.0", "System.Threading": "4.0.0.0", "System.Threading.Tasks": "4.0.0.0", - "System.Xml.ReaderWriter": "4.0.0" + "System.Xml.ReaderWriter": "4.0.0" }, "dependencies": { "SimpleInjector": "3.2.4", + "ServiceStack.Text": "4.5.4", "NLog": "4.4.0-betaV15", "MediaBrowser.Model": { "target": "project" }, "MediaBrowser.Common": { "target": "project" - } - } + } + } }, "netstandard1.6": { "imports": "dnxcore50", "dependencies": { "NETStandard.Library": "1.6.0", - "System.IO.FileSystem.DriveInfo": "4.0.0", - "System.Diagnostics.Process": "4.1.0", - "System.Threading.Timer": "4.0.1", - "System.Net.Requests": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XmlSerializer": "4.0.11", - "System.Net.Http": "4.1.0", - "System.Net.Primitives": "4.0.11", - "System.Net.Sockets": "4.1.0", - "System.Net.NetworkInformation": "4.1.0", - "System.Net.NameResolution": "4.0.0", - "System.Runtime.InteropServices.RuntimeInformation": "4.0.0", - "System.Reflection": "4.1.0", - "System.Reflection.Primitives": "4.0.1", - "System.Runtime.Loader": "4.0.0", - "SimpleInjector": "3.2.4", + "System.IO.FileSystem.DriveInfo": "4.0.0", + "System.Diagnostics.Process": "4.1.0", + "System.Threading.Timer": "4.0.1", + "System.Net.Requests": "4.0.11", + "System.Xml.ReaderWriter": "4.0.11", + "System.Xml.XmlSerializer": "4.0.11", + "System.Net.Http": "4.1.0", + "System.Net.Primitives": "4.0.11", + "System.Net.Sockets": "4.1.0", + "System.Net.NetworkInformation": "4.1.0", + "System.Net.NameResolution": "4.0.0", + "System.Runtime.InteropServices.RuntimeInformation": "4.0.0", + "System.Reflection": "4.1.0", + "System.Reflection.Primitives": "4.0.1", + "System.Runtime.Loader": "4.0.0", + "SimpleInjector": "3.2.4", + "ServiceStack.Text.Core": "1.0.27", "NLog": "4.4.0-betaV15", "MediaBrowser.Model": { "target": "project" }, "MediaBrowser.Common": { "target": "project" - } } + } + } } } } diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 7e885b7798..3f55bd7fb8 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -69,6 +69,7 @@ + @@ -263,6 +264,9 @@ {442b5058-dcaf-4263-bb6a-f21e31120a1b} MediaBrowser.Providers + + ..\ThirdParty\ServiceStack\ServiceStack.dll + ..\ThirdParty\emby\SocketHttpListener.Portable.dll diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs similarity index 95% rename from MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs rename to Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index b013a0952b..bbd5566616 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -21,7 +21,7 @@ using IRequest = MediaBrowser.Model.Services.IRequest; using MimeTypes = MediaBrowser.Model.Net.MimeTypes; using StreamWriter = Emby.Server.Implementations.HttpServer.StreamWriter; -namespace MediaBrowser.Server.Implementations.HttpServer +namespace Emby.Server.Implementations.HttpServer { /// /// Class HttpResultFactory @@ -161,13 +161,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer public static string GetCompressionType(IRequest request) { - var prefs = new RequestPreferences(request); + var acceptEncoding = request.Headers["Accept-Encoding"]; - if (prefs.AcceptsDeflate) - return "deflate"; + if (!string.IsNullOrWhiteSpace(acceptEncoding)) + { + if (acceptEncoding.Contains("deflate")) + return "deflate"; - if (prefs.AcceptsGzip) - return "gzip"; + if (acceptEncoding.Contains("gzip")) + return "gzip"; + } return null; } @@ -187,14 +190,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (compressionType == null) { var contentType = request.ResponseContentType; - var contentTypeAttr = ContentFormat.GetEndpointAttributes(contentType); - switch (contentTypeAttr) + switch (GetRealContentType(contentType)) { - case RequestAttributes.Xml: + case "application/xml": + case "text/xml": + case "text/xml; charset=utf-8": //"text/xml; charset=utf-8" also matches xml return SerializeToXmlString(dto); - case RequestAttributes.Json: + case "application/json": + case "text/json": return _jsonSerializer.SerializeToString(dto); } } @@ -204,7 +209,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer using (var compressionStream = GetCompressionStream(ms, compressionType)) { ContentTypes.Instance.SerializeToStream(request, dto, compressionStream); - compressionStream.Close(); + compressionStream.Dispose(); var compressedBytes = ms.ToArray(); @@ -221,6 +226,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } + public static string GetRealContentType(string contentType) + { + return contentType == null + ? null + : contentType.Split(';')[0].ToLower().Trim(); + } + public static string SerializeToXmlString(object from) { using (var ms = new MemoryStream()) @@ -520,7 +532,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer private bool ShouldCompressResponse(IRequest requestContext, string contentType) { // It will take some work to support compression with byte range requests - if (!string.IsNullOrEmpty(requestContext.GetHeader("Range"))) + if (!string.IsNullOrEmpty(requestContext.Headers.Get("Range"))) { return false; } @@ -573,7 +585,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (!compress || string.IsNullOrEmpty(requestedCompressionType)) { - var rangeHeader = requestContext.GetHeader("Range"); + var rangeHeader = requestContext.Headers.Get("Range"); var stream = await factoryFn().ConfigureAwait(false); @@ -648,7 +660,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer using (var zipStream = new DeflateStream(ms, CompressionMode.Compress)) { zipStream.Write(bytes, 0, bytes.Length); - zipStream.Close(); + zipStream.Dispose(); return ms.ToArray(); } @@ -665,7 +677,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer using (var zipStream = new GZipStream(ms, CompressionMode.Compress)) { zipStream.Write(buffer, 0, buffer.Length); - zipStream.Close(); + zipStream.Dispose(); return ms.ToArray(); } @@ -747,7 +759,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer { var isNotModified = true; - var ifModifiedSinceHeader = requestContext.GetHeader("If-Modified-Since"); + var ifModifiedSinceHeader = requestContext.Headers.Get("If-Modified-Since"); if (!string.IsNullOrEmpty(ifModifiedSinceHeader)) { @@ -759,7 +771,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer } } - var ifNoneMatchHeader = requestContext.GetHeader("If-None-Match"); + var ifNoneMatchHeader = requestContext.Headers.Get("If-None-Match"); // Validate If-None-Match if (isNotModified && (cacheKey.HasValue || !string.IsNullOrEmpty(ifNoneMatchHeader))) diff --git a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs index 813f07fffd..c32af8eb1e 100644 --- a/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs +++ b/Emby.Server.Implementations/Library/Validators/PeopleValidator.cs @@ -127,23 +127,7 @@ namespace Emby.Server.Implementations.Library.Validators { var item = _libraryManager.GetPerson(person.Key); - var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview); - var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30; - - var defaultMetadataRefreshMode = performFullRefresh - ? MetadataRefreshMode.FullRefresh - : MetadataRefreshMode.Default; - - var imageRefreshMode = performFullRefresh - ? ImageRefreshMode.FullRefresh - : ImageRefreshMode.Default; - - var options = new MetadataRefreshOptions(_fileSystem) - { - MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly, - ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly, - ForceSave = performFullRefresh - }; + var options = new MetadataRefreshOptions(_fileSystem); await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 643d0c9560..4218370ac4 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -28,6 +28,7 @@ using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using MediaBrowser.Model.Text; +using ServiceStack.Text.Jsv; using SocketHttpListener.Net; using SocketHttpListener.Primitives; @@ -87,9 +88,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public override void Configure() { - HostConfig.Instance.DefaultRedirectPath = DefaultRedirectPath; - - HostConfig.Instance.MapExceptionToStatusCode = new Dictionary + var mapExceptionToStatusCode = new Dictionary { {typeof (InvalidOperationException), 500}, {typeof (NotImplementedException), 500}, @@ -126,21 +125,24 @@ namespace MediaBrowser.Server.Implementations.HttpServer return _appHost.Resolve(); } - public override T TryResolve() + public override Type[] GetGenericArguments(Type type) { - return _appHost.TryResolve(); + return type.GetGenericArguments(); } - public override object CreateInstance(Type type) + public override bool IsAssignableFrom(Type type1, Type type2) { - return _appHost.CreateInstance(type); + return type1.IsAssignableFrom(type2); } - public override void OnConfigLoad() + public override T TryResolve() { - base.OnConfigLoad(); + return _appHost.TryResolve(); + } - Config.HandlerFactoryPath = null; + public override object CreateInstance(Type type) + { + return _appHost.CreateInstance(type); } protected override ServiceController CreateServiceController(params Assembly[] assembliesWithServices) @@ -156,12 +158,14 @@ namespace MediaBrowser.Server.Implementations.HttpServer return this; } + public static string HandlerFactoryPath; + /// /// Starts the Web Service /// private void StartListener() { - HostContext.Config.HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes.First()); + HandlerFactoryPath = GetHandlerPathIfAny(UrlPrefixes.First()); _listener = GetListener(); @@ -610,6 +614,40 @@ namespace MediaBrowser.Server.Implementations.HttpServer return routes.ToArray(); } + public override object GetTaskResult(Task task, string requestName) + { + try + { + var taskObject = task as Task; + if (taskObject != null) + { + return taskObject.Result; + } + + task.Wait(); + + var type = task.GetType(); + if (!type.IsGenericType) + { + return null; + } + + Logger.Warn("Getting task result from " + requestName + " using reflection. For better performance have your api return Task"); + return type.GetProperty("Result").GetValue(task); + } + catch (TypeAccessException) + { + return null; //return null for void Task's + } + } + + public override Func GetParseFn(Type propertyType) + { + var fn = JsvReader.GetParseFn(propertyType); + + return s => fn(s); + } + public override void SerializeToJson(object o, Stream stream) { _jsonSerializer.SerializeToStream(o, stream); diff --git a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs index 95b2ccaba3..628e5cc7e4 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpRequest.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Text; +using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer.SocketSharp; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Services; using ServiceStack; -using ServiceStack.Host; using SocketHttpListener.Net; using IHttpFile = MediaBrowser.Model.Services.IHttpFile; using IHttpRequest = MediaBrowser.Model.Services.IHttpRequest; @@ -244,14 +244,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp var specifiedContentType = GetQueryStringContentType(httpReq); if (!string.IsNullOrEmpty(specifiedContentType)) return specifiedContentType; + var serverDefaultContentType = "application/json"; + var acceptContentTypes = httpReq.AcceptTypes; var defaultContentType = httpReq.ContentType; if (HasAnyOfContentTypes(httpReq, FormUrlEncoded, MultiPartFormData)) { - defaultContentType = HostContext.Config.DefaultContentType; + defaultContentType = serverDefaultContentType; } - var customContentTypes = ContentTypes.Instance.ContentTypeFormats.Values; var preferredContentTypes = new string[] {}; var acceptsAnything = false; @@ -261,7 +262,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp var hasPreferredContentTypes = new bool[preferredContentTypes.Length]; foreach (var acceptsType in acceptContentTypes) { - var contentType = ContentFormat.GetRealContentType(acceptsType); + var contentType = HttpResultFactory.GetRealContentType(acceptsType); acceptsAnything = acceptsAnything || contentType == "*/*"; for (var i = 0; i < preferredContentTypes.Length; i++) @@ -285,17 +286,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { if (hasDefaultContentType) return defaultContentType; - if (HostContext.Config.DefaultContentType != null) - return HostContext.Config.DefaultContentType; - } - - foreach (var contentType in acceptContentTypes) - { - foreach (var customContentType in customContentTypes) - { - if (contentType.StartsWith(customContentType, StringComparison.OrdinalIgnoreCase)) - return customContentType; - } + if (serverDefaultContentType != null) + return serverDefaultContentType; } } @@ -305,8 +297,9 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp } //We could also send a '406 Not Acceptable', but this is allowed also - return HostContext.Config.DefaultContentType; + return serverDefaultContentType; } + public const string Soap11 = "text/xml; charset=utf-8"; public static bool HasAnyOfContentTypes(IRequest request, params string[] contentTypes) @@ -342,10 +335,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp if (format.Contains("json")) return "application/json"; if (format.Contains("xml")) return Xml; - string contentType; - ContentTypes.Instance.ContentTypeFormats.TryGetValue(format, out contentType); - - return contentType; + return null; } public bool HasExplicitResponseContentType { get; private set; } @@ -357,7 +347,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.SocketSharp { if (this.pathInfo == null) { - var mode = HostContext.Config.HandlerFactoryPath; + var mode = HttpListenerHost.HandlerFactoryPath; var pos = request.RawUrl.IndexOf("?"); if (pos != -1) diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index a2edc7aa84..a253753c56 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -69,6 +69,10 @@ ..\packages\Patterns.Logging.1.0.0.6\lib\portable-net45+win8\Patterns.Logging.dll True + + ..\packages\ServiceStack.Text.4.5.4\lib\net45\ServiceStack.Text.dll + True + False ..\ThirdParty\SharpCompress\SharpCompress.dll @@ -88,9 +92,6 @@ ..\ThirdParty\ServiceStack\ServiceStack.dll - - ..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll - ..\packages\UniversalDetector.1.0.1\lib\portable-net45+sl4+wp71+win8+wpa81\UniversalDetector.dll @@ -109,7 +110,6 @@ - @@ -141,7 +141,6 @@ - @@ -351,7 +350,9 @@ - + + +