diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index d267d58..045237c 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -10,6 +10,7 @@ namespace ChatTwo; [Serializable] internal class Configuration : IPluginConfiguration { private const int LatestVersion = 5; + internal const int LatestDbVersion = 1; public int Version { get; set; } = LatestVersion; @@ -49,7 +50,7 @@ internal class Configuration : IPluginConfiguration { public Dictionary ChatColours = new(); public List Tabs = new(); - public uint DatabaseMigration; + public uint DatabaseMigration = LatestDbVersion; internal void UpdateFrom(Configuration other) { this.HideChat = other.HideChat; diff --git a/ChatTwo/PluginUi.cs b/ChatTwo/PluginUi.cs index 05fec24..f6aa343 100755 --- a/ChatTwo/PluginUi.cs +++ b/ChatTwo/PluginUi.cs @@ -130,6 +130,10 @@ internal sealed class PluginUi : IDisposable { } private void Draw() { + if (this.Plugin.Config.DatabaseMigration != Configuration.LatestDbVersion) { + return; + } + this.Plugin.Interface.UiBuilder.DisableUserUiHide = !this.Plugin.Config.HideWhenUiHidden; this.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text]; diff --git a/ChatTwo/Resources/Language.Designer.cs b/ChatTwo/Resources/Language.Designer.cs index 9524eb1..6cf8d03 100755 --- a/ChatTwo/Resources/Language.Designer.cs +++ b/ChatTwo/Resources/Language.Designer.cs @@ -1502,5 +1502,29 @@ namespace ChatTwo.Resources { return ResourceManager.GetString("Options_Tabs_ExtraChatAll", resourceCulture); } } + + internal static string Migration_Line1 { + get { + return ResourceManager.GetString("Migration_Line1", resourceCulture); + } + } + + internal static string Migration_Line2 { + get { + return ResourceManager.GetString("Migration_Line2", resourceCulture); + } + } + + internal static string Migration_Line3 { + get { + return ResourceManager.GetString("Migration_Line3", resourceCulture); + } + } + + internal static string Migration_Line4 { + get { + return ResourceManager.GetString("Migration_Line4", resourceCulture); + } + } } } diff --git a/ChatTwo/Resources/Language.resx b/ChatTwo/Resources/Language.resx index 6373b05..7816daa 100644 --- a/ChatTwo/Resources/Language.resx +++ b/ChatTwo/Resources/Language.resx @@ -851,4 +851,16 @@ All + + Chat 2 is performing a database migration. + + + Chat 2 and the plugin installer will be unavailable until it is complete. + + + This may take a few minutes depending on the size of your chat database. + + + Do not close FFXIV, unload Dalamud, or turn off your computer during this time. + diff --git a/ChatTwo/Store.cs b/ChatTwo/Store.cs index ecd5a97..ade2088 100755 --- a/ChatTwo/Store.cs +++ b/ChatTwo/Store.cs @@ -1,11 +1,14 @@ using System.Collections.Concurrent; using System.Diagnostics; +using System.Numerics; using ChatTwo.Code; +using ChatTwo.Resources; using ChatTwo.Util; using Dalamud.Game; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Logging; +using ImGuiNET; using LiteDB; using Lumina.Excel.GeneratedSheets; @@ -139,46 +142,7 @@ internal class Store : IDisposable { this.Messages.EnsureIndex(msg => msg.SortCode); this.Messages.EnsureIndex(msg => msg.ExtraChatChannel); - // re-save all messages, which will add the ExtraChat channel - if (this.Plugin.Config.DatabaseMigration == 0) { - var total = (float) this.Messages.LongCount() / 10_000.0; - var rounds = (long) Math.Ceiling(total); - var lastId = ObjectId.Empty; - for (var i = 0; i < rounds; i++) { - PluginLog.Log($"Update round {i}/{rounds}"); - var messages = this.Messages.Query() - .OrderBy(msg => msg.Id) - .Where(msg => msg.Id > lastId) - .Limit(10_000) - .ToArray(); - - foreach (var message in messages) { - this.Messages.Update(message); - lastId = message.Id; - } - } - - this.Database.Checkpoint(); - - this.Plugin.Config.DatabaseMigration = 1; - this.Plugin.SaveConfig(); - - BsonMapper.Global.Entity() - .Id(msg => msg.Id) - .Ctor(doc => new Message( - doc["_id"].AsObjectId, - (ulong) doc["Receiver"].AsInt64, - (ulong) doc["ContentId"].AsInt64, - DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64), - doc["Code"].AsDocument, - doc["Sender"].AsArray, - doc["Content"].AsArray, - doc["SenderSource"], - doc["ContentSource"], - doc["SortCode"].AsDocument, - doc["ExtraChatChannel"] - )); - } + this.MigrateWrapper(); this.Plugin.ChatGui.ChatMessageUnhandled += this.ChatMessage; this.Plugin.Framework.Update += this.GetMessageInfo; @@ -241,6 +205,87 @@ internal class Store : IDisposable { } } + private long _migrateCurrent; + private long _migrateMax; + + private void MigrateDraw() { + ImGui.SetNextWindowSizeConstraints(new Vector2(450, 0), new Vector2(450, float.MaxValue)); + if (!ImGui.Begin($"{this.Plugin.Name}##migration-window", ImGuiWindowFlags.AlwaysAutoResize)) { + ImGui.End(); + return; + } + + ImGui.PushTextWrapPos(); + ImGui.TextUnformatted(Language.Migration_Line1); + ImGui.TextUnformatted(Language.Migration_Line2); + ImGui.TextUnformatted(Language.Migration_Line3); + ImGui.TextUnformatted(Language.Migration_Line4); + ImGui.PopTextWrapPos(); + + ImGui.Spacing(); + ImGui.ProgressBar((float) this._migrateCurrent / this._migrateMax, new Vector2(-1, 0), $"{this._migrateCurrent} / {this._migrateMax}"); + + ImGui.End(); + } + + internal void MigrateWrapper() { + if (this.Plugin.Config.DatabaseMigration < Configuration.LatestDbVersion) { + this.Plugin.Interface.UiBuilder.Draw += this.MigrateDraw; + } + + try { + this.Migrate(); + } finally { + this.Plugin.Interface.UiBuilder.Draw -= this.MigrateDraw; + } + } + + internal void Migrate() { + // re-save all messages, which will add the ExtraChat channel + if (this.Plugin.Config.DatabaseMigration == 0) { + var total = (float) this.Messages.LongCount() / 10_000.0; + var rounds = (long) Math.Ceiling(total); + this._migrateMax = rounds; + + var lastId = ObjectId.Empty; + for (var i = 0; i < rounds; i++) { + this._migrateCurrent = i + 1; + PluginLog.Log($"Update round {i + 1}/{rounds}"); + var messages = this.Messages.Query() + .OrderBy(msg => msg.Id) + .Where(msg => msg.Id > lastId) + .Limit(10_000) + .ToArray(); + + foreach (var message in messages) { + this.Messages.Update(message); + lastId = message.Id; + } + } + + this.Database.Checkpoint(); + + BsonMapper.Global.Entity() + .Id(msg => msg.Id) + .Ctor(doc => new Message( + doc["_id"].AsObjectId, + (ulong) doc["Receiver"].AsInt64, + (ulong) doc["ContentId"].AsInt64, + DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64), + doc["Code"].AsDocument, + doc["Sender"].AsArray, + doc["Content"].AsArray, + doc["SenderSource"], + doc["ContentSource"], + doc["SortCode"].AsDocument, + doc["ExtraChatChannel"] + )); + + this.Plugin.Config.DatabaseMigration = 1; + this.Plugin.SaveConfig(); + } + } + internal void AddMessage(Message message, Tab? currentTab) { if (this.Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle()) { this.Messages.Insert(message);