MigrateActivityLogDb.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using Emby.Server.Implementations.Data;
  6. using Jellyfin.Data.Entities;
  7. using Jellyfin.Server.Implementations;
  8. using MediaBrowser.Controller;
  9. using Microsoft.EntityFrameworkCore;
  10. using Microsoft.Extensions.Logging;
  11. using SQLitePCL.pretty;
  12. namespace Jellyfin.Server.Migrations.Routines
  13. {
  14. /// <summary>
  15. /// The migration routine for migrating the activity log database to EF Core.
  16. /// </summary>
  17. public class MigrateActivityLogDb : IMigrationRoutine
  18. {
  19. private const string DbFilename = "activitylog.db";
  20. private readonly ILogger<MigrateActivityLogDb> _logger;
  21. private readonly JellyfinDbProvider _provider;
  22. private readonly IServerApplicationPaths _paths;
  23. /// <summary>
  24. /// Initializes a new instance of the <see cref="MigrateActivityLogDb"/> class.
  25. /// </summary>
  26. /// <param name="logger">The logger.</param>
  27. /// <param name="paths">The server application paths.</param>
  28. /// <param name="provider">The database provider.</param>
  29. public MigrateActivityLogDb(ILogger<MigrateActivityLogDb> logger, IServerApplicationPaths paths, JellyfinDbProvider provider)
  30. {
  31. _logger = logger;
  32. _provider = provider;
  33. _paths = paths;
  34. }
  35. /// <inheritdoc/>
  36. public Guid Id => Guid.Parse("3793eb59-bc8c-456c-8b9f-bd5a62a42978");
  37. /// <inheritdoc/>
  38. public string Name => "MigrateActivityLogDatabase";
  39. /// <inheritdoc/>
  40. public void Perform()
  41. {
  42. var logLevelDictionary = new Dictionary<string, LogLevel>(StringComparer.OrdinalIgnoreCase)
  43. {
  44. { "None", LogLevel.None },
  45. { "Trace", LogLevel.Trace },
  46. { "Debug", LogLevel.Debug },
  47. { "Information", LogLevel.Information },
  48. { "Info", LogLevel.Information },
  49. { "Warn", LogLevel.Warning },
  50. { "Warning", LogLevel.Warning },
  51. { "Error", LogLevel.Error },
  52. { "Critical", LogLevel.Critical }
  53. };
  54. var dataPath = _paths.DataPath;
  55. using (var connection = SQLite3.Open(
  56. Path.Combine(dataPath, DbFilename),
  57. ConnectionFlags.ReadOnly,
  58. null))
  59. {
  60. _logger.LogWarning("Migrating the activity database may take a while, do not stop Jellyfin.");
  61. using var dbContext = _provider.CreateContext();
  62. var queryResult = connection.Query("SELECT * FROM ActivityLog ORDER BY Id ASC");
  63. // Make sure that the database is empty in case of failed migration due to power outages, etc.
  64. dbContext.ActivityLogs.RemoveRange(dbContext.ActivityLogs);
  65. dbContext.SaveChanges();
  66. // Reset the autoincrement counter
  67. dbContext.Database.ExecuteSqlRaw("UPDATE sqlite_sequence SET seq = 0 WHERE name = 'ActivityLog';");
  68. dbContext.SaveChanges();
  69. var newEntries = queryResult.Select(entry =>
  70. {
  71. if (!logLevelDictionary.TryGetValue(entry[8].ToString(), out var severity))
  72. {
  73. severity = LogLevel.Trace;
  74. }
  75. var newEntry = new ActivityLog(
  76. entry[1].ToString(),
  77. entry[4].ToString(),
  78. entry[6].SQLiteType == SQLiteType.Null ? Guid.Empty : Guid.Parse(entry[6].ToString()))
  79. {
  80. DateCreated = entry[7].ReadDateTime(),
  81. LogSeverity = severity
  82. };
  83. if (entry[2].SQLiteType != SQLiteType.Null)
  84. {
  85. newEntry.Overview = entry[2].ToString();
  86. }
  87. if (entry[3].SQLiteType != SQLiteType.Null)
  88. {
  89. newEntry.ShortOverview = entry[3].ToString();
  90. }
  91. if (entry[5].SQLiteType != SQLiteType.Null)
  92. {
  93. newEntry.ItemId = entry[5].ToString();
  94. }
  95. return newEntry;
  96. });
  97. dbContext.ActivityLogs.AddRange(newEntries);
  98. dbContext.SaveChanges();
  99. }
  100. try
  101. {
  102. File.Move(Path.Combine(dataPath, DbFilename), Path.Combine(dataPath, DbFilename + ".old"));
  103. var journalPath = Path.Combine(dataPath, DbFilename + "-journal");
  104. if (File.Exists(journalPath))
  105. {
  106. File.Move(journalPath, Path.Combine(dataPath, DbFilename + ".old-journal"));
  107. }
  108. }
  109. catch (IOException e)
  110. {
  111. _logger.LogError(e, "Error renaming legacy activity log database to 'activitylog.db.old'");
  112. }
  113. }
  114. }
  115. }