From a660aa001eb31e91d040e066787fa764cf5f0fb4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 12 Mar 2017 15:27:26 -0400 Subject: re-organize file streaming --- .../HttpServer/FileWriter.cs | 188 +++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 Emby.Server.Implementations/HttpServer/FileWriter.cs (limited to 'Emby.Server.Implementations/HttpServer/FileWriter.cs') diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs new file mode 100644 index 000000000..b80a40962 --- /dev/null +++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Net; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Services; + +namespace Emby.Server.Implementations.HttpServer +{ + public class FileWriter : IHttpResult + { + private ILogger Logger { get; set; } + + private string RangeHeader { get; set; } + private bool IsHeadRequest { get; set; } + + private long RangeStart { get; set; } + private long RangeEnd { get; set; } + private long RangeLength { get; set; } + private long TotalContentLength { get; set; } + + public Action OnComplete { get; set; } + public Action OnError { get; set; } + private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); + public List Cookies { get; private set; } + + /// + /// The _options + /// + private readonly IDictionary _options = new Dictionary(); + /// + /// Gets the options. + /// + /// The options. + public IDictionary Headers + { + get { return _options; } + } + + public string Path { get; set; } + + public FileWriter(string path, string contentType, string rangeHeader, ILogger logger, IFileSystem fileSystem) + { + if (string.IsNullOrEmpty(contentType)) + { + throw new ArgumentNullException("contentType"); + } + + Path = path; + Logger = logger; + RangeHeader = rangeHeader; + + Headers["Content-Type"] = contentType; + + TotalContentLength = fileSystem.GetFileInfo(path).Length; + + if (string.IsNullOrWhiteSpace(rangeHeader)) + { + Headers["Content-Length"] = TotalContentLength.ToString(UsCulture); + StatusCode = HttpStatusCode.OK; + } + else + { + Headers["Accept-Ranges"] = "bytes"; + StatusCode = HttpStatusCode.PartialContent; + SetRangeValues(); + } + + Cookies = new List(); + } + + /// + /// Sets the range values. + /// + private void SetRangeValues() + { + var requestedRange = RequestedRanges[0]; + + // If the requested range is "0-", we can optimize by just doing a stream copy + if (!requestedRange.Value.HasValue) + { + RangeEnd = TotalContentLength - 1; + } + else + { + RangeEnd = requestedRange.Value.Value; + } + + RangeStart = requestedRange.Key; + RangeLength = 1 + RangeEnd - RangeStart; + + // Content-Length is the length of what we're serving, not the original content + Headers["Content-Length"] = RangeLength.ToString(UsCulture); + Headers["Content-Range"] = string.Format("bytes {0}-{1}/{2}", RangeStart, RangeEnd, TotalContentLength); + } + + /// + /// The _requested ranges + /// + private List> _requestedRanges; + /// + /// Gets the requested ranges. + /// + /// The requested ranges. + protected List> RequestedRanges + { + get + { + if (_requestedRanges == null) + { + _requestedRanges = new List>(); + + // Example: bytes=0-,32-63 + var ranges = RangeHeader.Split('=')[1].Split(','); + + foreach (var range in ranges) + { + var vals = range.Split('-'); + + long start = 0; + long? end = null; + + if (!string.IsNullOrEmpty(vals[0])) + { + start = long.Parse(vals[0], UsCulture); + } + if (!string.IsNullOrEmpty(vals[1])) + { + end = long.Parse(vals[1], UsCulture); + } + + _requestedRanges.Add(new KeyValuePair(start, end)); + } + } + + return _requestedRanges; + } + } + + public async Task WriteToAsync(IResponse response, CancellationToken cancellationToken) + { + try + { + // Headers only + if (IsHeadRequest) + { + return; + } + + if (string.IsNullOrWhiteSpace(RangeHeader) || (RangeStart <= 0 && RangeEnd >= TotalContentLength - 1)) + { + Logger.Info("Transmit file {0}", Path); + await response.TransmitFile(Path, 0, 0, cancellationToken).ConfigureAwait(false); + return; + } + + await response.TransmitFile(Path, RangeStart, RangeEnd, cancellationToken).ConfigureAwait(false); + } + finally + { + if (OnComplete != null) + { + OnComplete(); + } + } + } + + public string ContentType { get; set; } + + public IRequest RequestContext { get; set; } + + public object Response { get; set; } + + public int Status { get; set; } + + public HttpStatusCode StatusCode + { + get { return (HttpStatusCode)Status; } + set { Status = (int)value; } + } + + public string StatusDescription { get; set; } + + } +} -- cgit v1.2.3 From b38b7a706268fe5d92d8cbe703a188b58ed7ec4d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 13 Mar 2017 00:08:23 -0400 Subject: rework filestream --- Emby.Common.Implementations/Net/NetAcceptSocket.cs | 2 +- Emby.Common.Implementations/Net/SocketFactory.cs | 27 +++++++++++++++++++--- .../HttpServer/FileWriter.cs | 7 ++++-- .../HttpServer/HttpResultFactory.cs | 5 ++-- .../SocketSharp/WebSocketSharpResponse.cs | 4 ++-- .../Library/LibraryManager.cs | 27 ++++++++++++++-------- MediaBrowser.Api/StartupWizardService.cs | 1 + .../Entities/Audio/MusicArtist.cs | 7 +++++- .../Entities/Audio/MusicGenre.cs | 7 +++++- MediaBrowser.Controller/Entities/GameGenre.cs | 7 +++++- MediaBrowser.Controller/Entities/Genre.cs | 7 +++++- MediaBrowser.Controller/Entities/Person.cs | 7 +++++- MediaBrowser.Controller/Entities/Studio.cs | 7 +++++- MediaBrowser.Controller/Entities/Year.cs | 7 +++++- MediaBrowser.Controller/LiveTv/ITunerHost.cs | 2 ++ .../Configuration/ServerConfiguration.cs | 1 + MediaBrowser.Model/Net/ISocketFactory.cs | 2 ++ MediaBrowser.Model/Services/IRequest.cs | 3 ++- .../Net/HttpListenerResponse.cs | 4 ++-- SocketHttpListener.Portable/Net/ResponseStream.cs | 8 +++---- 20 files changed, 108 insertions(+), 34 deletions(-) (limited to 'Emby.Server.Implementations/HttpServer/FileWriter.cs') diff --git a/Emby.Common.Implementations/Net/NetAcceptSocket.cs b/Emby.Common.Implementations/Net/NetAcceptSocket.cs index e21ffe553..3721709e6 100644 --- a/Emby.Common.Implementations/Net/NetAcceptSocket.cs +++ b/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(); diff --git a/Emby.Common.Implementations/Net/SocketFactory.cs b/Emby.Common.Implementations/Net/SocketFactory.cs index 021613e57..0f4306a6b 100644 --- a/Emby.Common.Implementations/Net/SocketFactory.cs +++ b/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; + } + } + /// - /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port. - /// - /// An implementation of the interface used by RSSDP components to perform acceptSocket operations. + /// Creates a new UDP acceptSocket that is a member of the SSDP multicast local admin group and binds it to the specified local port. + /// + /// An implementation of the interface used by RSSDP components to perform acceptSocket operations. public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort) { if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", "localPort"); diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs index b80a40962..d230a9b91 100644 --- a/Emby.Server.Implementations/HttpServer/FileWriter.cs +++ b/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 Cookies { get; private set; } + public FileShareMode FileShare { get; set; } + /// /// The _options /// @@ -69,6 +71,7 @@ namespace Emby.Server.Implementations.HttpServer SetRangeValues(); } + FileShare = FileShareMode.Read; Cookies = new List(); } @@ -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 { diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index e3f105941..310161d41 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/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 }; } diff --git a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs b/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs index a497ee715..fd30b227f 100644 --- a/Emby.Server.Implementations/HttpServer/SocketSharp/WebSocketSharpResponse.cs +++ b/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); } } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index f7706db47..026486efc 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/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 /// Task{Person}. public Person GetPerson(string name) { - return CreateItemByName(Person.GetPath(name), name); + return CreateItemByName(Person.GetPath, name); } /// @@ -875,7 +880,7 @@ namespace Emby.Server.Implementations.Library /// Task{Studio}. public Studio GetStudio(string name) { - return CreateItemByName(Studio.GetPath(name), name); + return CreateItemByName(Studio.GetPath, name); } /// @@ -885,7 +890,7 @@ namespace Emby.Server.Implementations.Library /// Task{Genre}. public Genre GetGenre(string name) { - return CreateItemByName(Genre.GetPath(name), name); + return CreateItemByName(Genre.GetPath, name); } /// @@ -895,7 +900,7 @@ namespace Emby.Server.Implementations.Library /// Task{MusicGenre}. public MusicGenre GetMusicGenre(string name) { - return CreateItemByName(MusicGenre.GetPath(name), name); + return CreateItemByName(MusicGenre.GetPath, name); } /// @@ -905,7 +910,7 @@ namespace Emby.Server.Implementations.Library /// Task{GameGenre}. public GameGenre GetGameGenre(string name) { - return CreateItemByName(GameGenre.GetPath(name), name); + return CreateItemByName(GameGenre.GetPath, name); } /// @@ -923,7 +928,7 @@ namespace Emby.Server.Implementations.Library var name = value.ToString(CultureInfo.InvariantCulture); - return CreateItemByName(Year.GetPath(name), name); + return CreateItemByName(Year.GetPath, name); } /// @@ -933,10 +938,10 @@ namespace Emby.Server.Implementations.Library /// Task{Genre}. public MusicArtist GetArtist(string name) { - return CreateItemByName(MusicArtist.GetPath(name), name); + return CreateItemByName(MusicArtist.GetPath, name); } - private T CreateItemByName(string path, string name) + private T CreateItemByName(Func 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; diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index e010f122c..02154b98d 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/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) diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 20b2529c0..8d83f8a35 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 74679b474..e26e0dfce 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 22a8675c5..4187167b9 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index 1b746ae51..9769efdd0 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index ee1aea938..b68681d36 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index b8ad691a9..2e5e6ce43 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index 75fb69435..b352950a0 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/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 ? diff --git a/MediaBrowser.Controller/LiveTv/ITunerHost.cs b/MediaBrowser.Controller/LiveTv/ITunerHost.cs index 5615649c2..af1c0d12e 100644 --- a/MediaBrowser.Controller/LiveTv/ITunerHost.cs +++ b/MediaBrowser.Controller/LiveTv/ITunerHost.cs @@ -44,6 +44,8 @@ namespace MediaBrowser.Controller.LiveTv /// The cancellation token. /// Task<List<MediaSourceInfo>>. Task> GetChannelStreamMediaSources(string channelId, CancellationToken cancellationToken); + + Task> DiscoverDevices(int discoveryDurationMs); } public interface IConfigurableTunerHost { diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index c2b1e3c89..0562d0ac5 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/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; } /// /// Gets or sets the value pointing to the file system where the ssl certiifcate is located.. diff --git a/MediaBrowser.Model/Net/ISocketFactory.cs b/MediaBrowser.Model/Net/ISocketFactory.cs index 4b70f3362..e7dbf6cb1 100644 --- a/MediaBrowser.Model/Net/ISocketFactory.cs +++ b/MediaBrowser.Model/Net/ISocketFactory.cs @@ -14,6 +14,8 @@ namespace MediaBrowser.Model.Net /// A implementation. ISocket CreateUdpSocket(int localPort); + ISocket CreateUdpBroadcastSocket(int localPort); + ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort); /// diff --git a/MediaBrowser.Model/Services/IRequest.cs b/MediaBrowser.Model/Services/IRequest.cs index 40cef4ec0..115ba25ce 100644 --- a/MediaBrowser.Model/Services/IRequest.cs +++ b/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 Items { get; } - Task TransmitFile(string path, long offset, long count, CancellationToken cancellationToken); + Task TransmitFile(string path, long offset, long count, FileShareMode fileShareMode, CancellationToken cancellationToken); } } diff --git a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs b/SocketHttpListener.Portable/Net/HttpListenerResponse.cs index d8011f05e..d9f91c0cc 100644 --- a/SocketHttpListener.Portable/Net/HttpListenerResponse.cs +++ b/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); } } } \ No newline at end of file diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs index ccc0efc55..19821f954 100644 --- a/SocketHttpListener.Portable/Net/ResponseStream.cs +++ b/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) { -- cgit v1.2.3 From f1b1458ee8b94a5c75ed009581f5e9cb22ba70b7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 20 Mar 2017 13:56:44 -0400 Subject: 3.2.8.6 --- Emby.Server.Implementations/HttpServer/FileWriter.cs | 2 +- SharedVersion.cs | 2 +- SocketHttpListener.Portable/Net/ResponseStream.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/HttpServer/FileWriter.cs') diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs index d230a9b91..dbaf97b1e 100644 --- a/Emby.Server.Implementations/HttpServer/FileWriter.cs +++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs @@ -160,7 +160,7 @@ namespace Emby.Server.Implementations.HttpServer return; } - await response.TransmitFile(Path, RangeStart, RangeEnd, FileShare, cancellationToken).ConfigureAwait(false); + await response.TransmitFile(Path, RangeStart, RangeLength, FileShare, cancellationToken).ConfigureAwait(false); } finally { diff --git a/SharedVersion.cs b/SharedVersion.cs index cae8e0a25..6582f8f0f 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,3 +1,3 @@ using System.Reflection; -[assembly: AssemblyVersion("3.2.8.5")] +[assembly: AssemblyVersion("3.2.8.6")] diff --git a/SocketHttpListener.Portable/Net/ResponseStream.cs b/SocketHttpListener.Portable/Net/ResponseStream.cs index 19821f954..3c79f47c2 100644 --- a/SocketHttpListener.Portable/Net/ResponseStream.cs +++ b/SocketHttpListener.Portable/Net/ResponseStream.cs @@ -363,7 +363,7 @@ namespace SocketHttpListener.Net } } - private async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) + private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) { var array = new byte[81920]; int count; -- cgit v1.2.3