From a5b82cd2ec9b03e949ab79791dc6c0469390c085 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 3 Oct 2017 14:39:37 -0400 Subject: remove unneeded async signatures --- .../Channels/ChannelManager.cs | 32 ++++------ .../Collections/CollectionManager.cs | 4 +- Emby.Server.Implementations/IO/FileRefresher.cs | 17 ++---- .../Library/LibraryManager.cs | 19 +++--- .../Library/LocalTrailerPostScanTask.cs | 7 +-- .../Library/Resolvers/Movies/MovieResolver.cs | 2 +- .../Library/UserViewManager.cs | 10 ++-- .../LiveTv/LiveTvManager.cs | 69 ++++++++++------------ .../Playlists/PlaylistManager.cs | 6 +- 9 files changed, 71 insertions(+), 95 deletions(-) (limited to 'Emby.Server.Implementations') diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs index d3950929d4..0036d19708 100644 --- a/Emby.Server.Implementations/Channels/ChannelManager.cs +++ b/Emby.Server.Implementations/Channels/ChannelManager.cs @@ -373,7 +373,7 @@ namespace Emby.Server.Implementations.Channels private async Task GetChannel(IChannel channelInfo, CancellationToken cancellationToken) { - var parentFolder = await GetInternalChannelFolder(cancellationToken).ConfigureAwait(false); + var parentFolder = GetInternalChannelFolder(cancellationToken); var parentFolderId = parentFolder.Id; var id = GetInternalChannelId(channelInfo.Name); @@ -434,7 +434,7 @@ namespace Emby.Server.Implementations.Channels } else if (forceUpdate) { - await item.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.None, cancellationToken); } await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem), cancellationToken); @@ -655,14 +655,12 @@ namespace Emby.Server.Implementations.Channels // Avoid implicitly captured closure var token = cancellationToken; - var itemTasks = items.Select(i => + var internalItems = items.Select(i => { var channelProvider = i.Item1; var internalChannelId = GetInternalChannelId(channelProvider.Name); return GetChannelItemEntity(i.Item2, channelProvider, internalChannelId, token); - }); - - var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false); + }).ToArray(); internalItems = ApplyFilters(internalItems, query.Filters, user).ToArray(); RefreshIfNeeded(internalItems); @@ -802,14 +800,12 @@ namespace Emby.Server.Implementations.Channels // Avoid implicitly captured closure var token = cancellationToken; - var itemTasks = items.Select(i => + var internalItems = items.Select(i => { var channelProvider = i.Item1; var internalChannelId = GetInternalChannelId(channelProvider.Name); return GetChannelItemEntity(i.Item2, channelProvider, internalChannelId, token); - }); - - var internalItems = await Task.WhenAll(itemTasks).ConfigureAwait(false); + }).ToArray(); return new QueryResult { @@ -955,9 +951,7 @@ namespace Emby.Server.Implementations.Channels var providerTotalRecordCount = providerLimit.HasValue ? itemsResult.TotalRecordCount : null; - var tasks = itemsResult.Items.Select(i => GetChannelItemEntity(i, channelProvider, channel.Id, cancellationToken)); - - var internalItems = await Task.WhenAll(tasks).ConfigureAwait(false); + var internalItems = itemsResult.Items.Select(i => GetChannelItemEntity(i, channelProvider, channel.Id, cancellationToken)).ToArray(); if (user != null) { @@ -1234,7 +1228,7 @@ namespace Emby.Server.Implementations.Channels return item; } - private async Task GetChannelItemEntity(ChannelItemInfo info, IChannel channelProvider, Guid internalChannelId, CancellationToken cancellationToken) + private BaseItem GetChannelItemEntity(ChannelItemInfo info, IChannel channelProvider, Guid internalChannelId, CancellationToken cancellationToken) { BaseItem item; bool isNew; @@ -1399,7 +1393,7 @@ namespace Emby.Server.Implementations.Channels } else if (forceUpdate) { - await item.UpdateToRepository(ItemUpdateType.None, cancellationToken).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.None, cancellationToken); } SaveMediaSources(item, info.MediaSources); @@ -1542,20 +1536,20 @@ namespace Emby.Server.Implementations.Channels return items; } - public async Task GetChannelFolder(string userId, CancellationToken cancellationToken) + public BaseItemDto GetChannelFolder(string userId, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(userId) ? null : _userManager.GetUserById(userId); - var folder = await GetInternalChannelFolder(cancellationToken).ConfigureAwait(false); + var folder = GetInternalChannelFolder(cancellationToken); return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user); } - public async Task GetInternalChannelFolder(CancellationToken cancellationToken) + public Folder GetInternalChannelFolder(CancellationToken cancellationToken) { var name = _localization.GetLocalizedString("ViewTypeChannels"); - return await _libraryManager.GetNamedView(name, "channels", "zz_" + name, cancellationToken).ConfigureAwait(false); + return _libraryManager.GetNamedView(name, "channels", "zz_" + name, cancellationToken); } } diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 2e884e729c..c8e947fd7d 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -203,7 +203,7 @@ namespace Emby.Server.Implementations.Collections collection.UpdateRatingToContent(); - await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); _providerManager.QueueRefresh(collection.Id, refreshOptions, RefreshPriority.High); @@ -262,7 +262,7 @@ namespace Emby.Server.Implementations.Collections collection.UpdateRatingToContent(); - await collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + collection.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); _providerManager.QueueRefresh(collection.Id, new MetadataRefreshOptions(_fileSystem), RefreshPriority.High); EventHelper.FireEventIfNotNull(ItemsRemovedFromCollection, this, new CollectionModifiedEventArgs diff --git a/Emby.Server.Implementations/IO/FileRefresher.cs b/Emby.Server.Implementations/IO/FileRefresher.cs index 315bee103e..85b8bddd28 100644 --- a/Emby.Server.Implementations/IO/FileRefresher.cs +++ b/Emby.Server.Implementations/IO/FileRefresher.cs @@ -154,20 +154,13 @@ namespace Emby.Server.Implementations.IO .DistinctBy(i => i.Id) .ToList(); - //foreach (var p in paths) - //{ - // Logger.Info(p + " reports change."); - //} - - // If the root folder changed, run the library task so the user can see it - if (itemsToRefresh.Any(i => i is AggregateFolder)) - { - LibraryManager.ValidateMediaLibrary(new SimpleProgress(), CancellationToken.None); - return; - } - foreach (var item in itemsToRefresh) { + if (item is AggregateFolder) + { + continue; + } + Logger.Info(item.Name + " (" + item.Path + ") will be refreshed."); try diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 85b91ac25a..a7b85ad428 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -738,8 +738,7 @@ namespace Emby.Server.Implementations.Library if (folder.ParentId != rootFolder.Id) { folder.ParentId = rootFolder.Id; - var task = folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); - Task.WaitAll(task); + folder.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); } rootFolder.AddVirtualChild(folder); @@ -1834,12 +1833,12 @@ namespace Emby.Server.Implementations.Library /// The update reason. /// The cancellation token. /// Task. - public async Task UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken) + public void UpdateItem(BaseItem item, ItemUpdateType updateReason, CancellationToken cancellationToken) { var locationType = item.LocationType; if (locationType != LocationType.Remote && locationType != LocationType.Virtual) { - await _providerManagerFactory().SaveMetadata(item, updateReason).ConfigureAwait(false); + _providerManagerFactory().SaveMetadata(item, updateReason); } item.DateLastSaved = DateTime.UtcNow; @@ -2053,7 +2052,7 @@ namespace Emby.Server.Implementations.Library return GetNamedView(user, name, null, viewType, sortName, cancellationToken); } - public async Task GetNamedView(string name, + public UserView GetNamedView(string name, string viewType, string sortName, CancellationToken cancellationToken) @@ -2100,7 +2099,7 @@ namespace Emby.Server.Implementations.Library if (refresh) { - await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(_fileSystem) { // Not sure why this is necessary but need to figure it out @@ -2241,7 +2240,7 @@ namespace Emby.Server.Implementations.Library return item; } - public async Task GetNamedView(string name, + public UserView GetNamedView(string name, string parentId, string viewType, string sortName, @@ -2294,7 +2293,7 @@ namespace Emby.Server.Implementations.Library if (!string.Equals(viewType, item.ViewType, StringComparison.OrdinalIgnoreCase)) { item.ViewType = viewType; - await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken); } var refresh = isNew || DateTime.UtcNow - item.DateLastRefreshed >= _viewRefreshInterval; @@ -2822,7 +2821,7 @@ namespace Emby.Server.Implementations.Library await _providerManagerFactory().SaveImage(item, url, image.Type, imageIndex, CancellationToken.None).ConfigureAwait(false); - await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); return item.GetImageInfo(image.Type, imageIndex); } @@ -2838,7 +2837,7 @@ namespace Emby.Server.Implementations.Library // Remove this image to prevent it from retrying over and over item.RemoveImage(image); - await item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false); + item.UpdateToRepository(ItemUpdateType.ImageUpdate, CancellationToken.None); throw new InvalidOperationException(); } diff --git a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs index 757e67eb49..4830da8fcf 100644 --- a/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs +++ b/Emby.Server.Implementations/Library/LocalTrailerPostScanTask.cs @@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.Library { cancellationToken.ThrowIfCancellationRequested(); - await AssignTrailers(item, trailers).ConfigureAwait(false); + AssignTrailers(item, trailers); numComplete++; double percent = numComplete; @@ -65,7 +65,7 @@ namespace Emby.Server.Implementations.Library progress.Report(100); } - private async Task AssignTrailers(IHasTrailers item, IEnumerable channelTrailers) + private void AssignTrailers(IHasTrailers item, IEnumerable channelTrailers) { if (item is Game) { @@ -98,8 +98,7 @@ namespace Emby.Server.Implementations.Library item.RemoteTrailerIds = trailerIds; var baseItem = (BaseItem)item; - await baseItem.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None) - .ConfigureAwait(false); + baseItem.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None); } } } diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index cd12647540..82f42c7455 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -147,7 +147,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies Items = videos }; - var isInMixedFolder = resolverResult.Count > 1; + var isInMixedFolder = resolverResult.Count > 1 || (parent != null && parent.IsTopParent); foreach (var video in resolverResult) { diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs index 8c93772915..4ee0f553f3 100644 --- a/Emby.Server.Implementations/Library/UserViewManager.cs +++ b/Emby.Server.Implementations/Library/UserViewManager.cs @@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Library if (_config.Configuration.EnableFolderView) { var name = _localizationManager.GetLocalizedString("ViewType" + CollectionType.Folders); - list.Add(await _libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken).ConfigureAwait(false)); + list.Add(_libraryManager.GetNamedView(name, CollectionType.Folders, string.Empty, cancellationToken)); } if (query.IncludeExternalContent) @@ -117,7 +117,7 @@ namespace Emby.Server.Implementations.Library if (_config.Configuration.EnableChannelView && channels.Length > 0) { - list.Add(await _channelManager.GetInternalChannelFolder(cancellationToken).ConfigureAwait(false)); + list.Add(_channelManager.GetInternalChannelFolder(cancellationToken)); } else { @@ -126,7 +126,7 @@ namespace Emby.Server.Implementations.Library if (_liveTvManager.GetEnabledUsers().Select(i => i.Id.ToString("N")).Contains(query.UserId)) { - list.Add(await _liveTvManager.GetInternalLiveTvFolder(CancellationToken.None).ConfigureAwait(false)); + list.Add(_liveTvManager.GetInternalLiveTvFolder(CancellationToken.None)); } } @@ -158,14 +158,14 @@ namespace Emby.Server.Implementations.Library .ToArray(); } - public Task GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken) + public UserView GetUserSubView(string name, string parentId, string type, string sortName, CancellationToken cancellationToken) { var uniqueId = parentId + "subview" + type; return _libraryManager.GetNamedView(name, parentId, type, sortName, uniqueId, cancellationToken); } - public Task GetUserSubView(string parentId, string type, string sortName, CancellationToken cancellationToken) + public UserView GetUserSubView(string parentId, string type, string sortName, CancellationToken cancellationToken) { var name = _localizationManager.GetLocalizedString("ViewType" + type); diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs index 857afa3781..ec2704aa08 100644 --- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs @@ -173,11 +173,11 @@ namespace Emby.Server.Implementations.LiveTv } } - public async Task> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken) + public QueryResult GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); - var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + var topFolder = GetInternalLiveTvFolder(cancellationToken); var internalQuery = new InternalItemsQuery(user) { @@ -565,7 +565,7 @@ namespace Emby.Server.Implementations.LiveTv } else if (forceUpdate) { - await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken); } await item.RefreshMetadata(new MetadataRefreshOptions(_fileSystem) @@ -760,7 +760,7 @@ namespace Emby.Server.Implementations.LiveTv return new Tuple(item, isNew, isUpdated); } - private async Task CreateRecordingRecord(RecordingInfo info, string serviceName, Guid parentFolderId, CancellationToken cancellationToken) + private Guid CreateRecordingRecord(RecordingInfo info, string serviceName, Guid parentFolderId, CancellationToken cancellationToken) { var isNew = false; @@ -892,7 +892,7 @@ namespace Emby.Server.Implementations.LiveTv else if (dataChanged || info.DateLastUpdated > recording.DateLastSaved || statusChanged) { metadataRefreshMode = MetadataRefreshMode.FullRefresh; - await _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + _libraryManager.UpdateItem(item, ItemUpdateType.MetadataImport, cancellationToken); } if (info.Status != RecordingStatus.InProgress) @@ -928,7 +928,7 @@ namespace Emby.Server.Implementations.LiveTv { var user = string.IsNullOrEmpty(query.UserId) ? null : _userManager.GetUserById(query.UserId); - var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + var topFolder = GetInternalLiveTvFolder(cancellationToken); if (query.OrderBy.Length == 0) { @@ -1007,11 +1007,11 @@ namespace Emby.Server.Implementations.LiveTv return result; } - public async Task> GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) + public QueryResult GetRecommendedProgramsInternal(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { var user = _userManager.GetUserById(query.UserId); - var topFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + var topFolder = GetInternalLiveTvFolder(cancellationToken); var internalQuery = new InternalItemsQuery(user) { @@ -1072,11 +1072,11 @@ namespace Emby.Server.Implementations.LiveTv return result; } - public async Task> GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) + public QueryResult GetRecommendedPrograms(RecommendedProgramQuery query, DtoOptions options, CancellationToken cancellationToken) { RemoveFields(options); - var internalResult = await GetRecommendedProgramsInternal(query, options, cancellationToken).ConfigureAwait(false); + var internalResult = GetRecommendedProgramsInternal(query, options, cancellationToken); var user = _userManager.GetUserById(query.UserId); @@ -1302,7 +1302,7 @@ namespace Emby.Server.Implementations.LiveTv var list = new List(); var numComplete = 0; - var parentFolder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + var parentFolder = GetInternalLiveTvFolder(cancellationToken); var parentFolderId = parentFolder.Id; foreach (var channelInfo in allChannelsList) @@ -1425,7 +1425,7 @@ namespace Emby.Server.Implementations.LiveTv // TODO: Do this in bulk foreach (var program in updatedPrograms) { - await _libraryManager.UpdateItem(program, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + _libraryManager.UpdateItem(program, ItemUpdateType.MetadataImport, cancellationToken); } currentChannel.IsMovie = isMovie; @@ -1434,7 +1434,7 @@ namespace Emby.Server.Implementations.LiveTv currentChannel.IsKids = isKids; currentChannel.IsSeries = iSSeries; - await currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); + currentChannel.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); } catch (OperationCanceledException) { @@ -1549,9 +1549,8 @@ namespace Emby.Server.Implementations.LiveTv var results = await Task.WhenAll(tasks).ConfigureAwait(false); - var recordingTasks = results.SelectMany(i => i.ToList()).Select(i => CreateRecordingRecord(i.Item1, i.Item2.Name, internalLiveTvFolderId, cancellationToken)); - - var idList = await Task.WhenAll(recordingTasks).ConfigureAwait(false); + var idList = results.SelectMany(i => i.ToList()).Select(i => CreateRecordingRecord(i.Item1, i.Item2.Name, internalLiveTvFolderId, cancellationToken)) + .ToArray(); await CleanDatabaseInternal(idList, new[] { typeof(LiveTvVideoRecording).Name, typeof(LiveTvAudioRecording).Name }, new SimpleProgress(), cancellationToken).ConfigureAwait(false); @@ -1726,7 +1725,7 @@ namespace Emby.Server.Implementations.LiveTv return new QueryResult(); } - var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + var folder = GetInternalLiveTvFolder(cancellationToken); // TODO: Figure out how to merge emby recordings + service recordings if (_services.Length == 1) @@ -2143,18 +2142,6 @@ namespace Emby.Server.Implementations.LiveTv }; } - public Task OnRecordingFileDeleted(BaseItem recording) - { - var service = GetService(recording); - - if (service is EmbyTV.EmbyTV) - { - return service.DeleteRecordingAsync(GetItemExternalId(recording), CancellationToken.None); - } - - return Task.FromResult(true); - } - public async Task DeleteRecording(string recordingId) { var recording = await GetInternalRecording(recordingId, CancellationToken.None).ConfigureAwait(false); @@ -2171,13 +2158,17 @@ namespace Emby.Server.Implementations.LiveTv { var service = GetService(recording.ServiceName); - try - { - await service.DeleteRecordingAsync(GetItemExternalId(recording), CancellationToken.None).ConfigureAwait(false); - } - catch (ResourceNotFoundException) + if (service != null) { + // handle the service being uninstalled and the item hanging around in the database + try + { + await service.DeleteRecordingAsync(GetItemExternalId(recording), CancellationToken.None).ConfigureAwait(false); + } + catch (ResourceNotFoundException) + { + } } _lastRecordingRefreshTime = DateTime.MinValue; @@ -2387,7 +2378,7 @@ namespace Emby.Server.Implementations.LiveTv MinEndDate = now, Limit = channelIds.Length, OrderBy = new[] { new Tuple(ItemSortBy.StartDate, SortOrder.Ascending) }, - TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Result.Id.ToString("N") }, + TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id.ToString("N") }, DtoOptions = options }) : new List(); @@ -2910,11 +2901,11 @@ namespace Emby.Server.Implementations.LiveTv return service.ResetTuner(parts[1], cancellationToken); } - public async Task GetLiveTvFolder(string userId, CancellationToken cancellationToken) + public BaseItemDto GetLiveTvFolder(string userId, CancellationToken cancellationToken) { var user = string.IsNullOrEmpty(userId) ? null : _userManager.GetUserById(userId); - var folder = await GetInternalLiveTvFolder(cancellationToken).ConfigureAwait(false); + var folder = GetInternalLiveTvFolder(cancellationToken); return _dtoService.GetBaseItemDto(folder, new DtoOptions(), user); } @@ -2930,10 +2921,10 @@ namespace Emby.Server.Implementations.LiveTv options.Fields = fields.ToArray(fields.Count); } - public async Task GetInternalLiveTvFolder(CancellationToken cancellationToken) + public Folder GetInternalLiveTvFolder(CancellationToken cancellationToken) { var name = _localization.GetLocalizedString("ViewTypeLiveTV"); - return await _libraryManager.GetNamedView(name, CollectionType.LiveTv, name, cancellationToken).ConfigureAwait(false); + return _libraryManager.GetNamedView(name, CollectionType.LiveTv, name, cancellationToken); } public async Task SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true) diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 87832e7dda..f268e9c0c1 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -209,7 +209,7 @@ namespace Emby.Server.Implementations.Playlists newList.AddRange(list); playlist.LinkedChildren = newList.ToArray(newList.Count); - await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem) { @@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.Playlists .Select(i => i.Item1) .ToArray(); - await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(_fileSystem) { @@ -281,7 +281,7 @@ namespace Emby.Server.Implementations.Playlists playlist.LinkedChildren = newList.ToArray(newList.Count); - await playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); + playlist.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None); } public Folder GetPlaylistsFolder(string userId) -- cgit v1.2.3 From 983b51e0830ece26c1bd8445359fda14f0f99925 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 4 Oct 2017 14:51:26 -0400 Subject: reduce socket activity --- Emby.Dlna/Eventing/EventManager.cs | 20 +- Emby.Dlna/Service/BaseService.cs | 4 +- .../IO/ManagedFileSystem.cs | 21 ++ .../Updates/InstallationManager.cs | 5 - MediaBrowser.Api/BasePeriodicWebSocketListener.cs | 327 --------------------- MediaBrowser.Api/Dlna/DlnaServerService.cs | 2 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 1 - .../ScheduledTasksWebSocketListener.cs | 1 + .../System/ActivityLogWebSocketListener.cs | 1 + MediaBrowser.Api/UserLibrary/ItemsService.cs | 4 +- MediaBrowser.Controller/Dlna/IEventManager.cs | 2 +- .../MediaBrowser.Controller.csproj | 1 + .../Net/BasePeriodicWebSocketListener.cs | 326 ++++++++++++++++++++ MediaBrowser.WebDashboard/Api/PackageCreator.cs | 2 +- 14 files changed, 373 insertions(+), 344 deletions(-) delete mode 100644 MediaBrowser.Api/BasePeriodicWebSocketListener.cs create mode 100644 MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs (limited to 'Emby.Server.Implementations') diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs index 0516585ae0..99ba74f327 100644 --- a/Emby.Dlna/Eventing/EventManager.cs +++ b/Emby.Dlna/Eventing/EventManager.cs @@ -26,9 +26,11 @@ namespace Emby.Dlna.Eventing _logger = logger; } - public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string requestedTimeoutString) + public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl) { - var subscription = GetSubscription(subscriptionId, true); + var subscription = GetSubscription(subscriptionId, false); + + int timeoutSeconds; // Remove logging for now because some devices are sending this very frequently // TODO re-enable with dlna debug logging setting @@ -37,10 +39,18 @@ namespace Emby.Dlna.Eventing // timeout, // subscription.CallbackUrl); - subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300; - subscription.SubscriptionTime = DateTime.UtcNow; + if (subscription != null) + { + subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300; + timeoutSeconds = subscription.TimeoutSeconds; + subscription.SubscriptionTime = DateTime.UtcNow; + } + else + { + timeoutSeconds = 300; + } - return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, subscription.TimeoutSeconds); + return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds); } public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl) diff --git a/Emby.Dlna/Service/BaseService.cs b/Emby.Dlna/Service/BaseService.cs index ddc37da095..bc7f01d974 100644 --- a/Emby.Dlna/Service/BaseService.cs +++ b/Emby.Dlna/Service/BaseService.cs @@ -24,9 +24,9 @@ namespace Emby.Dlna.Service return EventManager.CancelEventSubscription(subscriptionId); } - public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string timeoutString) + public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string timeoutString, string callbackUrl) { - return EventManager.RenewEventSubscription(subscriptionId, timeoutString); + return EventManager.RenewEventSubscription(subscriptionId, notificationType, timeoutString, callbackUrl); } public EventSubscriptionResponse CreateEventSubscription(string notificationType, string timeoutString, string callbackUrl) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 0d85a977c5..125d9e980f 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; using System.Text; @@ -24,12 +25,14 @@ namespace Emby.Server.Implementations.IO private string _tempPath; private SharpCifsFileSystem _sharpCifsFileSystem; + private IEnvironmentInfo _environmentInfo; public ManagedFileSystem(ILogger logger, IEnvironmentInfo environmentInfo, string tempPath) { Logger = logger; _supportsAsyncFileStreams = true; _tempPath = tempPath; + _environmentInfo = environmentInfo; // On Linux, this needs to be true or symbolic links are ignored EnableFileSystemRequestConcat = environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows && @@ -1051,7 +1054,25 @@ namespace Emby.Server.Implementations.IO public virtual void SetExecutable(string path) { + if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX) + { + RunProcess("chmod", "+x \"" + path + "\"", GetDirectoryName(path)); + } + } + private void RunProcess(string path, string args, string workingDirectory) + { + using (var process = Process.Start(new ProcessStartInfo + { + Arguments = args, + FileName = path, + CreateNoWindow = true, + WorkingDirectory = workingDirectory, + WindowStyle = ProcessWindowStyle.Normal + })) + { + process.WaitForExit(); + } } } } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 1804630403..772f2338ac 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -442,11 +442,6 @@ namespace Emby.Server.Implementations.Updates /// Task{IEnumerable{PackageVersionInfo}}. public async Task> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken) { - if (!_config.CommonConfiguration.EnableAutoUpdate) - { - return new PackageVersionInfo[] { }; - } - var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); var systemUpdateLevel = GetSystemUpdateLevel(); diff --git a/MediaBrowser.Api/BasePeriodicWebSocketListener.cs b/MediaBrowser.Api/BasePeriodicWebSocketListener.cs deleted file mode 100644 index c7a9d97bad..0000000000 --- a/MediaBrowser.Api/BasePeriodicWebSocketListener.cs +++ /dev/null @@ -1,327 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Net; -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.Threading; - -namespace MediaBrowser.Api -{ - /// - /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received - /// - /// The type of the T return data type. - /// The type of the T state type. - public abstract class BasePeriodicWebSocketListener : IWebSocketListener, IDisposable - where TStateType : WebSocketListenerState, new() - where TReturnDataType : class - { - /// - /// The _active connections - /// - protected readonly List> ActiveConnections = - new List>(); - - /// - /// Gets the name. - /// - /// The name. - protected abstract string Name { get; } - - /// - /// Gets the data to send. - /// - /// The state. - /// Task{`1}. - protected abstract Task GetDataToSend(TStateType state); - - /// - /// The logger - /// - protected ILogger Logger; - - protected ITimerFactory TimerFactory { get; private set; } - - protected BasePeriodicWebSocketListener(ILogger logger, ITimerFactory timerFactory) - { - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - Logger = logger; - TimerFactory = timerFactory; - } - - /// - /// The null task result - /// - protected Task NullTaskResult = Task.FromResult(true); - - /// - /// Processes the message. - /// - /// The message. - /// Task. - public Task ProcessMessage(WebSocketMessageInfo message) - { - if (message == null) - { - throw new ArgumentNullException("message"); - } - - if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase)) - { - Start(message); - } - - if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase)) - { - Stop(message); - } - - return NullTaskResult; - } - - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - protected virtual bool SendOnTimer - { - get - { - return true; - } - } - - protected virtual void ParseMessageParams(string[] values) - { - - } - - /// - /// Starts sending messages over a web socket - /// - /// The message. - private void Start(WebSocketMessageInfo message) - { - var vals = message.Data.Split(','); - - var dueTimeMs = long.Parse(vals[0], UsCulture); - var periodMs = long.Parse(vals[1], UsCulture); - - if (vals.Length > 2) - { - ParseMessageParams(vals.Skip(2).ToArray()); - } - - var cancellationTokenSource = new CancellationTokenSource(); - - Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); - - var timer = SendOnTimer ? - TimerFactory.Create(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : - null; - - var state = new TStateType - { - IntervalMs = periodMs, - InitialDelayMs = dueTimeMs - }; - - lock (ActiveConnections) - { - ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state)); - } - - if (timer != null) - { - timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); - } - } - - /// - /// Timers the callback. - /// - /// The state. - private void TimerCallback(object state) - { - var connection = (IWebSocketConnection)state; - - Tuple tuple; - - lock (ActiveConnections) - { - tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection); - } - - if (tuple == null) - { - return; - } - - if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested) - { - DisposeConnection(tuple); - return; - } - - SendData(tuple); - } - - protected void SendData(bool force) - { - List> tuples; - - lock (ActiveConnections) - { - tuples = ActiveConnections - .Where(c => - { - if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) - { - var state = c.Item4; - - if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs) - { - return true; - } - } - - return false; - }) - .ToList(); - } - - foreach (var tuple in tuples) - { - SendData(tuple); - } - } - - private async void SendData(Tuple tuple) - { - var connection = tuple.Item1; - - try - { - var state = tuple.Item4; - - var data = await GetDataToSend(state).ConfigureAwait(false); - - if (data != null) - { - await connection.SendAsync(new WebSocketMessage - { - MessageType = Name, - Data = data - - }, tuple.Item2.Token).ConfigureAwait(false); - - state.DateLastSendUtc = DateTime.UtcNow; - } - } - catch (OperationCanceledException) - { - if (tuple.Item2.IsCancellationRequested) - { - DisposeConnection(tuple); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message {0}", ex, Name); - DisposeConnection(tuple); - } - } - - /// - /// Stops sending messages over a web socket - /// - /// The message. - private void Stop(WebSocketMessageInfo message) - { - lock (ActiveConnections) - { - var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection); - - if (connection != null) - { - DisposeConnection(connection); - } - } - } - - /// - /// Disposes the connection. - /// - /// The connection. - private void DisposeConnection(Tuple connection) - { - Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); - - var timer = connection.Item3; - - if (timer != null) - { - try - { - timer.Dispose(); - } - catch (ObjectDisposedException) - { - - } - } - - try - { - connection.Item2.Cancel(); - connection.Item2.Dispose(); - } - catch (ObjectDisposedException) - { - - } - - ActiveConnections.Remove(connection); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - lock (ActiveConnections) - { - foreach (var connection in ActiveConnections.ToList()) - { - DisposeConnection(connection); - } - } - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } - - public class WebSocketListenerState - { - public DateTime DateLastSendUtc { get; set; } - public long InitialDelayMs { get; set; } - public long IntervalMs { get; set; } - } -} diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs index cbef6e5b3b..6a0cea4df9 100644 --- a/MediaBrowser.Api/Dlna/DlnaServerService.cs +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -246,7 +246,7 @@ namespace MediaBrowser.Api.Dlna if (string.IsNullOrEmpty(notificationType)) { - return GetSubscriptionResponse(eventManager.RenewEventSubscription(subscriptionId, timeoutString)); + return GetSubscriptionResponse(eventManager.RenewEventSubscription(subscriptionId, notificationType, timeoutString, callback)); } return GetSubscriptionResponse(eventManager.CreateEventSubscription(notificationType, timeoutString, callback)); diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index ddb187f3d9..650306ea60 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -40,7 +40,6 @@ Properties\SharedVersion.cs - diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index ee74ec450c..69ce6a385d 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Tasks; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.ScheduledTasks diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs index c641695dd8..793f745713 100644 --- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs +++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using System.Collections.Generic; using System.Threading.Tasks; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Threading; namespace MediaBrowser.Api.System diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 5fe386f1ab..1e531ba664 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -117,7 +117,9 @@ namespace MediaBrowser.Api.UserLibrary IsVirtualItem = false, CollapseBoxSetItems = false, EnableTotalRecordCount = request.EnableTotalRecordCount, - AncestorIds = ancestorIds.ToArray() + AncestorIds = ancestorIds.ToArray(), + IncludeItemTypes = request.GetIncludeItemTypes(), + ExcludeItemTypes = request.GetExcludeItemTypes() }); var returnItems = _dtoService.GetBaseItemDtos(itemsResult.Items, options, user); diff --git a/MediaBrowser.Controller/Dlna/IEventManager.cs b/MediaBrowser.Controller/Dlna/IEventManager.cs index 8c91bd889d..3af357a174 100644 --- a/MediaBrowser.Controller/Dlna/IEventManager.cs +++ b/MediaBrowser.Controller/Dlna/IEventManager.cs @@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Dlna /// /// Renews the event subscription. /// - EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string requestedTimeoutString); + EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl); /// /// Creates the event subscription. diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index b33993859b..960ff0aa7d 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -176,6 +176,7 @@ + diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs new file mode 100644 index 0000000000..6be94e7e6e --- /dev/null +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using MediaBrowser.Model.Threading; + +namespace MediaBrowser.Controller.Net +{ + /// + /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received + /// + /// The type of the T return data type. + /// The type of the T state type. + public abstract class BasePeriodicWebSocketListener : IWebSocketListener, IDisposable + where TStateType : WebSocketListenerState, new() + where TReturnDataType : class + { + /// + /// The _active connections + /// + protected readonly List> ActiveConnections = + new List>(); + + /// + /// Gets the name. + /// + /// The name. + protected abstract string Name { get; } + + /// + /// Gets the data to send. + /// + /// The state. + /// Task{`1}. + protected abstract Task GetDataToSend(TStateType state); + + /// + /// The logger + /// + protected ILogger Logger; + + protected ITimerFactory TimerFactory { get; private set; } + + protected BasePeriodicWebSocketListener(ILogger logger, ITimerFactory timerFactory) + { + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + + Logger = logger; + TimerFactory = timerFactory; + } + + /// + /// The null task result + /// + protected Task NullTaskResult = Task.FromResult(true); + + /// + /// Processes the message. + /// + /// The message. + /// Task. + public Task ProcessMessage(WebSocketMessageInfo message) + { + if (message == null) + { + throw new ArgumentNullException("message"); + } + + if (string.Equals(message.MessageType, Name + "Start", StringComparison.OrdinalIgnoreCase)) + { + Start(message); + } + + if (string.Equals(message.MessageType, Name + "Stop", StringComparison.OrdinalIgnoreCase)) + { + Stop(message); + } + + return NullTaskResult; + } + + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + protected virtual bool SendOnTimer + { + get + { + return false; + } + } + + protected virtual void ParseMessageParams(string[] values) + { + + } + + /// + /// Starts sending messages over a web socket + /// + /// The message. + private void Start(WebSocketMessageInfo message) + { + var vals = message.Data.Split(','); + + var dueTimeMs = long.Parse(vals[0], UsCulture); + var periodMs = long.Parse(vals[1], UsCulture); + + if (vals.Length > 2) + { + ParseMessageParams(vals.Skip(2).ToArray()); + } + + var cancellationTokenSource = new CancellationTokenSource(); + + Logger.Debug("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); + + var timer = SendOnTimer ? + TimerFactory.Create(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : + null; + + var state = new TStateType + { + IntervalMs = periodMs, + InitialDelayMs = dueTimeMs + }; + + lock (ActiveConnections) + { + ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state)); + } + + if (timer != null) + { + timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); + } + } + + /// + /// Timers the callback. + /// + /// The state. + private void TimerCallback(object state) + { + var connection = (IWebSocketConnection)state; + + Tuple tuple; + + lock (ActiveConnections) + { + tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection); + } + + if (tuple == null) + { + return; + } + + if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested) + { + DisposeConnection(tuple); + return; + } + + SendData(tuple); + } + + protected void SendData(bool force) + { + List> tuples; + + lock (ActiveConnections) + { + tuples = ActiveConnections + .Where(c => + { + if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) + { + var state = c.Item4; + + if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs) + { + return true; + } + } + + return false; + }) + .ToList(); + } + + foreach (var tuple in tuples) + { + SendData(tuple); + } + } + + private async void SendData(Tuple tuple) + { + var connection = tuple.Item1; + + try + { + var state = tuple.Item4; + + var data = await GetDataToSend(state).ConfigureAwait(false); + + if (data != null) + { + await connection.SendAsync(new WebSocketMessage + { + MessageType = Name, + Data = data + + }, tuple.Item2.Token).ConfigureAwait(false); + + state.DateLastSendUtc = DateTime.UtcNow; + } + } + catch (OperationCanceledException) + { + if (tuple.Item2.IsCancellationRequested) + { + DisposeConnection(tuple); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error sending web socket message {0}", ex, Name); + DisposeConnection(tuple); + } + } + + /// + /// Stops sending messages over a web socket + /// + /// The message. + private void Stop(WebSocketMessageInfo message) + { + lock (ActiveConnections) + { + var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection); + + if (connection != null) + { + DisposeConnection(connection); + } + } + } + + /// + /// Disposes the connection. + /// + /// The connection. + private void DisposeConnection(Tuple connection) + { + Logger.Debug("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); + + var timer = connection.Item3; + + if (timer != null) + { + try + { + timer.Dispose(); + } + catch (ObjectDisposedException) + { + + } + } + + try + { + connection.Item2.Cancel(); + connection.Item2.Dispose(); + } + catch (ObjectDisposedException) + { + + } + + ActiveConnections.Remove(connection); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + lock (ActiveConnections) + { + foreach (var connection in ActiveConnections.ToList()) + { + DisposeConnection(connection); + } + } + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } + + public class WebSocketListenerState + { + public DateTime DateLastSendUtc { get; set; } + public long InitialDelayMs { get; set; } + public long IntervalMs { get; set; } + } +} diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index c855a8d9ba..bb4a98fa86 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -265,7 +265,7 @@ namespace MediaBrowser.WebDashboard.Api builder.AppendFormat("window.appMode='{0}';", mode); } - if (string.IsNullOrWhiteSpace(mode)) + else { builder.AppendFormat("window.dashboardVersion='{0}';", version); } -- cgit v1.2.3