fix duplicate connections on the dashboard

This commit is contained in:
LukePulverenti 2013-03-16 12:41:49 -04:00
parent 110ee00517
commit bae89ee824
13 changed files with 79 additions and 88 deletions

View File

@ -252,30 +252,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger.Info("HttpClientManager.GetTempFile url: {0}, temp file: {1}", options.Url, tempFile); _logger.Info("HttpClientManager.GetTempFile url: {0}, temp file: {1}", options.Url, tempFile);
FileStream tempFileStream;
if (resumeCount > 0 && File.Exists(tempFile))
{
tempFileStream = new FileStream(tempFile, FileMode.Open, FileAccess.Write, FileShare.Read,
StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
var startPosition = tempFileStream.Length;
tempFileStream.Seek(startPosition, SeekOrigin.Current);
message.Headers.Range = new RangeHeaderValue(startPosition, null);
_logger.Info("Resuming from position {1} for {0}", options.Url, startPosition);
}
else
{
tempFileStream = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read,
StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous);
}
var serverSupportsRangeRequests = false;
Exception downloadException = null;
try try
{ {
options.CancellationToken.ThrowIfCancellationRequested(); options.CancellationToken.ThrowIfCancellationRequested();
@ -286,15 +262,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested(); options.CancellationToken.ThrowIfCancellationRequested();
var rangeValue = string.Join(" ", response.Headers.AcceptRanges.ToArray());
serverSupportsRangeRequests = rangeValue.IndexOf("bytes", StringComparison.OrdinalIgnoreCase) != -1 || rangeValue.IndexOf("*", StringComparison.OrdinalIgnoreCase) != -1;
if (!serverSupportsRangeRequests && resumeCount > 0)
{
_logger.Info("Server does not support range requests for {0}", options.Url);
tempFileStream.Position = 0;
}
IEnumerable<string> lengthValues; IEnumerable<string> lengthValues;
if (!response.Headers.TryGetValues("content-length", out lengthValues) && if (!response.Headers.TryGetValues("content-length", out lengthValues) &&
@ -303,7 +270,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
// We're not able to track progress // We're not able to track progress
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
{ {
await stream.CopyToAsync(tempFileStream, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
}
} }
} }
else else
@ -312,7 +282,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, length)) using (var stream = ProgressStream.CreateReadProgressStream(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), options.Progress.Report, length))
{ {
await stream.CopyToAsync(tempFileStream, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false); using (var fs = new FileStream(tempFile, FileMode.Create, FileAccess.Write, FileShare.Read, StreamDefaults.DefaultFileStreamBufferSize, FileOptions.Asynchronous))
{
await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, options.CancellationToken).ConfigureAwait(false);
}
} }
} }
@ -323,23 +296,16 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
} }
catch (Exception ex) catch (Exception ex)
{ {
downloadException = ex; HandleTempFileException(ex, options, tempFile);
} }
finally finally
{ {
tempFileStream.Dispose();
if (options.ResourcePool != null) if (options.ResourcePool != null)
{ {
options.ResourcePool.Release(); options.ResourcePool.Release();
} }
} }
if (downloadException != null)
{
await HandleTempFileException(downloadException, options, tempFile, serverSupportsRangeRequests, resumeCount).ConfigureAwait(false);
}
return tempFile; return tempFile;
} }
@ -349,11 +315,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// <param name="ex">The ex.</param> /// <param name="ex">The ex.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
/// <param name="tempFile">The temp file.</param> /// <param name="tempFile">The temp file.</param>
/// <param name="serverSupportsRangeRequests">if set to <c>true</c> [server supports range requests].</param>
/// <param name="resumeCount">The resume count.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
/// <exception cref="HttpException"></exception> /// <exception cref="HttpException"></exception>
private Task HandleTempFileException(Exception ex, HttpRequestOptions options, string tempFile, bool serverSupportsRangeRequests, int resumeCount) private void HandleTempFileException(Exception ex, HttpRequestOptions options, string tempFile)
{ {
var operationCanceledException = ex as OperationCanceledException; var operationCanceledException = ex as OperationCanceledException;
@ -375,14 +339,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
// Cleanup // Cleanup
if (File.Exists(tempFile)) if (File.Exists(tempFile))
{ {
// Try to resume
if (httpRequestException != null && serverSupportsRangeRequests && resumeCount < options.MaxResumeCount && new FileInfo(tempFile).Length > 0)
{
_logger.Info("Attempting to resume download from {0}", options.Url);
return GetTempFile(options, tempFile, resumeCount + 1);
}
File.Delete(tempFile); File.Delete(tempFile);
} }

View File

@ -75,8 +75,7 @@ namespace MediaBrowser.Common.Implementations.Updates
{ {
Url = package.sourceUrl, Url = package.sourceUrl,
CancellationToken = cancellationToken, CancellationToken = cancellationToken,
Progress = progress, Progress = progress
MaxResumeCount = 3
}).ConfigureAwait(false); }).ConfigureAwait(false);

View File

