浏览代码

rework filestream

Luke Pulverenti 8 年之前
父节点
当前提交
b38b7a7062

+ 1 - 1
Emby.Common.Implementations/Net/NetAcceptSocket.cs

@@ -100,7 +100,7 @@ namespace Emby.Common.Implementations.Net
 #if NET46
         public Task SendFile(string path, byte[] preBuffer, byte[] postBuffer, CancellationToken cancellationToken)
         {
-            var options = TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket | TransmitFileOptions.UseKernelApc;
+            var options = TransmitFileOptions.UseKernelApc;
 
             var completionSource = new TaskCompletionSource<bool>();
 

+ 24 - 3
Emby.Common.Implementations/Net/SocketFactory.cs

@@ -97,10 +97,31 @@ namespace Emby.Common.Implementations.Net
             }
         }
 
+        public ISocket CreateUdpBroadcastSocket(int localPort)
+        {
+            if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");
+
+            var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
+            try
+            {
+                retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+                retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
+
+                return new UdpSocket(retVal, localPort, IPAddress.Any);
+            }
+            catch
+            {
+                if (retVal != null)
+                    retVal.Dispose();
+
+                throw;
+            }
+        }
+        
         /// <summary>
-        /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
-        /// </summary>
-        /// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
+              /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port.
+              /// </summary>
+              /// <returns>An implementation of the <see cref="ISocket"/> interface used by RSSDP components to perform acceptSocket operations.</returns>
         public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort)
         {
             if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort");

+ 5 - 2
Emby.Server.Implementations/HttpServer/FileWriter.cs

@@ -27,6 +27,8 @@ namespace Emby.Server.Implementations.HttpServer
         private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
         public List<Cookie> Cookies { get; private set; }
 
+        public FileShareMode FileShare { get; set; }
+
         /// <summary>
         /// The _options
         /// </summary>
@@ -69,6 +71,7 @@ namespace Emby.Server.Implementations.HttpServer
                 SetRangeValues();
             }
 
+            FileShare = FileShareMode.Read;
             Cookies = new List<Cookie>();
         }
 
@@ -153,11 +156,11 @@ namespace Emby.Server.Implementations.HttpServer
                 if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1))
                 {
                     Logger.Info("Transmit file {0}", Path);
-                    await response.TransmitFile(Path, 0, 0, cancellationToken).ConfigureAwait(false);
+                    await response.TransmitFile(Path, 0, 0, FileShare, cancellationToken).ConfigureAwait(false);
                     return;
                 }
 
-                await response.TransmitFile(Path, RangeStart, RangeEnd, cancellationToken).ConfigureAwait(false);
+                await response.TransmitFile(Path, RangeStart, RangeEnd, FileShare, cancellationToken).ConfigureAwait(false);
             }
             finally
             {

+ 3 - 2
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -556,12 +556,13 @@ namespace Emby.Server.Implementations.HttpServer
             {
                 var rangeHeader = requestContext.Headers.Get("Range");
 
-                if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path) && options.FileShare == FileShareMode.Read)
+                if (!isHeadRequest && !string.IsNullOrWhiteSpace(options.Path))
                 {
                     return new FileWriter(options.Path, contentType, rangeHeader, _logger, _fileSystem)
                     {
                         OnComplete = options.OnComplete,
-                        OnError = options.OnError
+                        OnError = options.OnError,
+                        FileShare = options.FileShare
                     };
                 }
 

+ 2 - 2
Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs

@@ -193,9 +193,9 @@ namespace Emby.Server.Implementations.HttpServer.SocketSharp
         {
         }
 
-        public Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken)
+        public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
         {
-            return _response.TransmitFile(path, offset, count, cancellationToken);
+            return _response.TransmitFile(path, offset, count, fileShareMode, cancellationToken);
         }
     }
 }

+ 17 - 10
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -513,6 +513,11 @@ namespace Emby.Server.Implementations.Library
         }
 
         public Guid GetNewItemId(string key, Type type)
