diff options
| author | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-26 16:05:52 -0500 |
|---|---|---|
| committer | LukePulverenti <luke.pulverenti@gmail.com> | 2013-02-26 16:05:52 -0500 |
| commit | 51b3c32e2cc84778212531d72665d2c5f567f34a (patch) | |
| tree | 68fe93852dd6b3dffac09b3d7917dd6370b2784b /MediaBrowser.Networking | |
| parent | fbac08feada72c198cd5151e25008bca2b435cda (diff) | |
a little more consolidation
Diffstat (limited to 'MediaBrowser.Networking')
| -rw-r--r-- | MediaBrowser.Networking/HttpManager/HttpManager.cs | 482 | ||||
| -rw-r--r-- | MediaBrowser.Networking/HttpServer/BaseRestService.cs | 453 | ||||
| -rw-r--r-- | MediaBrowser.Networking/HttpServer/HttpServer.cs | 551 | ||||
| -rw-r--r-- | MediaBrowser.Networking/HttpServer/NativeWebSocket.cs | 165 | ||||
| -rw-r--r-- | MediaBrowser.Networking/HttpServer/ServerFactory.cs | 27 | ||||
| -rw-r--r-- | MediaBrowser.Networking/Management/NativeMethods.cs | 72 | ||||
| -rw-r--r-- | MediaBrowser.Networking/Management/NetworkManager.cs | 377 | ||||
| -rw-r--r-- | MediaBrowser.Networking/Management/NetworkShares.cs | 638 | ||||
| -rw-r--r-- | MediaBrowser.Networking/MediaBrowser.Networking.csproj | 11 | ||||
| -rw-r--r-- | MediaBrowser.Networking/Udp/UdpServer.cs | 203 | ||||
| -rw-r--r-- | MediaBrowser.Networking/WebSocket/AlchemyServer.cs | 113 | ||||
| -rw-r--r-- | MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs | 132 |
12 files changed, 0 insertions, 3224 deletions
diff --git a/MediaBrowser.Networking/HttpManager/HttpManager.cs b/MediaBrowser.Networking/HttpManager/HttpManager.cs deleted file mode 100644 index 2f44fa74b4..0000000000 --- a/MediaBrowser.Networking/HttpManager/HttpManager.cs +++ /dev/null @@ -1,482 +0,0 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Cache; -using System.Net.Http; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Networking.HttpManager -{ - /// <summary> - /// Class HttpManager - /// </summary> - public class HttpManager : IHttpClient - { - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// The _app paths - /// </summary> - private readonly IApplicationPaths _appPaths; - - /// <summary> - /// Initializes a new instance of the <see cref="HttpManager" /> class. - /// </summary> - /// <param name="appPaths">The kernel.</param> - /// <param name="logger">The logger.</param> - public HttpManager(IApplicationPaths appPaths, ILogger logger) - { - if (appPaths == null) - { - throw new ArgumentNullException("appPaths"); - } - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - _logger = logger; - _appPaths = appPaths; - } - - /// <summary> - /// 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. - /// </summary> - /// <value>The HTTP clients.</value> - private readonly ConcurrentDictionary<string, HttpClient> _httpClients = new ConcurrentDictionary<string, HttpClient>(); - - /// <summary> - /// Gets - /// </summary> - /// <param name="host">The host.</param> - /// <returns>HttpClient.</returns> - /// <exception cref="System.ArgumentNullException">host</exception> - private HttpClient GetHttpClient(string host) - { - if (string.IsNullOrEmpty(host)) - { - throw new ArgumentNullException("host"); - } - - HttpClient client; - if (!_httpClients.TryGetValue(host, out client)) - { - var handler = new WebRequestHandler - { - AutomaticDecompression = DecompressionMethods.Deflate, - CachePolicy = new RequestCachePolicy(RequestCacheLevel.Revalidate) - }; - - client = new HttpClient(handler); - client.DefaultRequestHeaders.Add("Accept", "application/json,image/*"); - client.Timeout = TimeSpan.FromSeconds(15); - _httpClients.TryAdd(host, client); - } - - return client; - } - - /// <summary> - /// Performs a GET request and returns the resulting stream - /// </summary> - /// <param name="url">The URL.</param> - /// <param name="resourcePool">The resource pool.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{Stream}.</returns> - /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception> - public async Task<Stream> Get(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken) - { - ValidateParams(url, resourcePool, cancellationToken); - - cancellationToken.ThrowIfCancellationRequested(); - - await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - _logger.Info("HttpManager.Get url: {0}", url); - - try - { - cancellationToken.ThrowIfCancellationRequested(); - - var msg = await GetHttpClient(GetHostFromUrl(url)).GetAsync(url, cancellationToken).ConfigureAwait(false); - - EnsureSuccessStatusCode(msg); - - return await msg.Content.ReadAsStreamAsync().ConfigureAwait(false); - } - catch (OperationCanceledException ex) - { - throw GetCancellationException(url, cancellationToken, ex); - } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + url, ex); - - throw new HttpException(ex.Message, ex); - } - finally - { - resourcePool.Release(); - } - } - - /// <summary> - /// Performs a POST request - /// </summary> - /// <param name="url">The URL.</param> - /// <param name="postData">Params to add to the POST data.</param> - /// <param name="resourcePool">The resource pool.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>stream on success, null on failure</returns> - /// <exception cref="System.ArgumentNullException">postData</exception> - /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception> - public async Task<Stream> Post(string url, Dictionary<string, string> postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken) - { - ValidateParams(url, resourcePool, cancellationToken); - - if (postData == null) - { - throw new ArgumentNullException("postData"); - } - - cancellationToken.ThrowIfCancellationRequested(); - - var strings = postData.Keys.Select(key => string.Format("{0}={1}", key, postData[key])); - var postContent = string.Join("&", strings.ToArray()); - var content = new StringContent(postContent, Encoding.UTF8, "application/x-www-form-urlencoded"); - - await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - _logger.Info("HttpManager.Post url: {0}", url); - - try - { - cancellationToken.ThrowIfCancellationRequested(); - - var msg = await GetHttpClient(GetHostFromUrl(url)).PostAsync(url, content, cancellationToken).ConfigureAwait(false); - - EnsureSuccessStatusCode(msg); - - return await msg.Content.ReadAsStreamAsync().ConfigureAwait(false); - } - catch (OperationCanceledException ex) - { - throw GetCancellationException(url, cancellationToken, ex); - } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + url, ex); - - throw new HttpException(ex.Message, ex); - } - finally - { - resourcePool.Release(); - } - } - - /// <summary> - /// Downloads the contents of a given url into a temporary location - /// </summary> - /// <param name="url">The URL.</param> - /// <param name="resourcePool">The resource pool.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="progress">The progress.</param> - /// <param name="userAgent">The user agent.</param> - /// <returns>Task{System.String}.</returns> - /// <exception cref="System.ArgumentNullException">progress</exception> - /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception> - public async Task<string> GetTempFile(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken, IProgress<double> progress, string userAgent = null) - { - ValidateParams(url, resourcePool, cancellationToken); - - if (progress == null) - { - throw new ArgumentNullException("progress"); - } - - cancellationToken.ThrowIfCancellationRequested(); - - var tempFile = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid() + ".tmp"); - - var message = new HttpRequestMessage(HttpMethod.Get, url); - - if (!string.IsNullOrEmpty(userAgent)) - { - message.Headers.Add("User-Agent", userAgent); - } - - await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - _logger.Info("HttpManager.GetTempFile url: {0}, temp file: {1}", url, tempFile); - - try - { - cancellationToken.ThrowIfCancellationRequested(); - - using (var response = await GetHttpClient(GetHostFromUrl(url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false)) - { - EnsureSuccessStatusCode(response); - - cancellationToken.ThrowIfCancellationRequested(); - - IEnumerable<string> lengthValues; - - if (!response.Headers.TryGetValues("content-length", out lengthValues) && - !response.Content.Headers.TryGetValues("content-length", out lengthValues)) - { - // We're not able to track progress - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - { - using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) - { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - } - } - else - { - var length = long.Parse(string.Join(string.Empty, lengthValues.ToArray())); - - using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), progress.Report, length)) - { - using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous)) - { - await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - } - } - - progress.Report(100); - - cancellationToken.ThrowIfCancellationRequested(); - } - - return tempFile; - } - catch (OperationCanceledException ex) - { - // Cleanup - if (File.Exists(tempFile)) - { - File.Delete(tempFile); - } - - throw GetCancellationException(url, cancellationToken, ex); - } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + url, ex); - - // Cleanup - if (File.Exists(tempFile)) - { - File.Delete(tempFile); - } - - throw new HttpException(ex.Message, ex); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting response from " + url, ex); - - // Cleanup - if (File.Exists(tempFile)) - { - File.Delete(tempFile); - } - - throw; - } - finally - { - resourcePool.Release(); - } - } - - /// <summary> - /// Downloads the contents of a given url into a MemoryStream - /// </summary> - /// <param name="url">The URL.</param> - /// <param name="resourcePool">The resource pool.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{MemoryStream}.</returns> - /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception> - public async Task<MemoryStream> GetMemoryStream(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken) - { - ValidateParams(url, resourcePool, cancellationToken); - - cancellationToken.ThrowIfCancellationRequested(); - - var message = new HttpRequestMessage(HttpMethod.Get, url); - - await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - - var ms = new MemoryStream(); - - _logger.Info("HttpManager.GetMemoryStream url: {0}", url); - - try - { - cancellationToken.ThrowIfCancellationRequested(); - - using (var response = await GetHttpClient(GetHostFromUrl(url)).SendAsync(message, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false)) - { - EnsureSuccessStatusCode(response); - - cancellationToken.ThrowIfCancellationRequested(); - - using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) - { - await stream.CopyToAsync(ms, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); - } - - cancellationToken.ThrowIfCancellationRequested(); - } - - ms.Position = 0; - - return ms; - } - catch (OperationCanceledException ex) - { - ms.Dispose(); - - throw GetCancellationException(url, cancellationToken, ex); - } - catch (HttpRequestException ex) - { - _logger.ErrorException("Error getting response from " + url, ex); - - ms.Dispose(); - - throw new HttpException(ex.Message, ex); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting response from " + url, ex); - - ms.Dispose(); - - throw; - } - finally - { - resourcePool.Release(); - } - } - - /// <summary> - /// Validates the params. - /// </summary> - /// <param name="url">The URL.</param> - /// <param name="resourcePool">The resource pool.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <exception cref="System.ArgumentNullException">url</exception> - private void ValidateParams(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken) - { - if (string.IsNullOrEmpty(url)) - { - throw new ArgumentNullException("url"); - } - - if (resourcePool == null) - { - throw new ArgumentNullException("resourcePool"); - } - - if (cancellationToken == null) - { - throw new ArgumentNullException("cancellationToken"); - } - } - - /// <summary> - /// Gets the host from URL. - /// </summary> - /// <param name="url">The URL.</param> - /// <returns>System.String.</returns> - private string GetHostFromUrl(string url) - { - var start = url.IndexOf("://", StringComparison.OrdinalIgnoreCase) + 3; - var len = url.IndexOf('/', start) - start; - return url.Substring(start, len); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - foreach (var client in _httpClients.Values.ToList()) - { - client.Dispose(); - } - - _httpClients.Clear(); - } - } - - /// <summary> - /// Throws the cancellation exception. - /// </summary> - /// <param name="url">The URL.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="exception">The exception.</param> - /// <returns>Exception.</returns> - private Exception GetCancellationException(string url, 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", url); - - _logger.Error(msg); - - // 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; - } - - /// <summary> - /// Ensures the success status code. - /// </summary> - /// <param name="response">The response.</param> - /// <exception cref="MediaBrowser.Model.Net.HttpException"></exception> - private void EnsureSuccessStatusCode(HttpResponseMessage response) - { - if (!response.IsSuccessStatusCode) - { - throw new HttpException(response.ReasonPhrase) { StatusCode = response.StatusCode }; - } - } - } -} diff --git a/MediaBrowser.Networking/HttpServer/BaseRestService.cs b/MediaBrowser.Networking/HttpServer/BaseRestService.cs deleted file mode 100644 index d499f07814..0000000000 --- a/MediaBrowser.Networking/HttpServer/BaseRestService.cs +++ /dev/null @@ -1,453 +0,0 @@ -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using ServiceStack.Common; -using ServiceStack.Common.Web; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface; -using ServiceStack.WebHost.Endpoints; -using System; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using MimeTypes = MediaBrowser.Common.Net.MimeTypes; -using StreamWriter = MediaBrowser.Common.Net.StreamWriter; - -namespace MediaBrowser.Networking.HttpServer -{ - /// <summary> - /// Class BaseRestService - /// </summary> - public class BaseRestService : Service, IRestfulService - { - /// <summary> - /// Gets or sets the kernel. - /// </summary> - /// <value>The kernel.</value> - public IKernel Kernel { get; set; } - - /// <summary> - /// Gets or sets the logger. - /// </summary> - /// <value>The logger.</value> - public ILogger Logger { get; set; } - - /// <summary> - /// Gets a value indicating whether this instance is range request. - /// </summary> - /// <value><c>true</c> if this instance is range request; otherwise, <c>false</c>.</value> - protected bool IsRangeRequest - { - get - { - return Request.Headers.AllKeys.Contains("Range"); - } - } - - /// <summary> - /// To the optimized result. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="result">The result.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">result</exception> - protected object ToOptimizedResult<T>(T result) - where T : class - { - if (result == null) - { - throw new ArgumentNullException("result"); - } - - Response.AddHeader("Vary", "Accept-Encoding"); - - return RequestContext.ToOptimizedResult(result); - } - - /// <summary> - /// To the optimized result using cache. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey</exception> - protected object ToOptimizedResultUsingCache<T>(Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn) - where T : class - { - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (factoryFn == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - var result = PreProcessCachedResult(cacheKey, key, lastDateModified, cacheDuration, string.Empty); - - if (result != null) - { - return result; - } - - return ToOptimizedResult(factoryFn()); - } - - /// <summary> - /// To the cached result. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey</exception> - protected object ToCachedResult<T>(Guid cacheKey, DateTime lastDateModified, TimeSpan? cacheDuration, Func<T> factoryFn, string contentType) - where T : class - { - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (factoryFn == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - var result = PreProcessCachedResult(cacheKey, key, lastDateModified, cacheDuration, contentType); - - if (result != null) - { - return result; - } - - return factoryFn(); - } - - /// <summary> - /// To the static file result. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">path</exception> - protected object ToStaticFileResult(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - var dateModified = File.GetLastWriteTimeUtc(path); - - var cacheKey = path + dateModified.Ticks; - - return ToStaticResult(cacheKey.GetMD5(), dateModified, null, MimeTypes.GetMimeType(path), () => Task.FromResult(GetFileStream(path))); - } - - /// <summary> - /// Gets the file stream. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>Stream.</returns> - private Stream GetFileStream(string path) - { - return new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous); - } - - /// <summary> - /// To the static result. - /// </summary> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="contentType">Type of the content.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <returns>System.Object.</returns> - /// <exception cref="System.ArgumentNullException">cacheKey</exception> - protected object ToStaticResult(Guid cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType, Func<Task<Stream>> factoryFn) - { - if (cacheKey == Guid.Empty) - { - throw new ArgumentNullException("cacheKey"); - } - if (factoryFn == null) - { - throw new ArgumentNullException("factoryFn"); - } - - var key = cacheKey.ToString("N"); - - var result = PreProcessCachedResult(cacheKey, key, lastDateModified, cacheDuration, contentType); - - if (result != null) - { - return result; - } - - var compress = ShouldCompressResponse(contentType); - - if (compress) - { - Response.AddHeader("Vary", "Accept-Encoding"); - } - - return ToStaticResult(contentType, factoryFn, compress).Result; - } - - /// <summary> - /// Shoulds the compress response. - /// </summary> - /// <param name="contentType">Type of the content.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> - private bool ShouldCompressResponse(string contentType) - { - // It will take some work to support compression with byte range requests - if (IsRangeRequest) - { - return false; - } - - // Don't compress media - if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - // Don't compress images - if (contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - if (contentType.StartsWith("font/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - if (contentType.StartsWith("application/", StringComparison.OrdinalIgnoreCase)) - { - return false; - } - - return true; - } - - /// <summary> - /// To the static result. - /// </summary> - /// <param name="contentType">Type of the content.</param> - /// <param name="factoryFn">The factory fn.</param> - /// <param name="compress">if set to <c>true</c> [compress].</param> - /// <returns>System.Object.</returns> - private async Task<object> ToStaticResult(string contentType, Func<Task<Stream>> factoryFn, bool compress) - { - if (!compress || string.IsNullOrEmpty(RequestContext.CompressionType)) - { - Response.ContentType = contentType; - - var stream = await factoryFn().ConfigureAwait(false); - - return new StreamWriter(stream); - } - - string content; - - using (var stream = await factoryFn().ConfigureAwait(false)) - { - using (var reader = new StreamReader(stream)) - { - content = await reader.ReadToEndAsync().ConfigureAwait(false); - } - } - - var contents = content.Compress(RequestContext.CompressionType); - - return new CompressedResult(contents, RequestContext.CompressionType, contentType); - } - - /// <summary> - /// Pres the process optimized result. - /// </summary> - /// <param name="cacheKey">The cache key.</param> - /// <param name="cacheKeyString">The cache key string.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="contentType">Type of the content.</param> - /// <returns>System.Object.</returns> - private object PreProcessCachedResult(Guid cacheKey, string cacheKeyString, DateTime? lastDateModified, TimeSpan? cacheDuration, string contentType) - { - Response.AddHeader("ETag", cacheKeyString); - - if (IsNotModified(cacheKey, lastDateModified, cacheDuration)) - { - AddAgeHeader(lastDateModified); - AddExpiresHeader(cacheKeyString, cacheDuration); - //ctx.Response.SendChunked = false; - - if (!string.IsNullOrEmpty(contentType)) - { - Response.ContentType = contentType; - } - - return new HttpResult(new byte[] { }, HttpStatusCode.NotModified); - } - - SetCachingHeaders(cacheKeyString, lastDateModified, cacheDuration); - - return null; - } - - /// <summary> - /// Determines whether [is not modified] [the specified cache key]. - /// </summary> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <returns><c>true</c> if [is not modified] [the specified cache key]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(Guid? cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) - { - var isNotModified = true; - - if (Request.Headers.AllKeys.Contains("If-Modified-Since")) - { - DateTime ifModifiedSince; - - if (DateTime.TryParse(Request.Headers["If-Modified-Since"], out ifModifiedSince)) - { - isNotModified = IsNotModified(ifModifiedSince.ToUniversalTime(), cacheDuration, lastDateModified); - } - } - - // Validate If-None-Match - if (isNotModified && (cacheKey.HasValue || !string.IsNullOrEmpty(Request.Headers["If-None-Match"]))) - { - Guid ifNoneMatch; - - if (Guid.TryParse(Request.Headers["If-None-Match"] ?? string.Empty, out ifNoneMatch)) - { - if (cacheKey.HasValue && cacheKey.Value == ifNoneMatch) - { - return true; - } - } - } - - return false; - } - - /// <summary> - /// Determines whether [is not modified] [the specified if modified since]. - /// </summary> - /// <param name="ifModifiedSince">If modified since.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - /// <param name="dateModified">The date modified.</param> - /// <returns><c>true</c> if [is not modified] [the specified if modified since]; otherwise, <c>false</c>.</returns> - private bool IsNotModified(DateTime ifModifiedSince, TimeSpan? cacheDuration, DateTime? dateModified) - { - if (dateModified.HasValue) - { - var lastModified = NormalizeDateForComparison(dateModified.Value); - ifModifiedSince = NormalizeDateForComparison(ifModifiedSince); - - return lastModified <= ifModifiedSince; - } - - if (cacheDuration.HasValue) - { - var cacheExpirationDate = ifModifiedSince.Add(cacheDuration.Value); - - if (DateTime.UtcNow < cacheExpirationDate) - { - return true; - } - } - - return false; - } - - - /// <summary> - /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that - /// </summary> - /// <param name="date">The date.</param> - /// <returns>DateTime.</returns> - private DateTime NormalizeDateForComparison(DateTime date) - { - return new DateTime(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Kind); - } - - /// <summary> - /// Sets the caching headers. - /// </summary> - /// <param name="cacheKey">The cache key.</param> - /// <param name="lastDateModified">The last date modified.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - private void SetCachingHeaders(string cacheKey, DateTime? lastDateModified, TimeSpan? cacheDuration) - { - // Don't specify both last modified and Etag, unless caching unconditionally. They are redundant - // https://developers.google.com/speed/docs/best-practices/caching#LeverageBrowserCaching - if (lastDateModified.HasValue && (string.IsNullOrEmpty(cacheKey) || cacheDuration.HasValue)) - { - AddAgeHeader(lastDateModified); - Response.AddHeader("LastModified", lastDateModified.Value.ToString("r")); - } - - if (cacheDuration.HasValue) - { - Response.AddHeader("Cache-Control", "public, max-age=" + Convert.ToInt32(cacheDuration.Value.TotalSeconds)); - } - else if (!string.IsNullOrEmpty(cacheKey)) - { - Response.AddHeader("Cache-Control", "public"); - } - else - { - Response.AddHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - Response.AddHeader("pragma", "no-cache, no-store, must-revalidate"); - } - - AddExpiresHeader(cacheKey, cacheDuration); - } - - /// <summary> - /// Adds the expires header. - /// </summary> - /// <param name="cacheKey">The cache key.</param> - /// <param name="cacheDuration">Duration of the cache.</param> - private void AddExpiresHeader(string cacheKey, TimeSpan? cacheDuration) - { - if (cacheDuration.HasValue) - { - Response.AddHeader("Expires", DateTime.UtcNow.Add(cacheDuration.Value).ToString("r")); - } - else if (string.IsNullOrEmpty(cacheKey)) - { - Response.AddHeader("Expires", "-1"); - } - } - - /// <summary> - /// Adds the age header. - /// </summary> - /// <param name="lastDateModified">The last date modified.</param> - private void AddAgeHeader(DateTime? lastDateModified) - { - if (lastDateModified.HasValue) - { - Response.AddHeader("Age", Convert.ToInt64((DateTime.UtcNow - lastDateModified.Value).TotalSeconds).ToString(CultureInfo.InvariantCulture)); - } - } - } -} diff --git a/MediaBrowser.Networking/HttpServer/HttpServer.cs b/MediaBrowser.Networking/HttpServer/HttpServer.cs deleted file mode 100644 index 08a6b3561e..0000000000 --- a/MediaBrowser.Networking/HttpServer/HttpServer.cs +++ /dev/null @@ -1,551 +0,0 @@ -using Funq; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; -using ServiceStack.Api.Swagger; -using ServiceStack.Common.Web; -using ServiceStack.Configuration; -using ServiceStack.Logging.NLogger; -using ServiceStack.ServiceHost; -using ServiceStack.ServiceInterface.Cors; -using ServiceStack.Text; -using ServiceStack.WebHost.Endpoints; -using ServiceStack.WebHost.Endpoints.Extensions; -using ServiceStack.WebHost.Endpoints.Support; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.WebSockets; -using System.Reactive.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Networking.HttpServer -{ - /// <summary> - /// Class HttpServer - /// </summary> - public class HttpServer : HttpListenerBase, IHttpServer - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Gets the URL prefix. - /// </summary> - /// <value>The URL prefix.</value> - public string UrlPrefix { get; private set; } - - /// <summary> - /// The _rest services - /// </summary> - private readonly List<IRestfulService> _restServices = new List<IRestfulService>(); - - /// <summary> - /// Gets or sets the application host. - /// </summary> - /// <value>The application host.</value> - private IApplicationHost ApplicationHost { get; set; } - - /// <summary> - /// This subscribes to HttpListener requests and finds the appropriate BaseHandler to process it - /// </summary> - /// <value>The HTTP listener.</value> - private IDisposable HttpListener { get; set; } - - /// <summary> - /// Gets or sets the protobuf serializer. - /// </summary> - /// <value>The protobuf serializer.</value> - private IProtobufSerializer ProtobufSerializer { get; set; } - - /// <summary> - /// Occurs when [web socket connected]. - /// </summary> - public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; - - /// <summary> - /// Gets the default redirect path. - /// </summary> - /// <value>The default redirect path.</value> - private string DefaultRedirectPath { get; set; } - - /// <summary> - /// Gets or sets the name of the server. - /// </summary> - /// <value>The name of the server.</value> - private string ServerName { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="HttpServer" /> class. - /// </summary> - /// <param name="applicationHost">The application host.</param> - /// <param name="protobufSerializer">The protobuf serializer.</param> - /// <param name="logger">The logger.</param> - /// <param name="serverName">Name of the server.</param> - /// <param name="defaultRedirectpath">The default redirectpath.</param> - /// <exception cref="System.ArgumentNullException">urlPrefix</exception> - public HttpServer(IApplicationHost applicationHost, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath) - : base() - { - if (protobufSerializer == null) - { - throw new ArgumentNullException("protobufSerializer"); - } - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - if (applicationHost == null) - { - throw new ArgumentNullException("applicationHost"); - } - if (string.IsNullOrEmpty(serverName)) - { - throw new ArgumentNullException("serverName"); - } - if (string.IsNullOrEmpty(defaultRedirectpath)) - { - throw new ArgumentNullException("defaultRedirectpath"); - } - - ServerName = serverName; - DefaultRedirectPath = defaultRedirectpath; - ProtobufSerializer = protobufSerializer; - _logger = logger; - ApplicationHost = applicationHost; - - EndpointHostConfig.Instance.ServiceStackHandlerFactoryPath = null; - EndpointHostConfig.Instance.MetadataRedirectPath = "metadata"; - } - - /// <summary> - /// Configures the specified container. - /// </summary> - /// <param name="container">The container.</param> - public override void Configure(Container container) - { - JsConfig.DateHandler = JsonDateHandler.ISO8601; - JsConfig.ExcludeTypeInfo = true; - JsConfig.IncludeNullValues = false; - - SetConfig(new EndpointHostConfig - { - DefaultRedirectPath = DefaultRedirectPath, - - // Tell SS to bubble exceptions up to here - WriteErrorsToResponse = false, - - DebugMode = true - }); - - container.Adapter = new ContainerAdapter(ApplicationHost); - - Plugins.Add(new SwaggerFeature()); - Plugins.Add(new CorsFeature()); - - ServiceStack.Logging.LogManager.LogFactory = new NLogFactory(); - } - - /// <summary> - /// Starts the Web Service - /// </summary> - /// <param name="urlBase">A Uri that acts as the base that the server is listening on. - /// Format should be: http://127.0.0.1:8080/ or http://127.0.0.1:8080/somevirtual/ - /// Note: the trailing slash is required! For more info see the - /// HttpListener.Prefixes property on MSDN.</param> - public override void Start(string urlBase) - { - if (string.IsNullOrEmpty(urlBase)) - { - throw new ArgumentNullException("urlBase"); - } - - // *** Already running - just leave it in place - if (IsStarted) - { - return; - } - - if (Listener == null) - { - Listener = new HttpListener(); - } - - EndpointHost.Config.ServiceStackHandlerFactoryPath = HttpListenerRequestWrapper.GetHandlerPathIfAny(urlBase); - - UrlPrefix = urlBase; - - Listener.Prefixes.Add(urlBase); - - IsStarted = true; - Listener.Start(); - - HttpListener = CreateObservableStream().Subscribe(ProcessHttpRequestAsync); - } - - /// <summary> - /// Creates the observable stream. - /// </summary> - /// <returns>IObservable{HttpListenerContext}.</returns> - private IObservable<HttpListenerContext> CreateObservableStream() - { - return Observable.Create<HttpListenerContext>(obs => - Observable.FromAsync(() => Listener.GetContextAsync()) - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// <summary> - /// Processes incoming http requests by routing them to the appropiate handler - /// </summary> - /// <param name="context">The CTX.</param> - private async void ProcessHttpRequestAsync(HttpListenerContext context) - { - LogHttpRequest(context); - - if (context.Request.IsWebSocketRequest) - { - await ProcessWebSocketRequest(context).ConfigureAwait(false); - return; - } - - - Task.Run(() => - { - RaiseReceiveWebRequest(context); - - try - { - ProcessRequest(context); - } - catch (InvalidOperationException ex) - { - HandleException(context.Response, ex, 422); - - throw; - } - catch (ResourceNotFoundException ex) - { - HandleException(context.Response, ex, 404); - - throw; - } - catch (FileNotFoundException ex) - { - HandleException(context.Response, ex, 404); - - throw; - } - catch (DirectoryNotFoundException ex) - { - HandleException(context.Response, ex, 404); - - throw; - } - catch (UnauthorizedAccessException ex) - { - HandleException(context.Response, ex, 401); - - throw; - } - catch (ArgumentException ex) - { - HandleException(context.Response, ex, 400); - - throw; - } - catch (Exception ex) - { - HandleException(context.Response, ex, 500); - - throw; - } - }); - } - - /// <summary> - /// Processes the web socket request. - /// </summary> - /// <param name="ctx">The CTX.</param> - /// <returns>Task.</returns> - private async Task ProcessWebSocketRequest(HttpListenerContext ctx) - { - try - { - var webSocketContext = await ctx.AcceptWebSocketAsync(null).ConfigureAwait(false); - - if (WebSocketConnected != null) - { - WebSocketConnected(this, new WebSocketConnectEventArgs { WebSocket = new NativeWebSocket(webSocketContext.WebSocket, _logger), Endpoint = ctx.Request.RemoteEndPoint.ToString() }); - } - } - catch (Exception ex) - { - _logger.ErrorException("AcceptWebSocketAsync error", ex); - - ctx.Response.StatusCode = 500; - ctx.Response.Close(); - } - } - - /// <summary> - /// Logs the HTTP request. - /// </summary> - /// <param name="ctx">The CTX.</param> - private void LogHttpRequest(HttpListenerContext ctx) - { - var log = new StringBuilder(); - - log.AppendLine("Url: " + ctx.Request.Url); - log.AppendLine("Headers: " + string.Join(",", ctx.Request.Headers.AllKeys.Select(k => k + "=" + ctx.Request.Headers[k]))); - - var type = ctx.Request.IsWebSocketRequest ? "Web Socket" : "HTTP " + ctx.Request.HttpMethod; - - if (EnableHttpRequestLogging) - { - _logger.LogMultiline(type + " request received from " + ctx.Request.RemoteEndPoint, LogSeverity.Debug, log); - } - } - - /// <summary> - /// Appends the error message. - /// </summary> - /// <param name="response">The response.</param> - /// <param name="ex">The ex.</param> - /// <param name="statusCode">The status code.</param> - private void HandleException(HttpListenerResponse response, Exception ex, int statusCode) - { - _logger.ErrorException("Error processing request", ex); - - response.StatusCode = statusCode; - - response.Headers.Add("Status", statusCode.ToString(new CultureInfo("en-US"))); - - response.Headers.Remove("Age"); - response.Headers.Remove("Expires"); - response.Headers.Remove("Cache-Control"); - response.Headers.Remove("Etag"); - response.Headers.Remove("Last-Modified"); - - response.ContentType = "text/plain"; - - if (!string.IsNullOrEmpty(ex.Message)) - { - response.AddHeader("X-Application-Error-Code", ex.Message); - } - - // This could fail, but try to add the stack trace as the body content - try - { - var sb = new StringBuilder(); - sb.AppendLine("{"); - sb.AppendLine("\"ResponseStatus\":{"); - sb.AppendFormat(" \"ErrorCode\":{0},\n", ex.GetType().Name.EncodeJson()); - sb.AppendFormat(" \"Message\":{0},\n", ex.Message.EncodeJson()); - sb.AppendFormat(" \"StackTrace\":{0}\n", ex.StackTrace.EncodeJson()); - sb.AppendLine("}"); - sb.AppendLine("}"); - - response.StatusCode = 500; - response.ContentType = ContentType.Json; - var sbBytes = sb.ToString().ToUtf8Bytes(); - response.OutputStream.Write(sbBytes, 0, sbBytes.Length); - response.Close(); - } - catch (Exception errorEx) - { - _logger.ErrorException("Error processing failed request", errorEx); - } - } - - - /// <summary> - /// Overridable method that can be used to implement a custom hnandler - /// </summary> - /// <param name="context">The context.</param> - /// <exception cref="System.NotImplementedException">Cannot execute handler: + handler + at PathInfo: + httpReq.PathInfo</exception> - protected override void ProcessRequest(HttpListenerContext context) - { - if (string.IsNullOrEmpty(context.Request.RawUrl)) return; - - var operationName = context.Request.GetOperationName(); - - var httpReq = new HttpListenerRequestWrapper(operationName, context.Request); - var httpRes = new HttpListenerResponseWrapper(context.Response); - var handler = ServiceStackHttpHandlerFactory.GetHandler(httpReq); - - var serviceStackHandler = handler as IServiceStackHttpHandler; - - if (serviceStackHandler != null) - { - var restHandler = serviceStackHandler as RestHandler; - if (restHandler != null) - { - httpReq.OperationName = operationName = restHandler.RestPath.RequestType.Name; - } - serviceStackHandler.ProcessRequest(httpReq, httpRes, operationName); - LogResponse(context); - httpRes.Close(); - return; - } - - throw new NotImplementedException("Cannot execute handler: " + handler + " at PathInfo: " + httpReq.PathInfo); - } - - /// <summary> - /// Logs the response. - /// </summary> - /// <param name="ctx">The CTX.</param> - private void LogResponse(HttpListenerContext ctx) - { - var statusode = ctx.Response.StatusCode; - - var log = new StringBuilder(); - - log.AppendLine(string.Format("Url: {0}", ctx.Request.Url)); - - log.AppendLine("Headers: " + string.Join(",", ctx.Response.Headers.AllKeys.Select(k => k + "=" + ctx.Response.Headers[k]))); - - var msg = "Http Response Sent (" + statusode + ") to " + ctx.Request.RemoteEndPoint; - - if (EnableHttpRequestLogging) - { - _logger.LogMultiline(msg, LogSeverity.Debug, log); - } - } - - /// <summary> - /// Creates the service manager. - /// </summary> - /// <param name="assembliesWithServices">The assemblies with services.</param> - /// <returns>ServiceManager.</returns> - protected override ServiceManager CreateServiceManager(params Assembly[] assembliesWithServices) - { - var types = _restServices.Select(r => r.GetType()).ToArray(); - - return new ServiceManager(new Container(), new ServiceController(() => types)); - } - - /// <summary> - /// Shut down the Web Service - /// </summary> - public override void Stop() - { - if (HttpListener != null) - { - HttpListener.Dispose(); - HttpListener = null; - } - - if (Listener != null) - { - Listener.Prefixes.Remove(UrlPrefix); - } - - base.Stop(); - } - - /// <summary> - /// The _supports native web socket - /// </summary> - private bool? _supportsNativeWebSocket; - - /// <summary> - /// Gets a value indicating whether [supports web sockets]. - /// </summary> - /// <value><c>true</c> if [supports web sockets]; otherwise, <c>false</c>.</value> - public bool SupportsWebSockets - { - get - { - if (!_supportsNativeWebSocket.HasValue) - { - try - { - new ClientWebSocket(); - - _supportsNativeWebSocket = true; - } - catch (PlatformNotSupportedException) - { - _supportsNativeWebSocket = false; - } - } - - return _supportsNativeWebSocket.Value; - } - } - - - /// <summary> - /// Gets or sets a value indicating whether [enable HTTP request logging]. - /// </summary> - /// <value><c>true</c> if [enable HTTP request logging]; otherwise, <c>false</c>.</value> - public bool EnableHttpRequestLogging { get; set; } - - /// <summary> - /// Adds the rest handlers. - /// </summary> - /// <param name="services">The services.</param> - public void Init(IEnumerable<IRestfulService> services) - { - _restServices.AddRange(services); - - EndpointHost.ConfigureHost(this, ServerName, CreateServiceManager()); - ContentTypeFilters.Register(ContentType.ProtoBuf, (reqCtx, res, stream) => ProtobufSerializer.SerializeToStream(res, stream), (type, stream) => ProtobufSerializer.DeserializeFromStream(stream, type)); - - Init(); - } - } - - /// <summary> - /// Class ContainerAdapter - /// </summary> - class ContainerAdapter : IContainerAdapter - { - /// <summary> - /// The _app host - /// </summary> - private readonly IApplicationHost _appHost; - - /// <summary> - /// Initializes a new instance of the <see cref="ContainerAdapter" /> class. - /// </summary> - /// <param name="appHost">The app host.</param> - public ContainerAdapter(IApplicationHost appHost) - { - _appHost = appHost; - } - /// <summary> - /// Resolves this instance. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T Resolve<T>() - { - return _appHost.Resolve<T>(); - } - - /// <summary> - /// Tries the resolve. - /// </summary> - /// <typeparam name="T"></typeparam> - /// <returns>``0.</returns> - public T TryResolve<T>() - { - return _appHost.TryResolve<T>(); - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Networking/HttpServer/NativeWebSocket.cs b/MediaBrowser.Networking/HttpServer/NativeWebSocket.cs deleted file mode 100644 index 84d163be87..0000000000 --- a/MediaBrowser.Networking/HttpServer/NativeWebSocket.cs +++ /dev/null @@ -1,165 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Net.WebSockets; -using System.Threading; -using System.Threading.Tasks; -using WebSocketMessageType = MediaBrowser.Common.Net.WebSocketMessageType; -using WebSocketState = MediaBrowser.Common.Net.WebSocketState; - -namespace MediaBrowser.Networking.HttpServer -{ - /// <summary> - /// Class NativeWebSocket - /// </summary> - public class NativeWebSocket : IWebSocket - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Gets or sets the web socket. - /// </summary> - /// <value>The web socket.</value> - private System.Net.WebSockets.WebSocket WebSocket { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="NativeWebSocket" /> class. - /// </summary> - /// <param name="socket">The socket.</param> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">socket</exception> - public NativeWebSocket(System.Net.WebSockets.WebSocket socket, ILogger logger) - { - if (socket == null) - { - throw new ArgumentNullException("socket"); - } - - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - _logger = logger; - WebSocket = socket; - - Receive(); - } - - /// <summary> - /// Gets or sets the state. - /// </summary> - /// <value>The state.</value> - public WebSocketState State - { - get - { - WebSocketState commonState; - - if (!Enum.TryParse(WebSocket.State.ToString(), true, out commonState)) - { - _logger.Warn("Unrecognized WebSocketState: {0}", WebSocket.State.ToString()); - } - - return commonState; - } - } - - /// <summary> - /// Receives this instance. - /// </summary> - private async void Receive() - { - while (true) - { - byte[] bytes; - - try - { - bytes = await ReceiveBytesAsync(CancellationToken.None).ConfigureAwait(false); - } - catch (WebSocketException ex) - { - _logger.ErrorException("Error reveiving web socket message", ex); - - break; - } - - if (OnReceiveDelegate != null) - { - OnReceiveDelegate(bytes); - } - } - } - - /// <summary> - /// Receives the async. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{WebSocketMessageInfo}.</returns> - /// <exception cref="System.Net.WebSockets.WebSocketException">Connection closed</exception> - private async Task<byte[]> ReceiveBytesAsync(CancellationToken cancellationToken) - { - var bytes = new byte[4096]; - var buffer = new ArraySegment<byte>(bytes); - - var result = await WebSocket.ReceiveAsync(buffer, cancellationToken).ConfigureAwait(false); - - if (result.CloseStatus.HasValue) - { - throw new WebSocketException("Connection closed"); - } - - return buffer.Array; - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="type">The type.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) - { - System.Net.WebSockets.WebSocketMessageType nativeType; - - if (!Enum.TryParse(type.ToString(), true, out nativeType)) - { - _logger.Warn("Unrecognized WebSocketMessageType: {0}", type.ToString()); - } - - return WebSocket.SendAsync(new ArraySegment<byte>(bytes), nativeType, true, cancellationToken); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - WebSocket.Dispose(); - } - } - - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> - public Action<byte[]> OnReceiveDelegate { get; set; } - } -} diff --git a/MediaBrowser.Networking/HttpServer/ServerFactory.cs b/MediaBrowser.Networking/HttpServer/ServerFactory.cs deleted file mode 100644 index 716fd450a5..0000000000 --- a/MediaBrowser.Networking/HttpServer/ServerFactory.cs +++ /dev/null @@ -1,27 +0,0 @@ -using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Serialization; - -namespace MediaBrowser.Networking.HttpServer -{ - /// <summary> - /// Class ServerFactory - /// </summary> - public static class ServerFactory - { - /// <summary> - /// Creates the server. - /// </summary> - /// <param name="applicationHost">The application host.</param> - /// <param name="protobufSerializer">The protobuf serializer.</param> - /// <param name="logger">The logger.</param> - /// <param name="serverName">Name of the server.</param> - /// <param name="defaultRedirectpath">The default redirectpath.</param> - /// <returns>IHttpServer.</returns> - public static IHttpServer CreateServer(IApplicationHost applicationHost, IProtobufSerializer protobufSerializer, ILogger logger, string serverName, string defaultRedirectpath) - { - return new HttpServer(applicationHost, protobufSerializer, logger, serverName, defaultRedirectpath); - } - } -} diff --git a/MediaBrowser.Networking/Management/NativeMethods.cs b/MediaBrowser.Networking/Management/NativeMethods.cs deleted file mode 100644 index 9a888fab2b..0000000000 --- a/MediaBrowser.Networking/Management/NativeMethods.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Security; - -namespace MediaBrowser.Networking.Management -{ - /// <summary> - /// Class NativeMethods - /// </summary> - [SuppressUnmanagedCodeSecurity] - public static class NativeMethods - { - //declare the Netapi32 : NetServerEnum method import - /// <summary> - /// Nets the server enum. - /// </summary> - /// <param name="ServerName">Name of the server.</param> - /// <param name="dwLevel">The dw level.</param> - /// <param name="pBuf">The p buf.</param> - /// <param name="dwPrefMaxLen">The dw pref max len.</param> - /// <param name="dwEntriesRead">The dw entries read.</param> - /// <param name="dwTotalEntries">The dw total entries.</param> - /// <param name="dwServerType">Type of the dw server.</param> - /// <param name="domain">The domain.</param> - /// <param name="dwResumeHandle">The dw resume handle.</param> - /// <returns>System.Int32.</returns> - [DllImport("Netapi32", CharSet = CharSet.Auto, SetLastError = true), - SuppressUnmanagedCodeSecurityAttribute] - - public static extern int NetServerEnum( - string ServerName, // must be null - int dwLevel, - ref IntPtr pBuf, - int dwPrefMaxLen, - out int dwEntriesRead, - out int dwTotalEntries, - int dwServerType, - string domain, // null for login domain - out int dwResumeHandle - ); - - //declare the Netapi32 : NetApiBufferFree method import - /// <summary> - /// Nets the API buffer free. - /// </summary> - /// <param name="pBuf">The p buf.</param> - /// <returns>System.Int32.</returns> - [DllImport("Netapi32", SetLastError = true), - SuppressUnmanagedCodeSecurityAttribute] - - public static extern int NetApiBufferFree( - IntPtr pBuf); - } - - //create a _SERVER_INFO_100 STRUCTURE - /// <summary> - /// Struct _SERVER_INFO_100 - /// </summary> - [StructLayout(LayoutKind.Sequential)] - public struct _SERVER_INFO_100 - { - /// <summary> - /// The sv100_platform_id - /// </summary> - internal int sv100_platform_id; - /// <summary> - /// The sv100_name - /// </summary> - [MarshalAs(UnmanagedType.LPWStr)] - internal string sv100_name; - } -} diff --git a/MediaBrowser.Networking/Management/NetworkManager.cs b/MediaBrowser.Networking/Management/NetworkManager.cs deleted file mode 100644 index 208c64a6ed..0000000000 --- a/MediaBrowser.Networking/Management/NetworkManager.cs +++ /dev/null @@ -1,377 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Net; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Management; -using System.Net; -using System.Net.Sockets; -using System.Runtime.InteropServices; - -namespace MediaBrowser.Networking.Management -{ - /// <summary> - /// Class NetUtils - /// </summary> - public class NetworkManager : INetworkManager - { - /// <summary> - /// Gets the machine's local ip address - /// </summary> - /// <returns>IPAddress.</returns> - public string GetLocalIpAddress() - { - var host = Dns.GetHostEntry(Dns.GetHostName()); - - var ip = host.AddressList.FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork); - - if (ip == null) - { - return null; - } - - return ip.ToString(); - } - - /// <summary> - /// Gets a random port number that is currently available - /// </summary> - /// <returns>System.Int32.</returns> - public int GetRandomUnusedPort() - { - var listener = new TcpListener(IPAddress.Any, 0); - listener.Start(); - var port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - return port; - } - - /// <summary> - /// Creates the netsh URL registration. - /// </summary> - public void AuthorizeHttpListening(string url) - { - var startInfo = new ProcessStartInfo - { - FileName = "netsh", - Arguments = string.Format("http add urlacl url={0} user=\"NT AUTHORITY\\Authenticated Users\"", url), - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - Verb = "runas", - ErrorDialog = false - }; - - using (var process = Process.Start(startInfo)) - { - process.WaitForExit(); - } - } - - /// <summary> - /// Adds the windows firewall rule. - /// </summary> - /// <param name="port">The port.</param> - /// <param name="protocol">The protocol.</param> - public void AddSystemFirewallRule(int port, NetworkProtocol protocol) - { - // First try to remove it so we don't end up creating duplicates - RemoveSystemFirewallRule(port, protocol); - - var args = string.Format("advfirewall firewall add rule name=\"Port {0}\" dir=in action=allow protocol={1} localport={0}", port, protocol); - - RunNetsh(args); - } - - /// <summary> - /// Removes the windows firewall rule. - /// </summary> - /// <param name="port">The port.</param> - /// <param name="protocol">The protocol.</param> - public void RemoveSystemFirewallRule(int port, NetworkProtocol protocol) - { - var args = string.Format("advfirewall firewall delete rule name=\"Port {0}\" protocol={1} localport={0}", port, protocol); - - RunNetsh(args); - } - - /// <summary> - /// Runs the netsh. - /// </summary> - /// <param name="args">The args.</param> - private void RunNetsh(string args) - { - var startInfo = new ProcessStartInfo - { - FileName = "netsh", - Arguments = args, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - Verb = "runas", - ErrorDialog = false - }; - - using (var process = new Process { StartInfo = startInfo }) - { - process.Start(); - process.WaitForExit(); - } - } - - /// <summary> - /// Returns MAC Address from first Network Card in Computer - /// </summary> - /// <returns>[string] MAC Address</returns> - public string GetMacAddress() - { - var mc = new ManagementClass("Win32_NetworkAdapterConfiguration"); - var moc = mc.GetInstances(); - var macAddress = String.Empty; - foreach (ManagementObject mo in moc) - { - if (macAddress == String.Empty) // only return MAC Address from first card - { - try - { - if ((bool)mo["IPEnabled"]) macAddress = mo["MacAddress"].ToString(); - } - catch - { - mo.Dispose(); - return ""; - } - } - mo.Dispose(); - } - - return macAddress.Replace(":", ""); - } - - /// <summary> - /// Uses the DllImport : NetServerEnum with all its required parameters - /// (see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp - /// for full details or method signature) to retrieve a list of domain SV_TYPE_WORKSTATION - /// and SV_TYPE_SERVER PC's - /// </summary> - /// <returns>Arraylist that represents all the SV_TYPE_WORKSTATION and SV_TYPE_SERVER - /// PC's in the Domain</returns> - public IEnumerable<string> GetNetworkDevices() - { - //local fields - const int MAX_PREFERRED_LENGTH = -1; - var SV_TYPE_WORKSTATION = 1; - var SV_TYPE_SERVER = 2; - var buffer = IntPtr.Zero; - var tmpBuffer = IntPtr.Zero; - var entriesRead = 0; - var totalEntries = 0; - var resHandle = 0; - var sizeofINFO = Marshal.SizeOf(typeof(_SERVER_INFO_100)); - - try - { - //call the DllImport : NetServerEnum with all its required parameters - //see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netserverenum.asp - //for full details of method signature - var ret = NativeMethods.NetServerEnum(null, 100, ref buffer, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries, SV_TYPE_WORKSTATION | SV_TYPE_SERVER, null, out resHandle); - - //if the returned with a NERR_Success (C++ term), =0 for C# - if (ret == 0) - { - //loop through all SV_TYPE_WORKSTATION and SV_TYPE_SERVER PC's - for (var i = 0; i < totalEntries; i++) - { - //get pointer to, Pointer to the buffer that received the data from - //the call to NetServerEnum. Must ensure to use correct size of - //STRUCTURE to ensure correct location in memory is pointed to - tmpBuffer = new IntPtr((int)buffer + (i * sizeofINFO)); - //Have now got a pointer to the list of SV_TYPE_WORKSTATION and - //SV_TYPE_SERVER PC's, which is unmanaged memory - //Needs to Marshal data from an unmanaged block of memory to a - //managed object, again using STRUCTURE to ensure the correct data - //is marshalled - var svrInfo = (_SERVER_INFO_100)Marshal.PtrToStructure(tmpBuffer, typeof(_SERVER_INFO_100)); - - //add the PC names to the ArrayList - if (!string.IsNullOrEmpty(svrInfo.sv100_name)) - { - yield return svrInfo.sv100_name; - } - } - } - } - finally - { - //The NetApiBufferFree function frees - //the memory that the NetApiBufferAllocate function allocates - NativeMethods.NetApiBufferFree(buffer); - } - } - - - /// <summary> - /// Gets the network shares. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>IEnumerable{NetworkShare}.</returns> - public IEnumerable<NetworkShare> GetNetworkShares(string path) - { - return new ShareCollection(path).OfType<Share>().Select(ToNetworkShare); - } - - /// <summary> - /// To the network share. - /// </summary> - /// <param name="share">The share.</param> - /// <returns>NetworkShare.</returns> - private NetworkShare ToNetworkShare(Share share) - { - return new NetworkShare - { - Name = share.NetName, - Path = share.Path, - Remark = share.Remark, - Server = share.Server, - ShareType = ToNetworkShareType(share.ShareType) - }; - } - - /// <summary> - /// To the type of the network share. - /// </summary> - /// <param name="shareType">Type of the share.</param> - /// <returns>NetworkShareType.</returns> - /// <exception cref="System.ArgumentException">Unknown share type</exception> - private NetworkShareType ToNetworkShareType(ShareType shareType) - { - switch (shareType) - { - case ShareType.Device: - return NetworkShareType.Device; - case ShareType.Disk : - return NetworkShareType.Disk; - case ShareType.IPC : - return NetworkShareType.Ipc; - case ShareType.Printer : - return NetworkShareType.Printer; - case ShareType.Special: - return NetworkShareType.Special; - default: - throw new ArgumentException("Unknown share type"); - } - } - - /// <summary> - /// Parses the specified endpointstring. - /// </summary> - /// <param name="endpointstring">The endpointstring.</param> - /// <returns>IPEndPoint.</returns> - public IPEndPoint Parse(string endpointstring) - { - return Parse(endpointstring, -1); - } - - /// <summary> - /// Parses the specified endpointstring. - /// </summary> - /// <param name="endpointstring">The endpointstring.</param> - /// <param name="defaultport">The defaultport.</param> - /// <returns>IPEndPoint.</returns> - /// <exception cref="System.ArgumentException">Endpoint descriptor may not be empty.</exception> - /// <exception cref="System.FormatException"></exception> - private static IPEndPoint Parse(string endpointstring, int defaultport) - { - if (string.IsNullOrEmpty(endpointstring) - || endpointstring.Trim().Length == 0) - { - throw new ArgumentException("Endpoint descriptor may not be empty."); - } - - if (defaultport != -1 && - (defaultport < IPEndPoint.MinPort - || defaultport > IPEndPoint.MaxPort)) - { - throw new ArgumentException(string.Format("Invalid default port '{0}'", defaultport)); - } - - string[] values = endpointstring.Split(new char[] { ':' }); - IPAddress ipaddy; - int port = -1; - - //check if we have an IPv6 or ports - if (values.Length <= 2) // ipv4 or hostname - { - if (values.Length == 1) - //no port is specified, default - port = defaultport; - else - port = GetPort(values[1]); - - //try to use the address as IPv4, otherwise get hostname - if (!IPAddress.TryParse(values[0], out ipaddy)) - ipaddy = GetIPfromHost(values[0]); - } - else if (values.Length > 2) //ipv6 - { - //could [a:b:c]:d - if (values[0].StartsWith("[") && values[values.Length - 2].EndsWith("]")) - { - string ipaddressstring = string.Join(":", values.Take(values.Length - 1).ToArray()); - ipaddy = IPAddress.Parse(ipaddressstring); - port = GetPort(values[values.Length - 1]); - } - else //[a:b:c] or a:b:c - { - ipaddy = IPAddress.Parse(endpointstring); - port = defaultport; - } - } - else - { - throw new FormatException(string.Format("Invalid endpoint ipaddress '{0}'", endpointstring)); - } - - if (port == -1) - throw new ArgumentException(string.Format("No port specified: '{0}'", endpointstring)); - - return new IPEndPoint(ipaddy, port); - } - - /// <summary> - /// Gets the port. - /// </summary> - /// <param name="p">The p.</param> - /// <returns>System.Int32.</returns> - /// <exception cref="System.FormatException"></exception> - private static int GetPort(string p) - { - int port; - - if (!int.TryParse(p, out port) - || port < IPEndPoint.MinPort - || port > IPEndPoint.MaxPort) - { - throw new FormatException(string.Format("Invalid end point port '{0}'", p)); - } - - return port; - } - - /// <summary> - /// Gets the I pfrom host. - /// </summary> - /// <param name="p">The p.</param> - /// <returns>IPAddress.</returns> - /// <exception cref="System.ArgumentException"></exception> - private static IPAddress GetIPfromHost(string p) - { - var hosts = Dns.GetHostAddresses(p); - - if (hosts == null || hosts.Length == 0) - throw new ArgumentException(string.Format("Host not found: {0}", p)); - - return hosts[0]; - } - } - -} diff --git a/MediaBrowser.Networking/Management/NetworkShares.cs b/MediaBrowser.Networking/Management/NetworkShares.cs deleted file mode 100644 index 0239ddead8..0000000000 --- a/MediaBrowser.Networking/Management/NetworkShares.cs +++ /dev/null @@ -1,638 +0,0 @@ -using System; -using System.IO; -using System.Collections; -using System.Runtime.InteropServices; - -namespace MediaBrowser.Networking.Management -{ - /// <summary> - /// Type of share - /// </summary> - [Flags] - public enum ShareType - { - /// <summary>Disk share</summary> - Disk = 0, - /// <summary>Printer share</summary> - Printer = 1, - /// <summary>Device share</summary> - Device = 2, - /// <summary>IPC share</summary> - IPC = 3, - /// <summary>Special share</summary> - Special = -2147483648, // 0x80000000, - } - - #region Share - - /// <summary> - /// Information about a local share - /// </summary> - public class Share - { - #region Private data - - private string _server; - private string _netName; - private string _path; - private ShareType _shareType; - private string _remark; - - #endregion - - #region Constructor - - /// <summary> - /// Constructor - /// </summary> - /// <param name="Server"></param> - /// <param name="shi"></param> - public Share(string server, string netName, string path, ShareType shareType, string remark) - { - if (ShareType.Special == shareType && "IPC$" == netName) - { - shareType |= ShareType.IPC; - } - - _server = server; - _netName = netName; - _path = path; - _shareType = shareType; - _remark = remark; - } - - #endregion - - #region Properties - - /// <summary> - /// The name of the computer that this share belongs to - /// </summary> - public string Server - { - get { return _server; } - } - - /// <summary> - /// Share name - /// </summary> - public string NetName - { - get { return _netName; } - } - - /// <summary> - /// Local path - /// </summary> - public string Path - { - get { return _path; } - } - - /// <summary> - /// Share type - /// </summary> - public ShareType ShareType - { - get { return _shareType; } - } - - /// <summary> - /// Comment - /// </summary> - public string Remark - { - get { return _remark; } - } - - /// <summary> - /// Returns true if this is a file system share - /// </summary> - public bool IsFileSystem - { - get - { - // Shared device - if (0 != (_shareType & ShareType.Device)) return false; - // IPC share - if (0 != (_shareType & ShareType.IPC)) return false; - // Shared printer - if (0 != (_shareType & ShareType.Printer)) return false; - - // Standard disk share - if (0 == (_shareType & ShareType.Special)) return true; - - // Special disk share (e.g. C$) - return ShareType.Special == _shareType && !string.IsNullOrEmpty(_netName); - } - } - - /// <summary> - /// Get the root of a disk-based share - /// </summary> - public DirectoryInfo Root - { - get - { - if (IsFileSystem) - { - if (string.IsNullOrEmpty(_server)) - if (string.IsNullOrEmpty(_path)) - return new DirectoryInfo(ToString()); - else - return new DirectoryInfo(_path); - return new DirectoryInfo(ToString()); - } - return null; - } - } - - #endregion - - /// <summary> - /// Returns the path to this share - /// </summary> - /// <returns></returns> - public override string ToString() - { - if (string.IsNullOrEmpty(_server)) - { - return string.Format(@"\\{0}\{1}", Environment.MachineName, _netName); - } - return string.Format(@"\\{0}\{1}", _server, _netName); - } - - /// <summary> - /// Returns true if this share matches the local path - /// </summary> - /// <param name="path"></param> - /// <returns></returns> - public bool MatchesPath(string path) - { - if (!IsFileSystem) return false; - if (string.IsNullOrEmpty(path)) return true; - - return path.ToLower().StartsWith(_path.ToLower()); - } - } - - #endregion - - /// <summary> - /// A collection of shares - /// </summary> - public class ShareCollection : ReadOnlyCollectionBase - { - #region Platform - - /// <summary> - /// Is this an NT platform? - /// </summary> - protected static bool IsNT - { - get { return (PlatformID.Win32NT == Environment.OSVersion.Platform); } - } - - /// <summary> - /// Returns true if this is Windows 2000 or higher - /// </summary> - protected static bool IsW2KUp - { - get - { - OperatingSystem os = Environment.OSVersion; - if (PlatformID.Win32NT == os.Platform && os.Version.Major >= 5) - return true; - else - return false; - } - } - - #endregion - - #region Interop - - #region Constants - - /// <summary>Maximum path length</summary> - protected const int MAX_PATH = 260; - /// <summary>No error</summary> - protected const int NO_ERROR = 0; - /// <summary>Access denied</summary> - protected const int ERROR_ACCESS_DENIED = 5; - /// <summary>Access denied</summary> - protected const int ERROR_WRONG_LEVEL = 124; - /// <summary>More data available</summary> - protected const int ERROR_MORE_DATA = 234; - /// <summary>Not connected</summary> - protected const int ERROR_NOT_CONNECTED = 2250; - /// <summary>Level 1</summary> - protected const int UNIVERSAL_NAME_INFO_LEVEL = 1; - /// <summary>Max extries (9x)</summary> - protected const int MAX_SI50_ENTRIES = 20; - - #endregion - - #region Structures - - /// <summary>Unc name</summary> - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - protected struct UNIVERSAL_NAME_INFO - { - [MarshalAs(UnmanagedType.LPTStr)] - public string lpUniversalName; - } - - /// <summary>Share information, NT, level 2</summary> - /// <remarks> - /// Requires admin rights to work. - /// </remarks> - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - protected struct SHARE_INFO_2 - { - [MarshalAs(UnmanagedType.LPWStr)] - public string NetName; - public ShareType ShareType; - [MarshalAs(UnmanagedType.LPWStr)] - public string Remark; - public int Permissions; - public int MaxUsers; - public int CurrentUsers; - [MarshalAs(UnmanagedType.LPWStr)] - public string Path; - [MarshalAs(UnmanagedType.LPWStr)] - public string Password; - } - - /// <summary>Share information, NT, level 1</summary> - /// <remarks> - /// Fallback when no admin rights. - /// </remarks> - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - protected struct SHARE_INFO_1 - { - [MarshalAs(UnmanagedType.LPWStr)] - public string NetName; - public ShareType ShareType; - [MarshalAs(UnmanagedType.LPWStr)] - public string Remark; - } - - /// <summary>Share information, Win9x</summary> - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - protected struct SHARE_INFO_50 - { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)] - public string NetName; - - public byte bShareType; - public ushort Flags; - - [MarshalAs(UnmanagedType.LPTStr)] - public string Remark; - [MarshalAs(UnmanagedType.LPTStr)] - public string Path; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)] - public string PasswordRW; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 9)] - public string PasswordRO; - - public ShareType ShareType - { - get { return (ShareType)((int)bShareType & 0x7F); } - } - } - - /// <summary>Share information level 1, Win9x</summary> - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] - protected struct SHARE_INFO_1_9x - { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 13)] - public string NetName; - public byte Padding; - - public ushort bShareType; - - [MarshalAs(UnmanagedType.LPTStr)] - public string Remark; - - public ShareType ShareType - { - get { return (ShareType)((int)bShareType & 0x7FFF); } - } - } - - #endregion - - #region Functions - - /// <summary>Get a UNC name</summary> - [DllImport("mpr", CharSet = CharSet.Auto)] - protected static extern int WNetGetUniversalName(string lpLocalPath, - int dwInfoLevel, ref UNIVERSAL_NAME_INFO lpBuffer, ref int lpBufferSize); - - /// <summary>Get a UNC name</summary> - [DllImport("mpr", CharSet = CharSet.Auto)] - protected static extern int WNetGetUniversalName(string lpLocalPath, - int dwInfoLevel, IntPtr lpBuffer, ref int lpBufferSize); - - /// <summary>Enumerate shares (NT)</summary> - [DllImport("netapi32", CharSet = CharSet.Unicode)] - protected static extern int NetShareEnum(string lpServerName, int dwLevel, - out IntPtr lpBuffer, int dwPrefMaxLen, out int entriesRead, - out int totalEntries, ref int hResume); - - /// <summary>Enumerate shares (9x)</summary> - [DllImport("svrapi", CharSet = CharSet.Ansi)] - protected static extern int NetShareEnum( - [MarshalAs(UnmanagedType.LPTStr)] string lpServerName, int dwLevel, - IntPtr lpBuffer, ushort cbBuffer, out ushort entriesRead, - out ushort totalEntries); - - /// <summary>Free the buffer (NT)</summary> - [DllImport("netapi32")] - protected static extern int NetApiBufferFree(IntPtr lpBuffer); - - #endregion - - #region Enumerate shares - - /// <summary> - /// Enumerates the shares on Windows NT - /// </summary> - /// <param name="server">The server name</param> - /// <param name="shares">The ShareCollection</param> - protected static void EnumerateSharesNT(string server, ShareCollection shares) - { - int level = 2; - int entriesRead, totalEntries, nRet, hResume = 0; - IntPtr pBuffer = IntPtr.Zero; - - try - { - nRet = NetShareEnum(server, level, out pBuffer, -1, - out entriesRead, out totalEntries, ref hResume); - - if (ERROR_ACCESS_DENIED == nRet) - { - //Need admin for level 2, drop to level 1 - level = 1; - nRet = NetShareEnum(server, level, out pBuffer, -1, - out entriesRead, out totalEntries, ref hResume); - } - - if (NO_ERROR == nRet && entriesRead > 0) - { - Type t = (2 == level) ? typeof(SHARE_INFO_2) : typeof(SHARE_INFO_1); - int offset = Marshal.SizeOf(t); - - for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += offset) - { - IntPtr pItem = new IntPtr(lpItem); - if (1 == level) - { - SHARE_INFO_1 si = (SHARE_INFO_1)Marshal.PtrToStructure(pItem, t); - shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark); - } - else - { - SHARE_INFO_2 si = (SHARE_INFO_2)Marshal.PtrToStructure(pItem, t); - shares.Add(si.NetName, si.Path, si.ShareType, si.Remark); - } - } - } - - } - finally - { - // Clean up buffer allocated by system - if (IntPtr.Zero != pBuffer) - NetApiBufferFree(pBuffer); - } - } - - /// <summary> - /// Enumerates the shares on Windows 9x - /// </summary> - /// <param name="server">The server name</param> - /// <param name="shares">The ShareCollection</param> - protected static void EnumerateShares9x(string server, ShareCollection shares) - { - int level = 50; - int nRet = 0; - ushort entriesRead, totalEntries; - - Type t = typeof(SHARE_INFO_50); - int size = Marshal.SizeOf(t); - ushort cbBuffer = (ushort)(MAX_SI50_ENTRIES * size); - //On Win9x, must allocate buffer before calling API - IntPtr pBuffer = Marshal.AllocHGlobal(cbBuffer); - - try - { - nRet = NetShareEnum(server, level, pBuffer, cbBuffer, - out entriesRead, out totalEntries); - - if (ERROR_WRONG_LEVEL == nRet) - { - level = 1; - t = typeof(SHARE_INFO_1_9x); - size = Marshal.SizeOf(t); - - nRet = NetShareEnum(server, level, pBuffer, cbBuffer, - out entriesRead, out totalEntries); - } - - if (NO_ERROR == nRet || ERROR_MORE_DATA == nRet) - { - for (int i = 0, lpItem = pBuffer.ToInt32(); i < entriesRead; i++, lpItem += size) - { - IntPtr pItem = new IntPtr(lpItem); - - if (1 == level) - { - SHARE_INFO_1_9x si = (SHARE_INFO_1_9x)Marshal.PtrToStructure(pItem, t); - shares.Add(si.NetName, string.Empty, si.ShareType, si.Remark); - } - else - { - SHARE_INFO_50 si = (SHARE_INFO_50)Marshal.PtrToStructure(pItem, t); - shares.Add(si.NetName, si.Path, si.ShareType, si.Remark); - } - } - } - else - Console.WriteLine(nRet); - - } - finally - { - //Clean up buffer - Marshal.FreeHGlobal(pBuffer); - } - } - - /// <summary> - /// Enumerates the shares - /// </summary> - /// <param name="server">The server name</param> - /// <param name="shares">The ShareCollection</param> - protected static void EnumerateShares(string server, ShareCollection shares) - { - if (null != server && 0 != server.Length && !IsW2KUp) - { - server = server.ToUpper(); - - // On NT4, 9x and Me, server has to start with "\\" - if (!('\\' == server[0] && '\\' == server[1])) - server = @"\\" + server; - } - - if (IsNT) - EnumerateSharesNT(server, shares); - else - EnumerateShares9x(server, shares); - } - - #endregion - - #endregion - - #region Static methods - - /// <summary> - /// Returns true if fileName is a valid local file-name of the form: - /// X:\, where X is a drive letter from A-Z - /// </summary> - /// <param name="fileName">The filename to check</param> - /// <returns></returns> - public static bool IsValidFilePath(string fileName) - { - if (null == fileName || 0 == fileName.Length) return false; - - char drive = char.ToUpper(fileName[0]); - if ('A' > drive || drive > 'Z') - return false; - - else if (Path.VolumeSeparatorChar != fileName[1]) - return false; - else if (Path.DirectorySeparatorChar != fileName[2]) - return false; - else - return true; - } - - #endregion - - /// <summary>The name of the server this collection represents</summary> - private string _server; - - #region Constructor - - /// <summary> - /// Default constructor - local machine - /// </summary> - public ShareCollection() - { - _server = string.Empty; - EnumerateShares(_server, this); - } - - /// <summary> - /// Constructor - /// </summary> - /// <param name="Server"></param> - public ShareCollection(string server) - { - _server = server; - EnumerateShares(_server, this); - } - - #endregion - - #region Add - - protected void Add(Share share) - { - InnerList.Add(share); - } - - protected void Add(string netName, string path, ShareType shareType, string remark) - { - InnerList.Add(new Share(_server, netName, path, shareType, remark)); - } - - #endregion - - #region Properties - - /// <summary> - /// Returns the name of the server this collection represents - /// </summary> - public string Server - { - get { return _server; } - } - - /// <summary> - /// Returns the <see cref="Share"/> at the specified index. - /// </summary> - public Share this[int index] - { - get { return (Share)InnerList[index]; } - } - - /// <summary> - /// Returns the <see cref="Share"/> which matches a given local path - /// </summary> - /// <param name="path">The path to match</param> - public Share this[string path] - { - get - { - if (null == path || 0 == path.Length) return null; - - path = Path.GetFullPath(path); - if (!IsValidFilePath(path)) return null; - - Share match = null; - - for (int i = 0; i < InnerList.Count; i++) - { - Share s = (Share)InnerList[i]; - - if (s.IsFileSystem && s.MatchesPath(path)) - { - //Store first match - if (null == match) - match = s; - - // If this has a longer path, - // and this is a disk share or match is a special share, - // then this is a better match - else if (match.Path.Length < s.Path.Length) - { - if (ShareType.Disk == s.ShareType || ShareType.Disk != match.ShareType) - match = s; - } - } - } - - return match; - } - } - - #endregion - - /// <summary> - /// Copy this collection to an array - /// </summary> - /// <param name="array"></param> - /// <param name="index"></param> - public void CopyTo(Share[] array, int index) - { - InnerList.CopyTo(array, index); - } - } -}
\ No newline at end of file diff --git a/MediaBrowser.Networking/MediaBrowser.Networking.csproj b/MediaBrowser.Networking/MediaBrowser.Networking.csproj index 3ef7832dfc..b7d269eeee 100644 --- a/MediaBrowser.Networking/MediaBrowser.Networking.csproj +++ b/MediaBrowser.Networking/MediaBrowser.Networking.csproj @@ -106,18 +106,7 @@ <Compile Include="..\SharedVersion.cs"> <Link>Properties\SharedVersion.cs</Link> </Compile> - <Compile Include="HttpManager\HttpManager.cs" /> - <Compile Include="HttpServer\BaseRestService.cs" /> - <Compile Include="Udp\UdpServer.cs" /> - <Compile Include="WebSocket\AlchemyServer.cs" /> - <Compile Include="WebSocket\AlchemyWebSocket.cs" /> - <Compile Include="HttpServer\HttpServer.cs" /> - <Compile Include="Management\NativeMethods.cs" /> - <Compile Include="Management\NetworkManager.cs" /> - <Compile Include="Management\NetworkShares.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="HttpServer\ServerFactory.cs" /> - <Compile Include="HttpServer\NativeWebSocket.cs" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj"> diff --git a/MediaBrowser.Networking/Udp/UdpServer.cs b/MediaBrowser.Networking/Udp/UdpServer.cs deleted file mode 100644 index 00eb2a0d13..0000000000 --- a/MediaBrowser.Networking/Udp/UdpServer.cs +++ /dev/null @@ -1,203 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Networking.Management; -using System; -using System.Net; -using System.Net.Sockets; -using System.Reactive.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Networking.Udp -{ - /// <summary> - /// Provides a Udp Server - /// </summary> - public class UdpServer : IUdpServer - { - /// <summary> - /// Occurs when [message received]. - /// </summary> - public event EventHandler<UdpMessageReceivedEventArgs> MessageReceived; - - /// <summary> - /// Gets or sets the logger. - /// </summary> - /// <value>The logger.</value> - private ILogger Logger { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="UdpServer" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - public UdpServer(ILogger logger) - { - Logger = logger; - } - - /// <summary> - /// Raises the <see cref="E:MessageReceived" /> event. - /// </summary> - /// <param name="e">The <see cref="UdpMessageReceivedEventArgs" /> instance containing the event data.</param> - protected virtual void OnMessageReceived(UdpMessageReceivedEventArgs e) - { - EventHandler<UdpMessageReceivedEventArgs> handler = MessageReceived; - if (handler != null) handler(this, e); - } - - /// <summary> - /// The _udp client - /// </summary> - private UdpClient _udpClient; - - /// <summary> - /// Starts the specified port. - /// </summary> - /// <param name="port">The port.</param> - public void Start(int port) - { - _udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, port)); - - _udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true); - - CreateObservable().Subscribe(OnMessageReceived); - } - - /// <summary> - /// Creates the observable. - /// </summary> - /// <returns>IObservable{UdpReceiveResult}.</returns> - private IObservable<UdpReceiveResult> CreateObservable() - { - return Observable.Create<UdpReceiveResult>(obs => - Observable.FromAsync(() => - { - try - { - return _udpClient.ReceiveAsync(); - } - catch (ObjectDisposedException) - { - return Task.FromResult(new UdpReceiveResult(new byte[]{}, new IPEndPoint(IPAddress.Any, 0))); - } - catch (Exception ex) - { - Logger.ErrorException("Error receiving udp message", ex); - return Task.FromResult(new UdpReceiveResult(new byte[] { }, new IPEndPoint(IPAddress.Any, 0))); - } - }) - - .Subscribe(obs)) - .Repeat() - .Retry() - .Publish() - .RefCount(); - } - - /// <summary> - /// Called when [message received]. - /// </summary> - /// <param name="message">The message.</param> - private void OnMessageReceived(UdpReceiveResult message) - { - if (message.RemoteEndPoint.Port == 0) - { - return; - } - var bytes = message.Buffer; - - OnMessageReceived(new UdpMessageReceivedEventArgs - { - Bytes = bytes, - RemoteEndPoint = message.RemoteEndPoint.ToString() - }); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Stops this instance. - /// </summary> - public void Stop() - { - _udpClient.Close(); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - Stop(); - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="data">The data.</param> - /// <param name="ipAddress">The ip address.</param> - /// <param name="port">The port.</param> - /// <returns>Task{System.Int32}.</returns> - /// <exception cref="System.ArgumentNullException">data</exception> - public Task SendAsync(string data, string ipAddress, int port) - { - return SendAsync(Encoding.UTF8.GetBytes(data), ipAddress, port); - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="ipAddress">The ip address.</param> - /// <param name="port">The port.</param> - /// <returns>Task{System.Int32}.</returns> - /// <exception cref="System.ArgumentNullException">bytes</exception> - public Task SendAsync(byte[] bytes, string ipAddress, int port) - { - if (bytes == null) - { - throw new ArgumentNullException("bytes"); - } - - if (string.IsNullOrEmpty(ipAddress)) - { - throw new ArgumentNullException("ipAddress"); - } - - return _udpClient.SendAsync(bytes, bytes.Length, ipAddress, port); - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="remoteEndPoint">The remote end point.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, string remoteEndPoint) - { - if (bytes == null) - { - throw new ArgumentNullException("bytes"); - } - - if (string.IsNullOrEmpty(remoteEndPoint)) - { - throw new ArgumentNullException("remoteEndPoint"); - } - - return _udpClient.SendAsync(bytes, bytes.Length, new NetworkManager().Parse(remoteEndPoint)); - } - } - -} diff --git a/MediaBrowser.Networking/WebSocket/AlchemyServer.cs b/MediaBrowser.Networking/WebSocket/AlchemyServer.cs deleted file mode 100644 index b3d5d710ec..0000000000 --- a/MediaBrowser.Networking/WebSocket/AlchemyServer.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Alchemy; -using Alchemy.Classes; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Net; - -namespace MediaBrowser.Networking.WebSocket -{ - /// <summary> - /// Class AlchemyServer - /// </summary> - public class AlchemyServer : IWebSocketServer - { - /// <summary> - /// Occurs when [web socket connected]. - /// </summary> - public event EventHandler<WebSocketConnectEventArgs> WebSocketConnected; - - /// <summary> - /// Gets or sets the web socket server. - /// </summary> - /// <value>The web socket server.</value> - private WebSocketServer WebSocketServer { get; set; } - - /// <summary> - /// The _logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Initializes a new instance of the <see cref="AlchemyServer" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">logger</exception> - public AlchemyServer(ILogger logger) - { - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - _logger = logger; - } - - /// <summary> - /// Gets the port. - /// </summary> - /// <value>The port.</value> - public int Port { get; private set; } - - /// <summary> - /// Starts the specified port number. - /// </summary> - /// <param name="portNumber">The port number.</param> - public void Start(int portNumber) - { - WebSocketServer = new WebSocketServer(portNumber, IPAddress.Any) - { - OnConnected = OnAlchemyWebSocketClientConnected, - TimeOut = TimeSpan.FromMinutes(60) - }; - - WebSocketServer.Start(); - - Port = portNumber; - - _logger.Info("Alchemy Web Socket Server started"); - } - - /// <summary> - /// Called when [alchemy web socket client connected]. - /// </summary> - /// <param name="context">The context.</param> - private void OnAlchemyWebSocketClientConnected(UserContext context) - { - if (WebSocketConnected != null) - { - var socket = new AlchemyWebSocket(context, _logger); - - WebSocketConnected(this, new WebSocketConnectEventArgs - { - WebSocket = socket, - Endpoint = context.ClientAddress.ToString() - }); - } - } - - /// <summary> - /// Stops this instance. - /// </summary> - public void Stop() - { - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - - } - } -} diff --git a/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs b/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs deleted file mode 100644 index c8ab58ca40..0000000000 --- a/MediaBrowser.Networking/WebSocket/AlchemyWebSocket.cs +++ /dev/null @@ -1,132 +0,0 @@ -using Alchemy.Classes; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Logging; -using System; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Networking.WebSocket -{ - /// <summary> - /// Class AlchemyWebSocket - /// </summary> - public class AlchemyWebSocket : IWebSocket - { - /// <summary> - /// The logger - /// </summary> - private readonly ILogger _logger; - - /// <summary> - /// Gets or sets the web socket. - /// </summary> - /// <value>The web socket.</value> - private UserContext UserContext { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="AlchemyWebSocket" /> class. - /// </summary> - /// <param name="context">The context.</param> - /// <param name="logger">The logger.</param> - /// <exception cref="System.ArgumentNullException">context</exception> - public AlchemyWebSocket(UserContext context, ILogger logger) - { - if (context == null) - { - throw new ArgumentNullException("context"); - } - - _logger = logger; - UserContext = context; - - context.SetOnDisconnect(OnDisconnected); - context.SetOnReceive(OnReceive); - - _logger.Info("Client connected from {0}", context.ClientAddress); - } - - /// <summary> - /// The _disconnected - /// </summary> - private bool _disconnected = false; - /// <summary> - /// Gets or sets the state. - /// </summary> - /// <value>The state.</value> - public WebSocketState State - { - get { return _disconnected ? WebSocketState.Closed : WebSocketState.Open; } - } - - /// <summary> - /// Called when [disconnected]. - /// </summary> - /// <param name="context">The context.</param> - private void OnDisconnected(UserContext context) - { - _disconnected = true; - } - - /// <summary> - /// Called when [receive]. - /// </summary> - /// <param name="context">The context.</param> - private void OnReceive(UserContext context) - { - if (OnReceiveDelegate != null) - { - var json = context.DataFrame.ToString(); - - if (!string.IsNullOrWhiteSpace(json)) - { - try - { - var bytes = Encoding.UTF8.GetBytes(json); - - OnReceiveDelegate(bytes); - } - catch (Exception ex) - { - _logger.ErrorException("Error processing web socket message", ex); - } - } - } - } - - /// <summary> - /// Sends the async. - /// </summary> - /// <param name="bytes">The bytes.</param> - /// <param name="type">The type.</param> - /// <param name="endOfMessage">if set to <c>true</c> [end of message].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public Task SendAsync(byte[] bytes, WebSocketMessageType type, bool endOfMessage, CancellationToken cancellationToken) - { - return Task.Run(() => UserContext.Send(bytes)); - } - - /// <summary> - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// </summary> - public void Dispose() - { - Dispose(true); - } - - /// <summary> - /// Releases unmanaged and - optionally - managed resources. - /// </summary> - /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> - protected virtual void Dispose(bool dispose) - { - } - - /// <summary> - /// Gets or sets the receive action. - /// </summary> - /// <value>The receive action.</value> - public Action<byte[]> OnReceiveDelegate { get; set; } - } -} |