@ -32,12 +32,6 @@ namespace MediaBrowser.Common.Net
/// <value>The user agent.</value> /// <value>The user agent.</value>
public string UserAgent { get; set; } public string UserAgent { get; set; }
/// <summary>
/// Gets or sets the max resume count.
/// </summary>
/// <value>The max resume count.</value>
public int MaxResumeCount { get; set; }
/// <summary> /// <summary>
/// Gets or sets the progress. /// Gets or sets the progress.
/// </summary> /// </summary>

View File

@ -64,6 +64,39 @@ namespace MediaBrowser.Controller.Drawing
return encoders.FirstOrDefault(i => i.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase)) ?? encoders.FirstOrDefault(); return encoders.FirstOrDefault(i => i.MimeType.Equals(mimeType, StringComparison.OrdinalIgnoreCase)) ?? encoders.FirstOrDefault();
} }
/// <summary>
/// Determines whether [is pixel format supported by graphics object] [the specified format].
/// </summary>
/// <param name="format">The format.</param>
/// <returns><c>true</c> if [is pixel format supported by graphics object] [the specified format]; otherwise, <c>false</c>.</returns>
public static bool IsPixelFormatSupportedByGraphicsObject(PixelFormat format)
{
// http://msdn.microsoft.com/en-us/library/system.drawing.graphics.fromimage.aspx
if (format.HasFlag(PixelFormat.Indexed))
{
return false;
}
if (format.HasFlag(PixelFormat.Undefined))
{
return false;
}
if (format.HasFlag(PixelFormat.DontCare))
{
return false;
}
if (format.HasFlag(PixelFormat.Format16bppArgb1555))
{
return false;
}
if (format.HasFlag(PixelFormat.Format16bppGrayScale))
{
return false;
}
return true;
}
/// <summary> /// <summary>
/// Crops an image by removing whitespace and transparency from the edges /// Crops an image by removing whitespace and transparency from the edges
/// </summary> /// </summary>

View File

@ -179,7 +179,7 @@ namespace MediaBrowser.Controller.Drawing
var newHeight = Convert.ToInt32(newSize.Height); var newHeight = Convert.ToInt32(newSize.Height);
// Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here // Graphics.FromImage will throw an exception if the PixelFormat is Indexed, so we need to handle that here
var thumbnail = originalImage.PixelFormat.HasFlag(PixelFormat.Indexed) ? new Bitmap(originalImage, newWidth, newHeight) : new Bitmap(newWidth, newHeight, originalImage.PixelFormat); var thumbnail = !ImageExtensions.IsPixelFormatSupportedByGraphicsObject(originalImage.PixelFormat) ? new Bitmap(originalImage, newWidth, newHeight) : new Bitmap(newWidth, newHeight, originalImage.PixelFormat);
// Preserve the original resolution // Preserve the original resolution
thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution); thumbnail.SetResolution(originalImage.HorizontalResolution, originalImage.VerticalResolution);

View File

@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.Library
/// Gets the active connections. /// Gets the active connections.
/// </summary> /// </summary>
/// <value>The active connections.</value> /// <value>The active connections.</value>
IEnumerable<ClientConnectionInfo> ConnectedUsers { get; } IEnumerable<ClientConnectionInfo> RecentConnections { get; }
/// <summary> /// <summary>
/// Occurs when [playback start]. /// Occurs when [playback start].

View File

@ -25,8 +25,8 @@ namespace MediaBrowser.Server.Implementations.Library
/// <summary> /// <summary>
/// The _active connections /// The _active connections
/// </summary> /// </summary>
private readonly ConcurrentBag<ClientConnectionInfo> _activeConnections = private readonly List<ClientConnectionInfo> _activeConnections =
new ConcurrentBag<ClientConnectionInfo>(); new List<ClientConnectionInfo>();
/// <summary> /// <summary>
/// The _users /// The _users
@ -67,7 +67,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// Gets all connections. /// Gets all connections.
/// </summary> /// </summary>
/// <value>All connections.</value> /// <value>All connections.</value>
private IEnumerable<ClientConnectionInfo> AllConnections public IEnumerable<ClientConnectionInfo> AllConnections
{ {
get { return _activeConnections.Where(c => GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); } get { return _activeConnections.Where(c => GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); }
} }
@ -76,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.Library
/// Gets the active connections. /// Gets the active connections.
/// </summary> /// </summary>
/// <value>The active connections.</value> /// <value>The active connections.</value>
public IEnumerable<ClientConnectionInfo> ConnectedUsers public IEnumerable<ClientConnectionInfo> RecentConnections
{ {
get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 10); } get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 10); }
} }
@ -303,22 +303,29 @@ namespace MediaBrowser.Server.Implementations.Library
/// <returns>ClientConnectionInfo.</returns> /// <returns>ClientConnectionInfo.</returns>
private ClientConnectionInfo GetConnection(Guid userId, ClientType clientType, string deviceId, string deviceName) private ClientConnectionInfo GetConnection(Guid userId, ClientType clientType, string deviceId, string deviceName)
{ {
var conn = _activeConnections.FirstOrDefault(c => c.UserId == userId && c.ClientType == clientType && string.Equals(deviceId, c.DeviceId)); lock (_activeConnections)
if (conn == null)
{ {
conn = new ClientConnectionInfo var conn = _activeConnections.FirstOrDefault(c => c.ClientType == clientType && string.Equals(deviceId, c.DeviceId));
if (conn == null)
{ {
UserId = userId, conn = new ClientConnectionInfo
ClientType = clientType, {
DeviceName = deviceName, UserId = userId,
DeviceId = deviceId ClientType = clientType,
}; DeviceName = deviceName,
DeviceId = deviceId
};
_activeConnections.Add(conn); _activeConnections.Add(conn);
}
else
{
conn.UserId = userId;
}
return conn;
} }
return conn;
} }
/// <summary> /// <summary>