+        {
+            return GetNewItemIdInternal(key, type, false);
+        }
+
+        private Guid GetNewItemIdInternal(string key, Type type, bool forceCaseInsensitive)
         {
             if (string.IsNullOrWhiteSpace(key))
             {
@@ -531,7 +536,7 @@ namespace Emby.Server.Implementations.Library
                     .Replace("/", "\\");
             }
 
-            if (!ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
+            if (forceCaseInsensitive || !ConfigurationManager.Configuration.EnableCaseSensitiveItemIds)
             {
                 key = key.ToLower();
             }
@@ -865,7 +870,7 @@ namespace Emby.Server.Implementations.Library
         /// <returns>Task{Person}.</returns>
         public Person GetPerson(string name)
         {
-            return CreateItemByName<Person>(Person.GetPath(name), name);
+            return CreateItemByName<Person>(Person.GetPath, name);
         }
 
         /// <summary>
@@ -875,7 +880,7 @@ namespace Emby.Server.Implementations.Library
         /// <returns>Task{Studio}.</returns>
         public Studio GetStudio(string name)
         {
-            return CreateItemByName<Studio>(Studio.GetPath(name), name);
+            return CreateItemByName<Studio>(Studio.GetPath, name);
         }
 
         /// <summary>
@@ -885,7 +890,7 @@ namespace Emby.Server.Implementations.Library
         /// <returns>Task{Genre}.</returns>
         public Genre GetGenre(string name)
         {
-            return CreateItemByName<Genre>(Genre.GetPath(name), name);
+            return CreateItemByName<Genre>(Genre.GetPath, name);
         }
 
         /// <summary>
@@ -895,7 +900,7 @@ namespace Emby.Server.Implementations.Library
         /// <returns>Task{MusicGenre}.</returns>
         public MusicGenre GetMusicGenre(string name)
         {
-            return CreateItemByName<MusicGenre>(MusicGenre.GetPath(name), name);
+            return CreateItemByName<MusicGenre>(MusicGenre.GetPath, name);
         }
 
         /// <summary>
@@ -905,7 +910,7 @@ namespace Emby.Server.Implementations.Library
         /// <returns>Task{GameGenre}.</returns>
         public GameGenre GetGameGenre(string name)
         {
-            return CreateItemByName<GameGenre>(GameGenre.GetPath(name), name);
+            return CreateItemByName<GameGenre>(GameGenre.GetPath, name);
         }
 
         /// <summary>
@@ -923,7 +928,7 @@ namespace Emby.Server.Implementations.Library
 
             var name = value.ToString(CultureInfo.InvariantCulture);
 
-            return CreateItemByName<Year>(Year.GetPath(name), name);
+            return CreateItemByName<Year>(Year.GetPath, name);
         }
 
         /// <summary>
@@ -933,10 +938,10 @@ namespace Emby.Server.Implementations.Library
         /// <returns>Task{Genre}.</returns>
         public MusicArtist GetArtist(string name)
         {
-            return CreateItemByName<MusicArtist>(MusicArtist.GetPath(name), name);
+            return CreateItemByName<MusicArtist>(MusicArtist.GetPath, name);
         }
 
-        private T CreateItemByName<T>(string path, string name)
+        private T CreateItemByName<T>(Func<string,string> getPathFn, string name)
             where T : BaseItem, new()
         {
             if (typeof(T) == typeof(MusicArtist))
@@ -957,7 +962,9 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            var id = GetNewItemId(path, typeof(T));
+            var path = getPathFn(name);
+            var forceCaseInsensitiveId = ConfigurationManager.Configuration.EnableNormalizedItemByNameIds;
+            var id = GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
 
             var item = GetItemById(id) as T;
 

+ 1 - 0
MediaBrowser.Api/StartupWizardService.cs

@@ -120,6 +120,7 @@ namespace MediaBrowser.Api
             config.EnableSeriesPresentationUniqueKey = true;
             config.EnableLocalizedGuids = true;
             config.EnableSimpleArtistDetection = true;
+            config.EnableNormalizedItemByNameIds = true;
         }
 
         public void Post(UpdateStartupConfiguration request)

+ 6 - 1
MediaBrowser.Controller/Entities/Audio/MusicArtist.cs

@@ -289,7 +289,12 @@ namespace MediaBrowser.Controller.Entities.Audio
             }
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validName = normalizeName ?

+ 6 - 1
MediaBrowser.Controller/Entities/Audio/MusicGenre.cs

@@ -118,7 +118,12 @@ namespace MediaBrowser.Controller.Entities.Audio
             return LibraryManager.GetItemList(query);
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validName = normalizeName ?

+ 6 - 1
MediaBrowser.Controller/Entities/GameGenre.cs

@@ -96,7 +96,12 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validName = normalizeName ?

+ 6 - 1
MediaBrowser.Controller/Entities/Genre.cs

@@ -108,7 +108,12 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validName = normalizeName ?

