using System.Collections.Generic; using MediaBrowser.Common.Events; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.Library { /// /// Class UserDataManager /// public class UserDataManager : IUserDataManager { public event EventHandler UserDataSaved; private readonly ConcurrentDictionary _userData = new ConcurrentDictionary(); private readonly ILogger _logger; public UserDataManager(ILogManager logManager) { _logger = logManager.GetLogger(GetType().Name); } /// /// Gets or sets the repository. /// /// The repository. public IUserDataRepository Repository { get; set; } /// /// Saves the user data. /// /// The user id. /// The item. /// The user data. /// The reason. /// The cancellation token. /// Task. /// userData /// or /// cancellationToken /// or /// userId /// or /// key public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken) { if (userData == null) { throw new ArgumentNullException("userData"); } if (item == null) { throw new ArgumentNullException("item"); } if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } cancellationToken.ThrowIfCancellationRequested(); var key = item.GetUserDataKey(); try { await Repository.SaveUserData(userId, key, userData, cancellationToken).ConfigureAwait(false); var newValue = userData; // Once it succeeds, put it into the dictionary to make it available to everyone else _userData.AddOrUpdate(GetCacheKey(userId, key), newValue, delegate { return newValue; }); } catch (Exception ex) { _logger.ErrorException("Error saving user data", ex); throw; } EventHelper.FireEventIfNotNull(UserDataSaved, this, new UserDataSaveEventArgs { Key = key, UserData = userData, SaveReason = reason, UserId = userId, Item = item }, _logger); } /// /// Save the provided user data for the given user. Batch operation. Does not fire any events or update the cache. /// /// /// /// /// public async Task SaveAllUserData(Guid userId, IEnumerable userData, CancellationToken cancellationToken) { if (userData == null) { throw new ArgumentNullException("userData"); } if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } cancellationToken.ThrowIfCancellationRequested(); try { await Repository.SaveAllUserData(userId, userData, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error saving user data", ex); throw; } } /// /// Retrieve all user data for the given user /// /// /// public IEnumerable GetAllUserData(Guid userId) { if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } return Repository.GetAllUserData(userId); } /// /// Gets the user data. /// /// The user id. /// The key. /// Task{UserItemData}. public UserItemData GetUserData(Guid userId, string key) { if (userId == Guid.Empty) { throw new ArgumentNullException("userId"); } if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException("key"); } return _userData.GetOrAdd(GetCacheKey(userId, key), keyName => Repository.GetUserData(userId, key)); } /// /// Gets the internal key. /// /// The user id. /// The key. /// System.String. private string GetCacheKey(Guid userId, string key) { return userId + key; } public UserItemDataDto GetUserDataDto(IHasUserData item, User user) { var userData = GetUserData(user.Id, item.GetUserDataKey()); var dto = GetUserItemDataDto(userData); item.FillUserDataDtoValues(dto, userData, user); return dto; } /// /// Converts a UserItemData to a DTOUserItemData /// /// The data. /// DtoUserItemData. /// private UserItemDataDto GetUserItemDataDto(UserItemData data) { if (data == null) { throw new ArgumentNullException("data"); } return new UserItemDataDto { IsFavorite = data.IsFavorite, Likes = data.Likes, PlaybackPositionTicks = data.PlaybackPositionTicks, PlayCount = data.PlayCount, Rating = data.Rating, Played = data.Played, LastPlayedDate = data.LastPlayedDate, Key = data.Key }; } } }