From a88ce6495185e7e63c5c1362c7e3f8660b89333d Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 5 Mar 2020 23:27:41 +0800 Subject: Migrate avatar service. TODO: Migrate database. --- Timeline/Entities/UserAvatarEntity.cs | 7 +- .../Resources/Services/DataManager.Designer.cs | 72 ++++++++++++ Timeline/Resources/Services/DataManager.resx | 123 +++++++++++++++++++++ Timeline/Services/DataManager.cs | 2 +- Timeline/Services/UserAvatarService.cs | 43 +++---- Timeline/Timeline.csproj | 9 ++ 6 files changed, 230 insertions(+), 26 deletions(-) create mode 100644 Timeline/Resources/Services/DataManager.Designer.cs create mode 100644 Timeline/Resources/Services/DataManager.resx diff --git a/Timeline/Entities/UserAvatarEntity.cs b/Timeline/Entities/UserAvatarEntity.cs index be094a77..3c2720f7 100644 --- a/Timeline/Entities/UserAvatarEntity.cs +++ b/Timeline/Entities/UserAvatarEntity.cs @@ -11,15 +11,12 @@ namespace Timeline.Entities [Column("id"), Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] public long Id { get; set; } - [Column("data")] - public byte[]? Data { get; set; } + [Column("data_tag")] + public string? DataTag { get; set; } [Column("type")] public string? Type { get; set; } - [Column("etag")] - public string? ETag { get; set; } - [Column("last_modified"), Required] public DateTime LastModified { get; set; } diff --git a/Timeline/Resources/Services/DataManager.Designer.cs b/Timeline/Resources/Services/DataManager.Designer.cs new file mode 100644 index 00000000..0872059a --- /dev/null +++ b/Timeline/Resources/Services/DataManager.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Timeline.Resources.Services { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class DataManager { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal DataManager() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Resources.Services.DataManager", typeof(DataManager).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Entry with given tag does not exist.. + /// + internal static string ExceptionEntryNotExist { + get { + return ResourceManager.GetString("ExceptionEntryNotExist", resourceCulture); + } + } + } +} diff --git a/Timeline/Resources/Services/DataManager.resx b/Timeline/Resources/Services/DataManager.resx new file mode 100644 index 00000000..688e0e96 --- /dev/null +++ b/Timeline/Resources/Services/DataManager.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Entry with given tag does not exist. + + \ No newline at end of file diff --git a/Timeline/Services/DataManager.cs b/Timeline/Services/DataManager.cs index 66aa6f81..d6b8b6a4 100644 --- a/Timeline/Services/DataManager.cs +++ b/Timeline/Services/DataManager.cs @@ -115,7 +115,7 @@ namespace Timeline.Services var entity = await _database.Data.Where(d => d.Tag == tag).Select(d => new { d.Data }).SingleOrDefaultAsync(); if (entity == null) - throw new InvalidOperationException("Entry with given tag does not exist."); + throw new InvalidOperationException(Resources.Services.DataManager.ExceptionEntryNotExist); return entity.Data; } diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs index 39b408e6..5a07da96 100644 --- a/Timeline/Services/UserAvatarService.cs +++ b/Timeline/Services/UserAvatarService.cs @@ -164,7 +164,7 @@ namespace Timeline.Services private readonly IDefaultUserAvatarProvider _defaultUserAvatarProvider; private readonly IUserAvatarValidator _avatarValidator; - private readonly IETagGenerator _eTagGenerator; + private readonly IDataManager _dataManager; private readonly IClock _clock; @@ -173,20 +173,20 @@ namespace Timeline.Services DatabaseContext database, IDefaultUserAvatarProvider defaultUserAvatarProvider, IUserAvatarValidator avatarValidator, - IETagGenerator eTagGenerator, + IDataManager dataManager, IClock clock) { _logger = logger; _database = database; _defaultUserAvatarProvider = defaultUserAvatarProvider; _avatarValidator = avatarValidator; - _eTagGenerator = eTagGenerator; + _dataManager = dataManager; _clock = clock; } public async Task GetAvatarETag(long id) { - var eTag = (await _database.UserAvatars.Where(a => a.UserId == id).Select(a => new { a.ETag }).SingleOrDefaultAsync())?.ETag; + var eTag = (await _database.UserAvatars.Where(a => a.UserId == id).Select(a => new { a.DataTag }).SingleOrDefaultAsync())?.DataTag; if (eTag == null) return await _defaultUserAvatarProvider.GetDefaultAvatarETag(); else @@ -195,25 +195,27 @@ namespace Timeline.Services public async Task GetAvatar(long id) { - var avatarEntity = await _database.UserAvatars.Where(a => a.UserId == id).Select(a => new { a.Type, a.Data, a.LastModified }).SingleOrDefaultAsync(); + var avatarEntity = await _database.UserAvatars.Where(a => a.UserId == id).Select(a => new { a.Type, a.DataTag, a.LastModified }).SingleOrDefaultAsync(); if (avatarEntity != null) { - if (!LanguageHelper.AreSame(avatarEntity.Data == null, avatarEntity.Type == null)) + if (!LanguageHelper.AreSame(avatarEntity.DataTag == null, avatarEntity.Type == null)) { var message = Resources.Services.UserAvatarService.ExceptionDatabaseCorruptedDataAndTypeNotSame; _logger.LogCritical(message); throw new DatabaseCorruptedException(message); } - if (avatarEntity.Data != null) + + if (avatarEntity.DataTag != null) { + var data = await _dataManager.GetEntry(avatarEntity.DataTag); return new AvatarInfo { Avatar = new Avatar { Type = avatarEntity.Type!, - Data = avatarEntity.Data + Data = data }, LastModified = avatarEntity.LastModified }; @@ -239,15 +241,15 @@ namespace Timeline.Services if (avatar == null) { - if (avatarEntity == null || avatarEntity.Data == null) + if (avatarEntity == null || avatarEntity.DataTag == null) { return; } else { - avatarEntity.Data = null; + await _dataManager.FreeEntry(avatarEntity.DataTag); + avatarEntity.DataTag = null; avatarEntity.Type = null; - avatarEntity.ETag = null; avatarEntity.LastModified = _clock.GetCurrentTime(); await _database.SaveChangesAsync(); _logger.LogInformation(Resources.Services.UserAvatarService.LogUpdateEntity); @@ -256,24 +258,26 @@ namespace Timeline.Services else { await _avatarValidator.Validate(avatar); + var oldTag = avatarEntity?.DataTag; var create = avatarEntity == null; - if (create) + if (avatarEntity == null) { avatarEntity = new UserAvatarEntity(); + _database.UserAvatars.Add(avatarEntity); } - avatarEntity!.Type = avatar.Type; - avatarEntity.Data = avatar.Data; - avatarEntity.ETag = await _eTagGenerator.Generate(avatar.Data); + var tag = await _dataManager.RetainEntry(avatar.Data); + avatarEntity.DataTag = tag; + avatarEntity.Type = avatar.Type; avatarEntity.LastModified = _clock.GetCurrentTime(); avatarEntity.UserId = id; - if (create) - { - _database.UserAvatars.Add(avatarEntity); - } await _database.SaveChangesAsync(); _logger.LogInformation(create ? Resources.Services.UserAvatarService.LogCreateEntity : Resources.Services.UserAvatarService.LogUpdateEntity); + if (oldTag != null) + { + await _dataManager.FreeEntry(oldTag); + } } } } @@ -282,7 +286,6 @@ namespace Timeline.Services { public static void AddUserAvatarService(this IServiceCollection services) { - services.TryAddTransient(); services.AddScoped(); services.AddSingleton(); services.AddTransient(); diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj index 2dcc3c9f..72bc1572 100644 --- a/Timeline/Timeline.csproj +++ b/Timeline/Timeline.csproj @@ -97,6 +97,11 @@ True Validator.resx + + True + True + DataManager.resx + True True @@ -174,6 +179,10 @@ ResXFileCodeGenerator Validator.Designer.cs + + ResXFileCodeGenerator + DataManager.Designer.cs + ResXFileCodeGenerator Exception.Designer.cs -- cgit v1.2.3