View File

@ -375,8 +375,10 @@ namespace MediaBrowser.Server.Implementations.Updates
throw; throw;
} }
catch catch (Exception ex)
{ {
_logger.ErrorException("Package installation failed", ex);
lock (CurrentInstallations) lock (CurrentInstallations)
{ {
CurrentInstallations.Remove(tuple); CurrentInstallations.Remove(tuple);

View File

@ -125,7 +125,7 @@ namespace MediaBrowser.WebDashboard.Api
/// <returns>DashboardInfo.</returns> /// <returns>DashboardInfo.</returns>
public static async Task<DashboardInfo> GetDashboardInfo(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager) public static async Task<DashboardInfo> GetDashboardInfo(IServerApplicationHost appHost, ILogger logger, ITaskManager taskManager, IUserManager userManager, ILibraryManager libraryManager)
{ {
var connections = userManager.ConnectedUsers.ToArray(); var connections = userManager.RecentConnections.ToArray();
var dtoBuilder = new DtoBuilder(logger, libraryManager); var dtoBuilder = new DtoBuilder(logger, libraryManager);

View File

@ -1387,7 +1387,7 @@ $(document).ajaxSend(function (event, jqXHR) {
if (ApiClient.currentUserId) { if (ApiClient.currentUserId) {
var auth = 'MediaBrowser UserId="' + ApiClient.currentUserId + '", Client="Dashboard", Device="' + ApiClient.getDeviceName() + '", DeviceId="' + ApiClient.getDeviceName() + '"'; var auth = 'MediaBrowser UserId="' + ApiClient.currentUserId + '", Client="Dashboard", Device="' + ApiClient.getDeviceName() + '", DeviceId="' + ApiClient.getDeviceId() + '"';
jqXHR.setRequestHeader("Authorization", auth); jqXHR.setRequestHeader("Authorization", auth);
} }
}); });

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata> <metadata>
<id>MediaBrowser.Common.Internal</id> <id>MediaBrowser.Common.Internal</id>
<version>3.0.48</version> <version>3.0.49</version>
<title>MediaBrowser.Common.Internal</title> <title>MediaBrowser.Common.Internal</title>
<authors>Luke</authors> <authors>Luke</authors>
<owners>ebr,Luke,scottisafool</owners> <owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description> <description>Contains common components shared by Media Browser Theatre and Media Browser Server. Not intended for plugin developer consumption.</description>
<copyright>Copyright © Media Browser 2013</copyright> <copyright>Copyright © Media Browser 2013</copyright>
<dependencies> <dependencies>
<dependency id="MediaBrowser.Common" version="3.0.48" /> <dependency id="MediaBrowser.Common" version="3.0.49" />
<dependency id="NLog" version="2.0.0.2000" /> <dependency id="NLog" version="2.0.0.2000" />
<dependency id="ServiceStack.Text" version="3.9.38" /> <dependency id="ServiceStack.Text" version="3.9.38" />
<dependency id="protobuf-net" version="2.0.0.621" /> <dependency id="protobuf-net" version="2.0.0.621" />

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>MediaBrowser.Common</id> <id>MediaBrowser.Common</id>
<version>3.0.48</version> <version>3.0.49</version>
<title>MediaBrowser.Common</title> <title>MediaBrowser.Common</title>
<authors>Media Browser Team</authors> <authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners> <owners>ebr,Luke,scottisafool</owners>

View File

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata> <metadata>
<id>MediaBrowser.Server.Core</id> <id>MediaBrowser.Server.Core</id>
<version>3.0.48</version> <version>3.0.49</version>
<title>Media Browser.Server.Core</title> <title>Media Browser.Server.Core</title>
<authors>Media Browser Team</authors> <authors>Media Browser Team</authors>
<owners>ebr,Luke,scottisafool</owners> <owners>ebr,Luke,scottisafool</owners>
@ -12,7 +12,7 @@
<description>Contains core components required to build plugins for Media Browser Server.</description> <description>Contains core components required to build plugins for Media Browser Server.</description>
<copyright>Copyright © Media Browser 2013</copyright> <copyright>Copyright © Media Browser 2013</copyright>
<dependencies> <dependencies>
<dependency id="MediaBrowser.Common" version="3.0.48" /> <dependency id="MediaBrowser.Common" version="3.0.49" />
</dependencies> </dependencies>
</metadata> </metadata>
<files> <files>