From bfcd1b520fd79b893e721ba916ae5e1656407d2f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 16 Aug 2017 02:43:41 -0400 Subject: merge common implementations and server implementations --- .../HttpClientManager/HttpClientManager.cs | 975 +++++++++++++++++++++ 1 file changed, 975 insertions(+) create mode 100644 Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs (limited to 'Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs') diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs new file mode 100644 index 000000000..1017953ba --- /dev/null +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -0,0 +1,975 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Emby.Server.Implementations.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; + +namespace Emby.Server.Implementations.HttpClientManager +{ + /// + /// Class HttpClientManager + /// + public class HttpClientManager : IHttpClient + { + /// + /// When one request to a host times out, we'll ban all other requests for this period of time, to prevent scans from stalling + /// + private const int TimeoutSeconds = 30; + + /// + /// The _logger + /// + private readonly ILogger _logger; + + /// + /// The _app paths + /// + private readonly IApplicationPaths _appPaths; + + private readonly IFileSystem _fileSystem; + private readonly IMemoryStreamFactory _memoryStreamProvider; + private readonly Func _defaultUserAgentFn; + + /// + /// Initializes a new instance of the class. + /// + public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IMemoryStreamFactory memoryStreamProvider, Func defaultUserAgentFn) + { + if (appPaths == null) + { + throw new ArgumentNullException("appPaths"); + } + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + + _logger = logger; + _fileSystem = fileSystem; + _memoryStreamProvider = memoryStreamProvider; + _appPaths = appPaths; + _defaultUserAgentFn = defaultUserAgentFn; + + // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c + ServicePointManager.Expect100Continue = false; + + // Trakt requests sometimes fail without this + ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls; + } + + /// + /// Holds a dictionary of http clients by host. Use GetHttpClient(host) to retrieve or create a client for web requests. + /// DON'T dispose it after use. + /// + /// The HTTP clients. + private readonly ConcurrentDictionary _httpClients = new ConcurrentDictionary(); + + /// + /// Gets + /// + /// The host. + /// if set to true [enable HTTP compression]. + /// HttpClient. + /// host + private HttpClientInfo GetHttpClient(string host, bool enableHttpCompression) + { + if (string.IsNullOrEmpty(host)) + { + throw new ArgumentNullException("host"); + } + + HttpClientInfo client; + + var key = host + enableHttpCompression; + + if (!_httpClients.TryGetValue(key, out client)) + { + client = new HttpClientInfo(); + + _httpClients.TryAdd(key, client); + } + + return client; + } + + private WebRequest CreateWebRequest(string url) + { + try + { + return WebRequest.Create(url); + } + catch (NotSupportedException) + { + //Webrequest creation does fail on MONO randomly when using WebRequest.Create + //the issue occurs in the GetCreator method here: http://www.oschina.net/code/explore/mono-2.8.1/mcs/class/System/System.Net/WebRequest.cs + + var type = Type.GetType("System.Net.HttpRequestCreator, System, Version=4.0.0.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"); + var creator = Activator.CreateInstance(type, nonPublic: true) as IWebRequestCreate; + return creator.Create(new Uri(url)) as HttpWebRequest; + } + } + + private void AddIpv4Option(HttpWebRequest request, HttpRequestOptions options) + { + request.ServicePoint.BindIPEndPointDelegate = (servicePount, remoteEndPoint, retryCount) => + { + if (remoteEndPoint.AddressFamily == AddressFamily.InterNetwork) + { + return new IPEndPoint(IPAddress.Any, 0); + } + throw new InvalidOperationException("no IPv4 address"); + }; + } + + private WebRequest GetRequest(HttpRequestOptions options, string method) + { + var url = options.Url; + + var uriAddress = new Uri(url); + var userInfo = uriAddress.UserInfo; + if (!string.IsNullOrWhiteSpace(userInfo)) + { + _logger.Info("Found userInfo in url: {0} ... url: {1}", userInfo, url); + url = url.Replace(userInfo + "@", string.Empty); + } + + var request = CreateWebRequest(url); + var httpWebRequest = request as HttpWebRequest; + + if (httpWebRequest != null) + { + if (options.PreferIpv4) + { + AddIpv4Option(httpWebRequest, options); + } + + AddRequestHeaders(httpWebRequest, options); + + if (options.EnableHttpCompression) + { + if (options.DecompressionMethod.HasValue) + { + httpWebRequest.AutomaticDecompression = options.DecompressionMethod.Value == CompressionMethod.Gzip + ? DecompressionMethods.GZip + : DecompressionMethods.Deflate; + } + else + { + httpWebRequest.AutomaticDecompression = DecompressionMethods.Deflate; + } + } + else + { + httpWebRequest.AutomaticDecompression = DecompressionMethods.None; + } + } + + + + request.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.BypassCache); + + if (httpWebRequest != null) + { + if (options.EnableKeepAlive) + { + httpWebRequest.KeepAlive = true; + } + } + + request.Method = method; + request.Timeout = options.TimeoutMs; + + if (httpWebRequest != null) + { + if (!string.IsNullOrEmpty(options.Host)) + { + httpWebRequest.Host = options.Host; + } + + if (!string.IsNullOrEmpty(options.Referer)) + { + httpWebRequest.Referer = options.Referer; + } + } + + if (!string.IsNullOrWhiteSpace(userInfo)) + { + var parts = userInfo.Split(':'); + if (parts.Length == 2) + { + request.Credentials = GetCredential(url, parts[0], parts[1]); + // TODO: .net core ?? + request.PreAuthenticate = true; + } + } + + return request; + } + + private CredentialCache GetCredential(string url, string username, string password) + { + //ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3; + CredentialCache credentialCache = new CredentialCache(); + credentialCache.Add(new Uri(url), "Basic", new NetworkCredential(username, password)); + return credentialCache; + } + + private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options) + { + var hasUserAgent = false; + + foreach (var header in options.RequestHeaders.ToList()) + { + if (string.Equals(header.Key, "Accept", StringComparison.OrdinalIgnoreCase)) + { + request.Accept = header.Value; + } + else if (string.Equals(header.Key, "User-Agent", StringComparison.OrdinalIgnoreCase)) + { + SetUserAgent(request, header.Value); + hasUserAgent = true; + } + else + { + request.Headers.Set(header.Key, header.Value); + } + } + + if (!hasUserAgent && options.EnableDefaultUserAgent) + { + SetUserAgent(request, _defaultUserAgentFn()); + } + } + + private void SetUserAgent(HttpWebRequest request, string userAgent) + { + request.UserAgent = userAgent; + } + + /// + /// Gets the response internal. + /// + /// The options. + /// Task{HttpResponseInfo}. + public Task GetResponse(HttpRequestOptions options) + { + return SendAsync(options, "GET"); + } + + /// + /// Performs a GET request and returns the resulting stream + /// + /// The options. + /// Task{Stream}. + public async Task Get(HttpRequestOptions options) + { + var response = await GetResponse(options).ConfigureAwait(false); + + return response.Content; + } + + /// + /// Performs a GET request and returns the resulting stream + /// + /// The URL. + /// The resource pool. + /// The cancellation token. + /// Task{Stream}. + public Task Get(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + { + return Get(new HttpRequestOptions + { + Url = url, + ResourcePool = resourcePool, + CancellationToken = cancellationToken, + BufferContent = resourcePool != null + }); + } + + /// + /// Gets the specified URL. + /// + /// The URL. + /// The cancellation token. + /// Task{Stream}. + public Task Get(string url, CancellationToken cancellationToken) + { + return Get(url, null, cancellationToken); + } + + /// + /// send as an asynchronous operation. + /// + /// The options. + /// The HTTP method. + /// Task{HttpResponseInfo}. + /// + /// + public async Task SendAsync(HttpRequestOptions options, string httpMethod) + { + if (options.CacheMode == CacheMode.None) + { + return await SendAsyncInternal(options, httpMethod).ConfigureAwait(false); + } + + var url = options.Url; + var urlHash = url.ToLower().GetMD5().ToString("N"); + + var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash); + + var response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false); + if (response != null) + { + return response; + } + + response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false); + + if (response.StatusCode == HttpStatusCode.OK) + { + await CacheResponse(response, responseCachePath).ConfigureAwait(false); + } + + return response; + } + + private async Task GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url) + { + _logger.Info("Checking for cache file {0}", responseCachePath); + + try + { + if (_fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow) + { + using (var stream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true)) + { + var memoryStream = _memoryStreamProvider.CreateNew(); + + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); + memoryStream.Position = 0; + + return new HttpResponseInfo + { + ResponseUrl = url, + Content = memoryStream, + StatusCode = HttpStatusCode.OK, + ContentLength = memoryStream.Length + }; + } + } + } + catch (FileNotFoundException) + { + + } + catch (DirectoryNotFoundException) + { + + } + + return null; + } + + private async Task CacheResponse(HttpResponseInfo response, string responseCachePath) + { + _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(responseCachePath)); + + using (var responseStream = response.Content) + { + var memoryStream = _memoryStreamProvider.CreateNew(); + await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false); + memoryStream.Position = 0; + + using (var fileStream = _fileSystem.GetFileStream(responseCachePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.None, true)) + { + await memoryStream.CopyToAsync(fileStream).ConfigureAwait(false); + + memoryStream.Position = 0; + response.Content = memoryStream; + } + } + } + + private async Task SendAsyncInternal(HttpRequestOptions options, string httpMethod) + { + ValidateParams(options); + + options.CancellationToken.ThrowIfCancellationRequested(); + + var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression); + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds) + { + throw new HttpException(string.Format("Cancelling connection to {0} due to a previous timeout.", options.Url)) + { + IsTimedOut = true + }; + } + + var httpWebRequest = GetRequest(options, httpMethod); + + if (options.RequestContentBytes != null || + !string.IsNullOrEmpty(options.RequestContent) || + string.Equals(httpMethod, "post", StringComparison.OrdinalIgnoreCase)) + { + try + { + var bytes = options.RequestContentBytes ?? + Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty); + + httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded"; + + httpWebRequest.ContentLength = bytes.Length; + (await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)).Write(bytes, 0, bytes.Length); + } + catch (Exception ex) + { + throw new HttpException(ex.Message) { IsTimedOut = true }; + } + } + + if (options.ResourcePool != null) + { + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + } + + if ((DateTime.UtcNow - client.LastTimeout).TotalSeconds < TimeoutSeconds) + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } + + throw new HttpException(string.Format("Connection to {0} timed out", options.Url)) { IsTimedOut = true }; + } + + if (options.LogRequest) + { + _logger.Info("HttpClientManager {0}: {1}", httpMethod.ToUpper(), options.Url); + } + + try + { + options.CancellationToken.ThrowIfCancellationRequested(); + + if (!options.BufferContent) + { + var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false); + + var httpResponse = (HttpWebResponse)response; + + EnsureSuccessStatusCode(client, httpResponse, options); + + options.CancellationToken.ThrowIfCancellationRequested(); + + return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse), httpResponse); + } + + using (var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false)) + { + var httpResponse = (HttpWebResponse)response; + + EnsureSuccessStatusCode(client, httpResponse, options); + + options.CancellationToken.ThrowIfCancellationRequested(); + + using (var stream = httpResponse.GetResponseStream()) + { + var memoryStream = _memoryStreamProvider.CreateNew(); + + await stream.CopyToAsync(memoryStream).ConfigureAwait(false); + + memoryStream.Position = 0; + + return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length, null); + } + } + } + catch (OperationCanceledException ex) + { + throw GetCancellationException(options, client, options.CancellationToken, ex); + } + catch (Exception ex) + { + throw GetException(ex, options, client); + } + finally + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } + } + } + + private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable) + { + var responseInfo = new HttpResponseInfo(disposable) + { + Content = content, + + StatusCode = httpResponse.StatusCode, + + ContentType = httpResponse.ContentType, + + ContentLength = contentLength, + + ResponseUrl = httpResponse.ResponseUri.ToString() + }; + + if (httpResponse.Headers != null) + { + SetHeaders(httpResponse.Headers, responseInfo); + } + + return responseInfo; + } + + private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, string tempFile, long? contentLength) + { + var responseInfo = new HttpResponseInfo + { + TempFilePath = tempFile, + + StatusCode = httpResponse.StatusCode, + + ContentType = httpResponse.ContentType, + + ContentLength = contentLength + }; + + if (httpResponse.Headers != null) + { + SetHeaders(httpResponse.Headers, responseInfo); + } + + return responseInfo; + } + + private void SetHeaders(WebHeaderCollection headers, HttpResponseInfo responseInfo) + { + foreach (var key in headers.AllKeys) + { + responseInfo.Headers[key] = headers[key]; + } + } + + public Task Post(HttpRequestOptions options) + { + return SendAsync(options, "POST"); + } + + /// + /// Performs a POST request + /// + /// The options. + /// Params to add to the POST data. + /// stream on success, null on failure + public async Task Post(HttpRequestOptions options, Dictionary postData) + { + options.SetPostData(postData); + + var response = await Post(options).ConfigureAwait(false); + + return response.Content; + } + + /// + /// Performs a POST request + /// + /// The URL. + /// Params to add to the POST data. + /// The resource pool. + /// The cancellation token. + /// stream on success, null on failure + public Task Post(string url, Dictionary postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken) + { + return Post(new HttpRequestOptions + { + Url = url, + ResourcePool = resourcePool, + CancellationToken = cancellationToken, + BufferContent = resourcePool != null + + }, postData); + } + + /// + /// Downloads the contents of a given url into a temporary location + /// + /// The options. + /// Task{System.String}. + public async Task GetTempFile(HttpRequestOptions options) + { + var response = await GetTempFileResponse(options).ConfigureAwait(false); + + return response.TempFilePath; + } + + public async Task GetTempFileResponse(HttpRequestOptions options) + { + ValidateParams(options); + + _fileSystem.CreateDirectory(_appPaths.TempDirectory); + + var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp"); + + if (options.Progress == null) + { + throw new ArgumentNullException("progress"); + } + + options.CancellationToken.ThrowIfCancellationRequested(); + + var httpWebRequest = GetRequest(options, "GET"); + + if (options.ResourcePool != null) + { + await options.ResourcePool.WaitAsync(options.CancellationToken).ConfigureAwait(false); + } + + options.Progress.Report(0); + + if (options.LogRequest) + { + _logger.Info("HttpClientManager.GetTempFileResponse url: {0}", options.Url); + } + + var client = GetHttpClient(GetHostFromUrl(options.Url), options.EnableHttpCompression); + + try + { + options.CancellationToken.ThrowIfCancellationRequested(); + + using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) + { + var httpResponse = (HttpWebResponse)response; + + EnsureSuccessStatusCode(client, httpResponse, options); + + options.CancellationToken.ThrowIfCancellationRequested(); + + var contentLength = GetContentLength(httpResponse); + + if (!contentLength.HasValue) + { + // We're not able to track progress + using (var stream = httpResponse.GetResponseStream()) + { + using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) + { + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); + } + } + } + else + { + using (var stream = ProgressStream.CreateReadProgressStream(httpResponse.GetResponseStream(), options.Progress.Report, contentLength.Value)) + { + using (var fs = _fileSystem.GetFileStream(tempFile, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, true)) + { + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); + } + } + } + + options.Progress.Report(100); + + return GetResponseInfo(httpResponse, tempFile, contentLength); + } + } + catch (Exception ex) + { + DeleteTempFile(tempFile); + throw GetException(ex, options, client); + } + finally + { + if (options.ResourcePool != null) + { + options.ResourcePool.Release(); + } + } + } + + private long? GetContentLength(HttpWebResponse response) + { + var length = response.ContentLength; + + if (length == 0) + { + return null; + } + + return length; + } + + protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + private Exception GetException(Exception ex, HttpRequestOptions options, HttpClientInfo client) + { + if (ex is HttpException) + { + return ex; + } + + var webException = ex as WebException + ?? ex.InnerException as WebException; + + if (webException != null) + { + if (options.LogErrors) + { + _logger.ErrorException("Error " + webException.Status + " getting response from " + options.Url, webException); + } + + var exception = new HttpException(webException.Message, webException); + + var response = webException.Response as HttpWebResponse; + if (response != null) + { + exception.StatusCode = response.StatusCode; + + if ((int)response.StatusCode == 429) + { + client.LastTimeout = DateTime.UtcNow; + } + } + + if (!exception.StatusCode.HasValue) + { + if (webException.Status == WebExceptionStatus.NameResolutionFailure || + webException.Status == WebExceptionStatus.ConnectFailure) + { + exception.IsTimedOut = true; + } + } + + return exception; + } + + var operationCanceledException = ex as OperationCanceledException + ?? ex.InnerException as OperationCanceledException; + + if (operationCanceledException != null) + { + return GetCancellationException(options, client, options.CancellationToken, operationCanceledException); + } + + if (options.LogErrors) + { + _logger.ErrorException("Error getting response from " + options.Url, ex); + } + + return ex; + } + + private void DeleteTempFile(string file) + { + try + { + _fileSystem.DeleteFile(file); + } + catch (IOException) + { + // Might not have been created at all. No need to worry. + } + } + + private void ValidateParams(HttpRequestOptions options) + { + if (string.IsNullOrEmpty(options.Url)) + { + throw new ArgumentNullException("options"); + } + } + + /// + /// Gets the host from URL. + /// + /// The URL. + /// System.String. + private string GetHostFromUrl(string url) + { + var index = url.IndexOf("://", StringComparison.OrdinalIgnoreCase); + + if (index != -1) + { + url = url.Substring(index + 3); + var host = url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(); + + if (!string.IsNullOrWhiteSpace(host)) + { + return host; + } + } + + return url; + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + _httpClients.Clear(); + } + } + + /// + /// Throws the cancellation exception. + /// + /// The options. + /// The client. + /// The cancellation token. + /// The exception. + /// Exception. + private Exception GetCancellationException(HttpRequestOptions options, HttpClientInfo client, CancellationToken cancellationToken, OperationCanceledException exception) + { + // If the HttpClient's timeout is reached, it will cancel the Task internally + if (!cancellationToken.IsCancellationRequested) + { + var msg = string.Format("Connection to {0} timed out", options.Url); + + if (options.LogErrors) + { + _logger.Error(msg); + } + + client.LastTimeout = DateTime.UtcNow; + + // Throw an HttpException so that the caller doesn't think it was cancelled by user code + return new HttpException(msg, exception) + { + IsTimedOut = true + }; + } + + return exception; + } + + private void EnsureSuccessStatusCode(HttpClientInfo client, HttpWebResponse response, HttpRequestOptions options) + { + var statusCode = response.StatusCode; + + var isSuccessful = statusCode >= HttpStatusCode.OK && statusCode <= (HttpStatusCode)299; + + if (!isSuccessful) + { + if (options.LogErrorResponseBody) + { + try + { + using (var stream = response.GetResponseStream()) + { + if (stream != null) + { + using (var reader = new StreamReader(stream)) + { + var msg = reader.ReadToEnd(); + + _logger.Error(msg); + } + } + } + } + catch + { + + } + } + throw new HttpException(response.StatusDescription) + { + StatusCode = response.StatusCode + }; + } + } + + /// + /// Posts the specified URL. + /// + /// The URL. + /// The post data. + /// The cancellation token. + /// Task{Stream}. + public Task Post(string url, Dictionary postData, CancellationToken cancellationToken) + { + return Post(url, postData, null, cancellationToken); + } + + private Task GetResponseAsync(WebRequest request, TimeSpan timeout) + { + var taskCompletion = new TaskCompletionSource(); + + Task asyncTask = Task.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null); + + ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, timeout, true); + var callback = new TaskCallback { taskCompletion = taskCompletion }; + asyncTask.ContinueWith(callback.OnSuccess, TaskContinuationOptions.NotOnFaulted); + + // Handle errors + asyncTask.ContinueWith(callback.OnError, TaskContinuationOptions.OnlyOnFaulted); + + return taskCompletion.Task; + } + + private static void TimeoutCallback(object state, bool timedOut) + { + if (timedOut) + { + WebRequest request = (WebRequest)state; + if (state != null) + { + request.Abort(); + } + } + } + + private class TaskCallback + { + public TaskCompletionSource taskCompletion; + + public void OnSuccess(Task task) + { + taskCompletion.TrySetResult(task.Result); + } + + public void OnError(Task task) + { + if (task.Exception != null) + { + taskCompletion.TrySetException(task.Exception); + } + else + { + taskCompletion.TrySetException(new List()); + } + } + } + } +} -- cgit v1.2.3 From a7dcf7191a71bfefd4a8c69d24d2eec53973bb83 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 17 Aug 2017 16:19:02 -0400 Subject: add fixes for .net core --- .../AppBase/BaseApplicationPaths.cs | 9 ++-- Emby.Server.Implementations/ApplicationHost.cs | 56 +++++++++++----------- .../Cryptography/CertificateGenerator.cs | 42 +++++++++++++++- .../EnvironmentInfo/EnvironmentInfo.cs | 20 +++++--- .../HttpClientManager/HttpClientManager.cs | 10 ++-- Emby.Server.Implementations/Library/UserManager.cs | 6 +-- .../Logging/SimpleLogManager.cs | 4 +- Emby.Server.Implementations/Net/SocketFactory.cs | 23 ++++++--- .../ServerApplicationPaths.cs | 4 +- MediaBrowser.Model/Session/PlaybackProgressInfo.cs | 2 +- MediaBrowser.Server.Mono/MonoAppHost.cs | 2 +- MediaBrowser.Server.Mono/Program.cs | 49 +++++-------------- .../ImageEncoderHelper.cs | 1 - MediaBrowser.ServerApplication/MainStartup.cs | 16 ++----- .../MediaBrowser.ServerApplication.csproj | 4 -- MediaBrowser.ServerApplication/WindowsAppHost.cs | 4 +- 16 files changed, 132 insertions(+), 120 deletions(-) (limited to 'Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs') diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index 54d1d5302..1e63aa1a6 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -13,15 +13,12 @@ namespace Emby.Server.Implementations.AppBase /// /// Initializes a new instance of the class. /// - protected BaseApplicationPaths(string programDataPath, string appFolderPath, Action createDirectoryFn) + protected BaseApplicationPaths(string programDataPath, string appFolderPath) { ProgramDataPath = programDataPath; ProgramSystemPath = appFolderPath; - CreateDirectoryFn = createDirectoryFn; } - protected Action CreateDirectoryFn; - public string ProgramDataPath { get; private set; } /// @@ -45,7 +42,7 @@ namespace Emby.Server.Implementations.AppBase { _dataDirectory = Path.Combine(ProgramDataPath, "data"); - CreateDirectoryFn(_dataDirectory); + Directory.CreateDirectory(_dataDirectory); } return _dataDirectory; @@ -152,7 +149,7 @@ namespace Emby.Server.Implementations.AppBase { _cachePath = Path.Combine(ProgramDataPath, "cache"); - CreateDirectoryFn(_cachePath); + Directory.CreateDirectory(_cachePath); } return _cachePath; diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 3ad8fe7df..bc88d652c 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -111,6 +111,7 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; using System.Threading.Tasks; +using Emby.Server.Core.Cryptography; using Emby.Server.Implementations.Archiving; using Emby.Server.Implementations.Cryptography; using Emby.Server.Implementations.Diagnostics; @@ -368,8 +369,6 @@ namespace Emby.Server.Implementations internal IPowerManagement PowerManagement { get; private set; } internal IImageEncoder ImageEncoder { get; private set; } - private readonly Action _certificateGenerator; - private readonly Func _defaultUserNameFactory; protected IProcessFactory ProcessFactory { get; private set; } protected ITimerFactory TimerFactory { get; private set; } protected ICryptoProvider CryptographyProvider = new CryptographyProvider(); @@ -394,10 +393,7 @@ namespace Emby.Server.Implementations IEnvironmentInfo environmentInfo, IImageEncoder imageEncoder, ISystemEvents systemEvents, - IMemoryStreamFactory memoryStreamFactory, - INetworkManager networkManager, - Action certificateGenerator, - Func defaultUsernameFactory) + INetworkManager networkManager) { // hack alert, until common can target .net core BaseExtensions.CryptographyProvider = CryptographyProvider; @@ -407,7 +403,7 @@ namespace Emby.Server.Implementations NetworkManager = networkManager; EnvironmentInfo = environmentInfo; SystemEvents = systemEvents; - MemoryStreamFactory = memoryStreamFactory; + MemoryStreamFactory = new MemoryStreamProvider(); FailedAssemblies = new List(); @@ -421,9 +417,7 @@ namespace Emby.Server.Implementations Logger = LogManager.GetLogger("App"); StartupOptions = options; - _certificateGenerator = certificateGenerator; _releaseAssetFilename = releaseAssetFilename; - _defaultUserNameFactory = defaultUsernameFactory; PowerManagement = powerManagement; ImageEncoder = imageEncoder; @@ -917,7 +911,7 @@ namespace Emby.Server.Implementations AuthenticationRepository = GetAuthenticationRepository(); RegisterSingleInstance(AuthenticationRepository); - UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider, _defaultUserNameFactory()); + UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider); RegisterSingleInstance(UserManager); LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager); @@ -1257,7 +1251,7 @@ namespace Emby.Server.Implementations case MediaBrowser.Model.System.Architecture.X64: return new[] { - "https://embydata.com/downloads/ffmpeg/osx/ffmpeg-x64-20170308.7z" + "https://embydata.com/downloads/ffmpeg/osx/ffmpeg-x64-20170308.7z" }; } @@ -1271,12 +1265,12 @@ namespace Emby.Server.Implementations case MediaBrowser.Model.System.Architecture.X64: return new[] { - "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win64.7z" + "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win64.7z" }; case MediaBrowser.Model.System.Architecture.X86: return new[] { - "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win32.7z" + "https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win32.7z" }; } @@ -1290,12 +1284,12 @@ namespace Emby.Server.Implementations case MediaBrowser.Model.System.Architecture.X64: return new[] { - "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-64bit-static.7z" + "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-64bit-static.7z" }; case MediaBrowser.Model.System.Architecture.X86: return new[] { - "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-32bit-static.7z" + "https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-32bit-static.7z" }; } @@ -1442,17 +1436,17 @@ namespace Emby.Server.Implementations StartServer(); LibraryManager.AddParts(GetExports(), - GetExports(), - GetExports(), - GetExports(), - GetExports(), - GetExports()); + GetExports(), + GetExports(), + GetExports(), + GetExports(), + GetExports()); ProviderManager.AddParts(GetExports(), - GetExports(), - GetExports(), - GetExports(), - GetExports()); + GetExports(), + GetExports(), + GetExports(), + GetExports()); ImageProcessor.AddParts(GetExports()); @@ -1652,7 +1646,7 @@ namespace Emby.Server.Implementations try { - _certificateGenerator(certPath, certHost, password); + CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger); } catch (Exception ex) { @@ -2158,7 +2152,7 @@ namespace Emby.Server.Implementations list.Remove(plugin); Plugins = list.ToArray(); } - + /// /// Checks for update. /// @@ -2176,7 +2170,7 @@ namespace Emby.Server.Implementations } var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser", "Emby", ApplicationVersion, updateLevel, _releaseAssetFilename, - "MBServer", "Mbserver.zip", cacheLength, cancellationToken).ConfigureAwait(false); + "MBServer", "Mbserver.zip", cacheLength, cancellationToken).ConfigureAwait(false); HasUpdateAvailable = result.IsUpdateAvailable; @@ -2314,12 +2308,18 @@ namespace Emby.Server.Implementations NotifyPendingRestart(); } + private bool _disposed; /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + if (!_disposed) + { + _disposed = true; + + Dispose(true); + } } /// diff --git a/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs index 2600d7470..b4c84a600 100644 --- a/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs +++ b/Emby.Server.Implementations/Cryptography/CertificateGenerator.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Security.Cryptography; +using System.Xml; namespace Emby.Server.Core.Cryptography { @@ -27,7 +28,11 @@ namespace Emby.Server.Core.Cryptography DateTime notAfter = DateTime.Now.AddYears(10); RSA issuerKey = RSA.Create(); +#if NET46 issuerKey.FromXmlString(MonoTestRootAgency); +#else + RSACryptoServiceProviderExtensions.FromXmlString(issuerKey, MonoTestRootAgency); +#endif RSA subjectKey = RSA.Create(); // serial number MUST be positive @@ -44,7 +49,7 @@ namespace Emby.Server.Core.Cryptography cb.NotAfter = notAfter; cb.SubjectName = subject; cb.SubjectPublicKey = subjectKey; - + // signature cb.Hash = "SHA256"; byte[] rawcert = cb.Sign(issuerKey); @@ -66,4 +71,39 @@ namespace Emby.Server.Core.Cryptography p12.SaveToFile(fileName); } } + + public static class RSACryptoServiceProviderExtensions + { + public static void FromXmlString(RSA rsa, string xmlString) + { + RSAParameters parameters = new RSAParameters(); + + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlString); + + if (xmlDoc.DocumentElement.Name.Equals("RSAKeyValue")) + { + foreach (XmlNode node in xmlDoc.DocumentElement.ChildNodes) + { + switch (node.Name) + { + case "Modulus": parameters.Modulus = Convert.FromBase64String(node.InnerText); break; + case "Exponent": parameters.Exponent = Convert.FromBase64String(node.InnerText); break; + case "P": parameters.P = Convert.FromBase64String(node.InnerText); break; + case "Q": parameters.Q = Convert.FromBase64String(node.InnerText); break; + case "DP": parameters.DP = Convert.FromBase64String(node.InnerText); break; + case "DQ": parameters.DQ = Convert.FromBase64String(node.InnerText); break; + case "InverseQ": parameters.InverseQ = Convert.FromBase64String(node.InnerText); break; + case "D": parameters.D = Convert.FromBase64String(node.InnerText); break; + } + } + } + else + { + throw new Exception("Invalid XML RSA key."); + } + + rsa.ImportParameters(parameters); + } + } } diff --git a/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs index 0999fa141..f86279f37 100644 --- a/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs +++ b/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs @@ -6,16 +6,16 @@ namespace Emby.Server.Implementations.EnvironmentInfo { public class EnvironmentInfo : IEnvironmentInfo { - public Architecture? CustomArchitecture { get; set; } - public MediaBrowser.Model.System.OperatingSystem? CustomOperatingSystem { get; set; } + private Architecture? _customArchitecture; + private MediaBrowser.Model.System.OperatingSystem? _customOperatingSystem; public virtual MediaBrowser.Model.System.OperatingSystem OperatingSystem { get { - if (CustomOperatingSystem.HasValue) + if (_customOperatingSystem.HasValue) { - return CustomOperatingSystem.Value; + return _customOperatingSystem.Value; } switch (Environment.OSVersion.Platform) @@ -30,6 +30,10 @@ namespace Emby.Server.Implementations.EnvironmentInfo return MediaBrowser.Model.System.OperatingSystem.Windows; } + set + { + _customOperatingSystem = value; + } } public string OperatingSystemName @@ -60,13 +64,17 @@ namespace Emby.Server.Implementations.EnvironmentInfo { get { - if (CustomArchitecture.HasValue) + if (_customArchitecture.HasValue) { - return CustomArchitecture.Value; + return _customArchitecture.Value; } return Environment.Is64BitOperatingSystem ? MediaBrowser.Model.System.Architecture.X64 : MediaBrowser.Model.System.Architecture.X86; } + set + { + _customArchitecture = value; + } } public string GetEnvironmentVariable(string name) diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs index 1017953ba..f512b723d 100644 --- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs +++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs @@ -66,8 +66,10 @@ namespace Emby.Server.Implementations.HttpClientManager // http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c ServicePointManager.Expect100Continue = false; - // Trakt requests sometimes fail without this +#if NET46 +// Trakt requests sometimes fail without this ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls; +#endif } /// @@ -428,7 +430,7 @@ namespace Emby.Server.Implementations.HttpClientManager try { var bytes = options.RequestContentBytes ?? - Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty); + Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty); httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded"; @@ -727,7 +729,7 @@ namespace Emby.Server.Implementations.HttpClientManager } var webException = ex as WebException - ?? ex.InnerException as WebException; + ?? ex.InnerException as WebException; if (webException != null) { @@ -762,7 +764,7 @@ namespace Emby.Server.Implementations.HttpClientManager } var operationCanceledException = ex as OperationCanceledException - ?? ex.InnerException as OperationCanceledException; + ?? ex.InnerException as OperationCanceledException; if (operationCanceledException != null) { diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 019b8162a..211c54cee 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -71,9 +71,8 @@ namespace Emby.Server.Implementations.Library private readonly IServerApplicationHost _appHost; private readonly IFileSystem _fileSystem; private readonly ICryptoProvider _cryptographyProvider; - private readonly string _defaultUserName; - public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func imageProcessorFactory, Func dtoServiceFactory, Func connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ICryptoProvider cryptographyProvider, string defaultUserName) + public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func imageProcessorFactory, Func dtoServiceFactory, Func connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer, IFileSystem fileSystem, ICryptoProvider cryptographyProvider) { _logger = logger; UserRepository = userRepository; @@ -86,7 +85,6 @@ namespace Emby.Server.Implementations.Library _jsonSerializer = jsonSerializer; _fileSystem = fileSystem; _cryptographyProvider = cryptographyProvider; - _defaultUserName = defaultUserName; ConfigurationManager = configurationManager; Users = new List(); @@ -381,7 +379,7 @@ namespace Emby.Server.Implementations.Library // There always has to be at least one user. if (users.Count == 0) { - var name = MakeValidUsername(_defaultUserName); + var name = MakeValidUsername(Environment.UserName); var user = InstantiateNewUser(name); diff --git a/Emby.Server.Implementations/Logging/SimpleLogManager.cs b/Emby.Server.Implementations/Logging/SimpleLogManager.cs index 1a50f162a..5c83766fe 100644 --- a/Emby.Server.Implementations/Logging/SimpleLogManager.cs +++ b/Emby.Server.Implementations/Logging/SimpleLogManager.cs @@ -138,10 +138,10 @@ namespace Emby.Server.Implementations.Logging foreach (var message in _queue.GetConsumingEnumerable()) { - any = true; - var bytes = Encoding.UTF8.GetBytes(message + Environment.NewLine); _fileStream.Write(bytes, 0, bytes.Length); + + any = true; } if (any) diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs index ab3bd0b31..f78fbdfd7 100644 --- a/Emby.Server.Implementations/Net/SocketFactory.cs +++ b/Emby.Server.Implementations/Net/SocketFactory.cs @@ -69,8 +69,8 @@ namespace Emby.Server.Implementations.Net if (remotePort < 0) throw new ArgumentException("remotePort cannot be less than zero.", "remotePort"); var addressFamily = remoteAddress.AddressFamily == IpAddressFamily.InterNetwork - ? AddressFamily.InterNetwork - : AddressFamily.InterNetworkV6; + ? AddressFamily.InterNetwork + : AddressFamily.InterNetworkV6; var retVal = new Socket(addressFamily, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp); @@ -82,7 +82,7 @@ namespace Emby.Server.Implementations.Net { // This is not supported on all operating systems (qnap) } - + try { return new UdpSocket(retVal, new IpEndPointInfo(remoteAddress, remotePort)); @@ -139,11 +139,11 @@ namespace Emby.Server.Implementations.Net throw; } } - + /// - /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port. - /// - /// An implementation of the interface used by RSSDP components to perform acceptSocket operations. + /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port. + /// + /// An implementation of the interface used by RSSDP components to perform acceptSocket operations. public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort) { if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort"); @@ -186,7 +186,16 @@ namespace Emby.Server.Implementations.Net try { + // not supported on all platforms. throws on ubuntu with .net core 2.0 retVal.ExclusiveAddressUse = false; + } + catch (SocketException) + { + + } + + try + { //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive); diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index b4b2bb139..675b0d78c 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -13,8 +13,8 @@ namespace Emby.Server.Implementations /// /// Initializes a new instance of the class. /// - public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath, Action createDirectoryFn) - : base(programDataPath, appFolderPath, createDirectoryFn) + public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath) + : base(programDataPath, appFolderPath) { ApplicationResourcesPath = applicationResourcesPath; } diff --git a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs index 5f81f7269..0319f6711 100644 --- a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs +++ b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Model.Session /// The position ticks. public long? PositionTicks { get; set; } - public long? playbackStartTimeTicks { get; set; } + public long? PlaybackStartTimeTicks { get; set; } /// /// Gets or sets the volume level. diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs index 1153d0f7d..e51324ec4 100644 --- a/MediaBrowser.Server.Mono/MonoAppHost.cs +++ b/MediaBrowser.Server.Mono/MonoAppHost.cs @@ -19,7 +19,7 @@ namespace MediaBrowser.Server.Mono { public class MonoAppHost : ApplicationHost { - public MonoAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, IMemoryStreamFactory memoryStreamFactory, MediaBrowser.Common.Net.INetworkManager networkManager, Action certificateGenerator, Func defaultUsernameFactory) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, memoryStreamFactory, networkManager, certificateGenerator, defaultUsernameFactory) + public MonoAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager) : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager) { } diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index c50f97fc1..73a568ca9 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -21,7 +21,6 @@ using Emby.Server.Implementations.Networking; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; using Mono.Unix.Native; -using NLog; using ILogger = MediaBrowser.Model.Logging.ILogger; using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate; @@ -48,7 +47,7 @@ namespace MediaBrowser.Server.Mono var appPaths = CreateApplicationPaths(applicationPath, customProgramDataPath); - var logManager = new NlogManager(appPaths.LogDirectoryPath, "server"); + var logManager = new SimpleLogManager(appPaths.LogDirectoryPath, "server"); logManager.ReloadLogger(LogSeverity.Info); logManager.AddConsoleOutput(); @@ -84,9 +83,7 @@ namespace MediaBrowser.Server.Mono var appFolderPath = Path.GetDirectoryName(applicationPath); - Action createDirectoryFn = s => Directory.CreateDirectory(s); - - return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath), createDirectoryFn); + return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath)); } private static readonly TaskCompletionSource ApplicationTaskCompletionSource = new TaskCompletionSource(); @@ -113,10 +110,7 @@ namespace MediaBrowser.Server.Mono environmentInfo, imageEncoder, new SystemEvents(logManager.GetLogger("SystemEvents")), - new MemoryStreamProvider(), - new NetworkManager(logManager.GetLogger("NetworkManager")), - GenerateCertificate, - () => Environment.UserName); + new NetworkManager(logManager.GetLogger("NetworkManager"))); if (options.ContainsOption("-v")) { @@ -141,11 +135,6 @@ namespace MediaBrowser.Server.Mono Task.WaitAll(task); } - private static void GenerateCertificate(string certPath, string certHost, string certPassword) - { - CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, certPassword, _logger); - } - private static MonoEnvironmentInfo GetEnvironmentInfo() { var info = new MonoEnvironmentInfo(); @@ -156,39 +145,38 @@ namespace MediaBrowser.Server.Mono if (string.Equals(sysName, "Darwin", StringComparison.OrdinalIgnoreCase)) { - //info.OperatingSystem = Startup.Common.OperatingSystem.Osx; + info.OperatingSystem = Model.System.OperatingSystem.OSX; } else if (string.Equals(sysName, "Linux", StringComparison.OrdinalIgnoreCase)) { - //info.OperatingSystem = Startup.Common.OperatingSystem.Linux; + info.OperatingSystem = Model.System.OperatingSystem.Linux; } else if (string.Equals(sysName, "BSD", StringComparison.OrdinalIgnoreCase)) { - //info.OperatingSystem = Startup.Common.OperatingSystem.Bsd; - info.IsBsd = true; + info.OperatingSystem = Model.System.OperatingSystem.BSD; } var archX86 = new Regex("(i|I)[3-6]86"); if (archX86.IsMatch(uname.machine)) { - info.CustomArchitecture = Architecture.X86; + info.SystemArchitecture = Architecture.X86; } else if (string.Equals(uname.machine, "x86_64", StringComparison.OrdinalIgnoreCase)) { - info.CustomArchitecture = Architecture.X64; + info.SystemArchitecture = Architecture.X64; } else if (uname.machine.StartsWith("arm", StringComparison.OrdinalIgnoreCase)) { - info.CustomArchitecture = Architecture.Arm; + info.SystemArchitecture = Architecture.Arm; } else if (System.Environment.Is64BitOperatingSystem) { - info.CustomArchitecture = Architecture.X64; + info.SystemArchitecture = Architecture.X64; } else { - info.CustomArchitecture = Architecture.X86; + info.SystemArchitecture = Architecture.X86; } return info; @@ -308,24 +296,9 @@ namespace MediaBrowser.Server.Mono public class MonoEnvironmentInfo : EnvironmentInfo { - public bool IsBsd { get; set; } - public override string GetUserId() { return Syscall.getuid().ToString(CultureInfo.InvariantCulture); } - - public override Model.System.OperatingSystem OperatingSystem - { - get - { - if (IsBsd) - { - return Model.System.OperatingSystem.BSD; - } - - return base.OperatingSystem; - } - } } } diff --git a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs index 77e6c65fe..0e99bbbad 100644 --- a/MediaBrowser.ServerApplication/ImageEncoderHelper.cs +++ b/MediaBrowser.ServerApplication/ImageEncoderHelper.cs @@ -1,6 +1,5 @@ using System; using Emby.Drawing; -using Emby.Drawing.ImageMagick; using Emby.Drawing.Skia; using Emby.Server.Core; using Emby.Server.Implementations; diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index fba8f4811..6635cddb7 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -236,18 +236,16 @@ namespace MediaBrowser.ServerApplication var resourcesPath = Path.GetDirectoryName(applicationPath); - Action createDirectoryFn = s => Directory.CreateDirectory(s); - if (runAsService) { var systemPath = Path.GetDirectoryName(applicationPath); var programDataPath = Path.GetDirectoryName(systemPath); - return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath, createDirectoryFn); + return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath); } - return new ServerApplicationPaths(ApplicationPathHelper.GetProgramDataPath(applicationPath), appFolderPath, resourcesPath, createDirectoryFn); + return new ServerApplicationPaths(ApplicationPathHelper.GetProgramDataPath(applicationPath), appFolderPath, resourcesPath); } /// @@ -316,10 +314,7 @@ namespace MediaBrowser.ServerApplication environmentInfo, new NullImageEncoder(), new SystemEvents(logManager.GetLogger("SystemEvents")), - new MemoryStreamProvider(), - new Networking.NetworkManager(logManager.GetLogger("NetworkManager")), - GenerateCertificate, - () => Environment.UserDomainName); + new Networking.NetworkManager(logManager.GetLogger("NetworkManager"))); var initProgress = new Progress(); @@ -366,11 +361,6 @@ namespace MediaBrowser.ServerApplication } } - private static void GenerateCertificate(string certPath, string certHost, string certPassword) - { - CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, certPassword, _logger); - } - private static ServerNotifyIcon _serverNotifyIcon; private static TaskScheduler _mainTaskScheduler; private static void ShowTrayIcon() diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index eed5bab8d..2ee2acfc2 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -201,10 +201,6 @@ {805844ab-e92f-45e6-9d99-4f6d48d129a5} Emby.Dlna - - {6cfee013-6e7c-432b-ac37-cabf0880c69a} - Emby.Drawing.ImageMagick - {2312da6d-ff86-4597-9777-bceec32d96dd} Emby.Drawing.Skia diff --git a/MediaBrowser.ServerApplication/WindowsAppHost.cs b/MediaBrowser.ServerApplication/WindowsAppHost.cs index c872d96e2..d72bd532e 100644 --- a/MediaBrowser.ServerApplication/WindowsAppHost.cs +++ b/MediaBrowser.ServerApplication/WindowsAppHost.cs @@ -25,8 +25,8 @@ namespace MediaBrowser.ServerApplication { public class WindowsAppHost : ApplicationHost { - public WindowsAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, IMemoryStreamFactory memoryStreamFactory, MediaBrowser.Common.Net.INetworkManager networkManager, Action certificateGenerator, Func defaultUsernameFactory) - : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, memoryStreamFactory, networkManager, certificateGenerator, defaultUsernameFactory) + public WindowsAppHost(ServerApplicationPaths applicationPaths, ILogManager logManager, StartupOptions options, IFileSystem fileSystem, IPowerManagement powerManagement, string releaseAssetFilename, IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, ISystemEvents systemEvents, MediaBrowser.Common.Net.INetworkManager networkManager) + : base(applicationPaths, logManager, options, fileSystem, powerManagement, releaseAssetFilename, environmentInfo, imageEncoder, systemEvents, networkManager) { } -- cgit v1.2.3