From ff4ee7ab9c41f9756e1db6f25f701c8ca69cecf2 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Wed, 27 Feb 2013 15:25:45 -0500 Subject: combined usermanager and userdata manager --- MediaBrowser.Controller/Library/DtoBuilder.cs | 18 +- MediaBrowser.Controller/Library/IUserManager.cs | 169 +++++++++ MediaBrowser.Controller/Library/LibraryManager.cs | 9 +- MediaBrowser.Controller/Library/UserDataManager.cs | 226 ------------ MediaBrowser.Controller/Library/UserManager.cs | 403 --------------------- 5 files changed, 184 insertions(+), 641 deletions(-) create mode 100644 MediaBrowser.Controller/Library/IUserManager.cs delete mode 100644 MediaBrowser.Controller/Library/UserDataManager.cs delete mode 100644 MediaBrowser.Controller/Library/UserManager.cs (limited to 'MediaBrowser.Controller/Library') diff --git a/MediaBrowser.Controller/Library/DtoBuilder.cs b/MediaBrowser.Controller/Library/DtoBuilder.cs index 8cf9d5b57..30a14bf97 100644 --- a/MediaBrowser.Controller/Library/DtoBuilder.cs +++ b/MediaBrowser.Controller/Library/DtoBuilder.cs @@ -823,7 +823,7 @@ namespace MediaBrowser.Controller.Library /// The id. /// The user id. /// BaseItem. - public static BaseItem GetItemByClientId(string id, Guid? userId = null) + public static BaseItem GetItemByClientId(string id, IUserManager userManager, Guid? userId = null) { var isIdEmpty = string.IsNullOrEmpty(id); @@ -835,7 +835,7 @@ namespace MediaBrowser.Controller.Library { if (userId.HasValue) { - return GetIndexFolder(id, userId.Value); + return GetIndexFolder(id, userId.Value, userManager); } } @@ -844,8 +844,8 @@ namespace MediaBrowser.Controller.Library if (userId.HasValue) { item = isIdEmpty - ? Kernel.Instance.GetUserById(userId.Value).RootFolder - : Kernel.Instance.GetItemById(new Guid(id), userId.Value); + ? userManager.GetUserById(userId.Value).RootFolder + : Kernel.Instance.GetItemById(new Guid(id), userId.Value, userManager); } else if (!isIndexFolder) { @@ -855,9 +855,9 @@ namespace MediaBrowser.Controller.Library // If we still don't find it, look within individual user views if (item == null && !userId.HasValue) { - foreach (var user in Kernel.Instance.Users) + foreach (var user in userManager.Users) { - item = GetItemByClientId(id, user.Id); + item = GetItemByClientId(id, userManager, user.Id); if (item != null) { @@ -875,9 +875,9 @@ namespace MediaBrowser.Controller.Library /// The id. /// The user id. /// BaseItem. - private static BaseItem GetIndexFolder(string id, Guid userId) + private static BaseItem GetIndexFolder(string id, Guid userId, IUserManager userManager) { - var user = Kernel.Instance.GetUserById(userId); + var user = userManager.GetUserById(userId); var stringSeparators = new[] { IndexFolderDelimeter }; @@ -885,7 +885,7 @@ namespace MediaBrowser.Controller.Library var values = id.Split(stringSeparators, StringSplitOptions.None).ToList(); // Get the top folder normally using the first id - var folder = GetItemByClientId(values[0], userId) as Folder; + var folder = GetItemByClientId(values[0], userManager, userId) as Folder; values.RemoveAt(0); diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs new file mode 100644 index 000000000..ea4f03330 --- /dev/null +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -0,0 +1,169 @@ +using MediaBrowser.Common.Events; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Connectivity; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Library +{ + public interface IUserManager + { + /// + /// Gets the users. + /// + /// The users. + IEnumerable Users { get; } + + /// + /// Gets the active connections. + /// + /// The active connections. + IEnumerable ConnectedUsers { get; } + + /// + /// Occurs when [playback start]. + /// + event EventHandler PlaybackStart; + + /// + /// Occurs when [playback progress]. + /// + event EventHandler PlaybackProgress; + + /// + /// Occurs when [playback stopped]. + /// + event EventHandler PlaybackStopped; + + /// + /// Occurs when [user updated]. + /// + event EventHandler> UserUpdated; + + /// + /// Occurs when [user deleted]. + /// + event EventHandler> UserDeleted; + + /// + /// Gets a User by Id + /// + /// The id. + /// User. + /// + User GetUserById(Guid id); + + /// + /// Authenticates a User and returns a result indicating whether or not it succeeded + /// + /// The user. + /// The password. + /// Task{System.Boolean}. + /// user + Task AuthenticateUser(User user, string password); + + /// + /// Logs the user activity. + /// + /// The user. + /// Type of the client. + /// Name of the device. + /// Task. + /// user + Task LogUserActivity(User user, ClientType clientType, string deviceName); + + /// + /// Loads the users from the repository + /// + /// IEnumerable{User}. + IEnumerable LoadUsers(); + + /// + /// Refreshes metadata for each user + /// + /// The cancellation token. + /// if set to true [force]. + /// Task. + Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false); + + /// + /// Renames the user. + /// + /// The user. + /// The new name. + /// Task. + /// user + /// + Task RenameUser(User user, string newName); + + /// + /// Updates the user. + /// + /// The user. + /// user + /// + Task UpdateUser(User user); + + /// + /// Creates the user. + /// + /// The name. + /// User. + /// name + /// + Task CreateUser(string name); + + /// + /// Deletes the user. + /// + /// The user. + /// Task. + /// user + /// + Task DeleteUser(User user); + + /// + /// Used to report that playback has started for an item + /// + /// The user. + /// The item. + /// Type of the client. + /// Name of the device. + /// + void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName); + + /// + /// Used to report playback progress for an item + /// + /// The user. + /// The item. + /// The position ticks. + /// Type of the client. + /// Name of the device. + /// Task. + /// + Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName); + + /// + /// Used to report that playback has ended for an item + /// + /// The user. + /// The item. + /// The position ticks. + /// Type of the client. + /// Name of the device. + /// Task. + /// + Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName); + + /// + /// Saves user data for an item + /// + /// The user. + /// The item. + /// The data. + Task SaveUserDataForItem(User user, BaseItem item, UserItemData data); + } +} diff --git a/MediaBrowser.Controller/Library/LibraryManager.cs b/MediaBrowser.Controller/Library/LibraryManager.cs index 53f4af4b2..5dbf5c72d 100644 --- a/MediaBrowser.Controller/Library/LibraryManager.cs +++ b/MediaBrowser.Controller/Library/LibraryManager.cs @@ -64,6 +64,8 @@ namespace MediaBrowser.Controller.Library /// private readonly ITaskManager _taskManager; + private readonly IUserManager _userManager; + /// /// Gets or sets the kernel. /// @@ -76,11 +78,12 @@ namespace MediaBrowser.Controller.Library /// The kernel. /// The logger. /// The task manager. - public LibraryManager(Kernel kernel, ILogger logger, ITaskManager taskManager) + public LibraryManager(Kernel kernel, ILogger logger, ITaskManager taskManager, IUserManager userManager) { Kernel = kernel; _logger = logger; _taskManager = taskManager; + _userManager = userManager; kernel.ConfigurationUpdated += kernel_ConfigurationUpdated; } @@ -490,13 +493,13 @@ namespace MediaBrowser.Controller.Library await Kernel.RootFolder.ValidateChildren(new Progress { }, cancellationToken, recursive: false); // Validate only the collection folders for each user, just to make them available as quickly as possible - var userCollectionFolderTasks = Kernel.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress { }, cancellationToken)); + var userCollectionFolderTasks = _userManager.Users.AsParallel().Select(user => user.ValidateCollectionFolders(new Progress { }, cancellationToken)); await Task.WhenAll(userCollectionFolderTasks).ConfigureAwait(false); // Now validate the entire media library await Kernel.RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false); - foreach (var user in Kernel.Users) + foreach (var user in _userManager.Users) { await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Controller/Library/UserDataManager.cs b/MediaBrowser.Controller/Library/UserDataManager.cs deleted file mode 100644 index bda5d0383..000000000 --- a/MediaBrowser.Controller/Library/UserDataManager.cs +++ /dev/null @@ -1,226 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Connectivity; -using MediaBrowser.Model.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Library -{ - /// - /// Class UserDataManager - /// - public class UserDataManager : BaseManager - { - #region Events - /// - /// Occurs when [playback start]. - /// - public event EventHandler PlaybackStart; - /// - /// Occurs when [playback progress]. - /// - public event EventHandler PlaybackProgress; - /// - /// Occurs when [playback stopped]. - /// - public event EventHandler PlaybackStopped; - #endregion - - /// - /// The _logger - /// - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The kernel. - /// The logger. - public UserDataManager(Kernel kernel, ILogger logger) - : base(kernel) - { - _logger = logger; - } - - /// - /// Used to report that playback has started for an item - /// - /// The user. - /// The item. - /// Type of the client. - /// Name of the device. - /// - public void OnPlaybackStart(User user, BaseItem item, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException(); - } - if (item == null) - { - throw new ArgumentNullException(); - } - - Kernel.UserManager.UpdateNowPlayingItemId(user, clientType, deviceName, item); - - // Nothing to save here - // Fire events to inform plugins - EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs - { - Argument = item, - User = user - }, _logger); - } - - /// - /// Used to report playback progress for an item - /// - /// The user. - /// The item. - /// The position ticks. - /// Type of the client. - /// Name of the device. - /// Task. - /// - public async Task OnPlaybackProgress(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException(); - } - if (item == null) - { - throw new ArgumentNullException(); - } - - Kernel.UserManager.UpdateNowPlayingItemId(user, clientType, deviceName, item, positionTicks); - - if (positionTicks.HasValue) - { - var data = item.GetUserData(user, true); - - UpdatePlayState(item, data, positionTicks.Value, false); - await SaveUserDataForItem(user, item, data).ConfigureAwait(false); - } - - EventHelper.QueueEventIfNotNull(PlaybackProgress, this, new PlaybackProgressEventArgs - { - Argument = item, - User = user, - PlaybackPositionTicks = positionTicks - }, _logger); - } - - /// - /// Used to report that playback has ended for an item - /// - /// The user. - /// The item. - /// The position ticks. - /// Type of the client. - /// Name of the device. - /// Task. - /// - public async Task OnPlaybackStopped(User user, BaseItem item, long? positionTicks, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException(); - } - if (item == null) - { - throw new ArgumentNullException(); - } - - Kernel.UserManager.RemoveNowPlayingItemId(user, clientType, deviceName, item); - - var data = item.GetUserData(user, true); - - if (positionTicks.HasValue) - { - UpdatePlayState(item, data, positionTicks.Value, true); - } - else - { - // If the client isn't able to report this, then we'll just have to make an assumption - data.PlayCount++; - data.Played = true; - } - - await SaveUserDataForItem(user, item, data).ConfigureAwait(false); - - EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackProgressEventArgs - { - Argument = item, - User = user, - PlaybackPositionTicks = positionTicks - }, _logger); - } - - /// - /// Updates playstate position for an item but does not save - /// - /// The item - /// User data for the item - /// The current playback position - /// Whether or not to increment playcount - private void UpdatePlayState(BaseItem item, UserItemData data, long positionTicks, bool incrementPlayCount) - { - // If a position has been reported, and if we know the duration - if (positionTicks > 0 && item.RunTimeTicks.HasValue && item.RunTimeTicks > 0) - { - var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100; - - // Don't track in very beginning - if (pctIn < Kernel.Configuration.MinResumePct) - { - positionTicks = 0; - incrementPlayCount = false; - } - - // If we're at the end, assume completed - else if (pctIn > Kernel.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value) - { - positionTicks = 0; - data.Played = true; - } - - else - { - // Enforce MinResumeDuration - var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds; - - if (durationSeconds < Kernel.Configuration.MinResumeDurationSeconds) - { - positionTicks = 0; - data.Played = true; - } - } - } - - data.PlaybackPositionTicks = positionTicks; - - if (incrementPlayCount) - { - data.PlayCount++; - data.LastPlayedDate = DateTime.UtcNow; - } - } - - /// - /// Saves user data for an item - /// - /// The user. - /// The item. - /// The data. - public Task SaveUserDataForItem(User user, BaseItem item, UserItemData data) - { - item.AddOrUpdateUserData(user, data); - - return Kernel.UserDataRepository.SaveUserData(item, CancellationToken.None); - } - } -} diff --git a/MediaBrowser.Controller/Library/UserManager.cs b/MediaBrowser.Controller/Library/UserManager.cs deleted file mode 100644 index 5340e70be..000000000 --- a/MediaBrowser.Controller/Library/UserManager.cs +++ /dev/null @@ -1,403 +0,0 @@ -using MediaBrowser.Common.Events; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Kernel; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Connectivity; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Model.Logging; - -namespace MediaBrowser.Controller.Library -{ - /// - /// Class UserManager - /// - public class UserManager : BaseManager - { - /// - /// The _active connections - /// - private readonly ConcurrentBag _activeConnections = - new ConcurrentBag(); - - /// - /// Gets all connections. - /// - /// All connections. - public IEnumerable AllConnections - { - get { return _activeConnections.Where(c => Kernel.GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); } - } - - /// - /// Gets the active connections. - /// - /// The active connections. - public IEnumerable ActiveConnections - { - get { return AllConnections.Where(c => (DateTime.UtcNow - c.LastActivityDate).TotalMinutes <= 10); } - } - - /// - /// The _logger - /// - private readonly ILogger _logger; - - /// - /// Initializes a new instance of the class. - /// - /// The kernel. - /// The logger. - public UserManager(Kernel kernel, ILogger logger) - : base(kernel) - { - _logger = logger; - } - - #region UserUpdated Event - /// - /// Occurs when [user updated]. - /// - public event EventHandler> UserUpdated; - - /// - /// Called when [user updated]. - /// - /// The user. - internal void OnUserUpdated(User user) - { - EventHelper.QueueEventIfNotNull(UserUpdated, this, new GenericEventArgs { Argument = user }, _logger); - - // Notify connected ui's - Kernel.ServerManager.SendWebSocketMessage("UserUpdated", new DtoBuilder(_logger).GetDtoUser(user)); - } - #endregion - - #region UserDeleted Event - /// - /// Occurs when [user deleted]. - /// - public event EventHandler> UserDeleted; - /// - /// Called when [user deleted]. - /// - /// The user. - internal void OnUserDeleted(User user) - { - EventHelper.QueueEventIfNotNull(UserDeleted, this, new GenericEventArgs { Argument = user }, _logger); - - // Notify connected ui's - Kernel.ServerManager.SendWebSocketMessage("UserDeleted", user.Id.ToString()); - } - #endregion - - /// - /// Authenticates a User and returns a result indicating whether or not it succeeded - /// - /// The user. - /// The password. - /// Task{System.Boolean}. - /// user - public async Task AuthenticateUser(User user, string password) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - password = password ?? string.Empty; - var existingPassword = string.IsNullOrEmpty(user.Password) ? string.Empty.GetMD5().ToString() : user.Password; - - var success = password.GetMD5().ToString().Equals(existingPassword); - - // Update LastActivityDate and LastLoginDate, then save - if (success) - { - user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow; - await UpdateUser(user).ConfigureAwait(false); - } - - _logger.Info("Authentication request for {0} {1}.", user.Name, (success ? "has succeeded" : "has been denied")); - - return success; - } - - /// - /// Logs the user activity. - /// - /// The user. - /// Type of the client. - /// Name of the device. - /// Task. - /// user - public Task LogUserActivity(User user, ClientType clientType, string deviceName) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - var activityDate = DateTime.UtcNow; - - user.LastActivityDate = activityDate; - - LogConnection(user.Id, clientType, deviceName, activityDate); - - // Save this directly. No need to fire off all the events for this. - return Kernel.UserRepository.SaveUser(user, CancellationToken.None); - } - - /// - /// Updates the now playing item id. - /// - /// The user. - /// Type of the client. - /// Name of the device. - /// The item. - /// The current position ticks. - public void UpdateNowPlayingItemId(User user, ClientType clientType, string deviceName, BaseItem item, long? currentPositionTicks = null) - { - var conn = GetConnection(user.Id, clientType, deviceName); - - conn.NowPlayingPositionTicks = currentPositionTicks; - conn.NowPlayingItem = DtoBuilder.GetBaseItemInfo(item); - } - - /// - /// Removes the now playing item id. - /// - /// The user. - /// Type of the client. - /// Name of the device. - /// The item. - public void RemoveNowPlayingItemId(User user, ClientType clientType, string deviceName, BaseItem item) - { - var conn = GetConnection(user.Id, clientType, deviceName); - - if (conn.NowPlayingItem != null && conn.NowPlayingItem.Id.Equals(item.Id.ToString())) - { - conn.NowPlayingItem = null; - conn.NowPlayingPositionTicks = null; - } - } - - /// - /// Logs the connection. - /// - /// The user id. - /// Type of the client. - /// Name of the device. - /// The last activity date. - private void LogConnection(Guid userId, ClientType clientType, string deviceName, DateTime lastActivityDate) - { - GetConnection(userId, clientType, deviceName).LastActivityDate = lastActivityDate; - } - - /// - /// Gets the connection. - /// - /// The user id. - /// Type of the client. - /// Name of the device. - /// ClientConnectionInfo. - private ClientConnectionInfo GetConnection(Guid userId, ClientType clientType, string deviceName) - { - var conn = _activeConnections.FirstOrDefault(c => c.UserId == userId && c.ClientType == clientType && string.Equals(deviceName, c.DeviceName, StringComparison.OrdinalIgnoreCase)); - - if (conn == null) - { - conn = new ClientConnectionInfo - { - UserId = userId, - ClientType = clientType, - DeviceName = deviceName - }; - - _activeConnections.Add(conn); - } - - return conn; - } - - /// - /// Loads the users from the repository - /// - /// IEnumerable{User}. - internal IEnumerable LoadUsers() - { - var users = Kernel.UserRepository.RetrieveAllUsers().ToList(); - - // There always has to be at least one user. - if (users.Count == 0) - { - var name = Environment.UserName; - - var user = InstantiateNewUser(name); - - var task = Kernel.UserRepository.SaveUser(user, CancellationToken.None); - - // Hate having to block threads - Task.WaitAll(task); - - users.Add(user); - } - - return users; - } - - /// - /// Refreshes metadata for each user - /// - /// The cancellation token. - /// if set to true [force]. - /// Task. - public Task RefreshUsersMetadata(CancellationToken cancellationToken, bool force = false) - { - var tasks = Kernel.Users.Select(user => user.RefreshMetadata(cancellationToken, forceRefresh: force)).ToList(); - - return Task.WhenAll(tasks); - } - - /// - /// Renames the user. - /// - /// The user. - /// The new name. - /// Task. - /// user - /// - public async Task RenameUser(User user, string newName) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (string.IsNullOrEmpty(newName)) - { - throw new ArgumentNullException("newName"); - } - - if (Kernel.Users.Any(u => u.Id != user.Id && u.Name.Equals(newName, StringComparison.OrdinalIgnoreCase))) - { - throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", newName)); - } - - if (user.Name.Equals(newName, StringComparison.Ordinal)) - { - throw new ArgumentException("The new and old names must be different."); - } - - await user.Rename(newName); - - OnUserUpdated(user); - } - - /// - /// Updates the user. - /// - /// The user. - /// user - /// - public async Task UpdateUser(User user) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (user.Id == Guid.Empty || !Kernel.Users.Any(u => u.Id.Equals(user.Id))) - { - throw new ArgumentException(string.Format("User with name '{0}' and Id {1} does not exist.", user.Name, user.Id)); - } - - user.DateModified = DateTime.UtcNow; - - await Kernel.UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); - - OnUserUpdated(user); - } - - /// - /// Creates the user. - /// - /// The name. - /// User. - /// name - /// - public async Task CreateUser(string name) - { - if (string.IsNullOrEmpty(name)) - { - throw new ArgumentNullException("name"); - } - - if (Kernel.Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) - { - throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name)); - } - - var user = InstantiateNewUser(name); - - var list = Kernel.Users.ToList(); - list.Add(user); - Kernel.Users = list; - - await Kernel.UserRepository.SaveUser(user, CancellationToken.None).ConfigureAwait(false); - - return user; - } - - /// - /// Deletes the user. - /// - /// The user. - /// Task. - /// user - /// - public async Task DeleteUser(User user) - { - if (user == null) - { - throw new ArgumentNullException("user"); - } - - if (Kernel.Users.FirstOrDefault(u => u.Id == user.Id) == null) - { - throw new ArgumentException(string.Format("The user cannot be deleted because there is no user with the Name {0} and Id {1}.", user.Name, user.Id)); - } - - if (Kernel.Users.Count() == 1) - { - throw new ArgumentException(string.Format("The user '{0}' be deleted because there must be at least one user in the system.", user.Name)); - } - - await Kernel.UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); - - OnUserDeleted(user); - - // Force this to be lazy loaded again - Kernel.Users = null; - } - - /// - /// Instantiates the new user. - /// - /// The name. - /// User. - private User InstantiateNewUser(string name) - { - return new User - { - Name = name, - Id = ("MBUser" + name).GetMD5(), - DateCreated = DateTime.UtcNow, - DateModified = DateTime.UtcNow - }; - } - } -} -- cgit v1.2.3