+ 6 - 1
MediaBrowser.Controller/Entities/Person.cs

@@ -133,7 +133,12 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validFilename = normalizeName ?

+ 6 - 1
MediaBrowser.Controller/Entities/Studio.cs

@@ -114,7 +114,12 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validName = normalizeName ?

+ 6 - 1
MediaBrowser.Controller/Entities/Year.cs

@@ -122,7 +122,12 @@ namespace MediaBrowser.Controller.Entities
             }
         }
 
-        public static string GetPath(string name, bool normalizeName = true)
+        public static string GetPath(string name)
+        {
+            return GetPath(name, true);
+        }
+
+        public static string GetPath(string name, bool normalizeName)
         {
             // Trim the period at the end because windows will have a hard time with that
             var validName = normalizeName ?

+ 2 - 0
MediaBrowser.Controller/LiveTv/ITunerHost.cs

@@ -44,6 +44,8 @@ namespace MediaBrowser.Controller.LiveTv
         /// <param name="cancellationToken">The cancellation token.</param>
         /// <returns>Task&lt;List&lt;MediaSourceInfo&gt;&gt;.</returns>
         Task<List<MediaSourceInfo>> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken);
+
+        Task<List<TunerHostInfo>> DiscoverDevices(int discoveryDurationMs);
     }
     public interface IConfigurableTunerHost
     {

+ 1 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -48,6 +48,7 @@ namespace MediaBrowser.Model.Configuration
         public bool EnableHttps { get; set; }
         public bool EnableSeriesPresentationUniqueKey { get; set; }
         public bool EnableLocalizedGuids { get; set; }
+        public bool EnableNormalizedItemByNameIds { get; set; }
 
         /// <summary>
         /// Gets or sets the value pointing to the file system where the ssl certiifcate is located..

+ 2 - 0
MediaBrowser.Model/Net/ISocketFactory.cs

@@ -14,6 +14,8 @@ namespace MediaBrowser.Model.Net
 		/// <returns>A <see cref="ISocket"/> implementation.</returns>
 		ISocket CreateUdpSocket(int localPort);
 
+        ISocket CreateUdpBroadcastSocket(int localPort);
+
         ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort);
 
         /// <summary>

+ 2 - 1
MediaBrowser.Model/Services/IRequest.cs

@@ -4,6 +4,7 @@ using System.IO;
 using System.Net;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.IO;
 
 namespace MediaBrowser.Model.Services
 {
@@ -154,6 +155,6 @@ namespace MediaBrowser.Model.Services
         //Add Metadata to Response
         Dictionary<string, object> Items { get; }
 
-        Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken);
+        Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken);
     }
 }

+ 2 - 2
SocketHttpListener.Portable/Net/HttpListenerResponse.cs

@@ -515,9 +515,9 @@ namespace SocketHttpListener.Net
             cookies.Add(cookie);
         }
 
-        public Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken)
+        public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
         {
-            return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, cancellationToken);
+            return ((ResponseStream)OutputStream).TransmitFile(path, offset, count, fileShareMode, cancellationToken);
         }
     }
 }

+ 4 - 4
SocketHttpListener.Portable/Net/ResponseStream.cs

@@ -307,13 +307,13 @@ namespace SocketHttpListener.Net
             throw new NotSupportedException();
         }
 
-        public Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken)
+        public Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
         {
             //if (_supportsDirectSocketAccess && offset == 0 && count == 0 && !response.SendChunked)
             //{
             //    return TransmitFileOverSocket(path, offset, count, cancellationToken);
             //}
-            return TransmitFileManaged(path, offset, count, cancellationToken);
+            return TransmitFileManaged(path, offset, count, fileShareMode, cancellationToken);
         }
 
         private readonly byte[] _emptyBuffer = new byte[] { };
@@ -334,7 +334,7 @@ namespace SocketHttpListener.Net
             await _socket.SendFile(path, buffer, _emptyBuffer, cancellationToken).ConfigureAwait(false);
         }
 
-        private async Task TransmitFileManaged(string path, long offset, long count, CancellationToken cancellationToken)
+        private async Task TransmitFileManaged(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken)
         {
             var chunked = response.SendChunked;
 
@@ -343,7 +343,7 @@ namespace SocketHttpListener.Net
                 await WriteAsync(_emptyBuffer, 0, 0, cancellationToken).ConfigureAwait(false);
             }
 
-            using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read, true))
+            using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, fileShareMode, true))
             {
                 if (offset > 0)
                 {