using System; using System.IO; using TweetLib.Core.Serialization; namespace TweetDuck.Configuration.Instance{ sealed class FileConfigInstance<T> : IConfigInstance<T> where T : ConfigManager.BaseConfig{ private const string ErrorTitle = "Configuration Error"; public T Instance { get; } public FileSerializer<T> Serializer { get; } private readonly string filenameMain; private readonly string filenameBackup; private readonly string errorIdentifier; public FileConfigInstance(string filename, T instance, string errorIdentifier){ this.filenameMain = filename; this.filenameBackup = filename+".bak"; this.errorIdentifier = errorIdentifier; this.Instance = instance; this.Serializer = new FileSerializer<T>(); } private void LoadInternal(bool backup){ Serializer.Read(backup ? filenameBackup : filenameMain, Instance); } public void Load(){ Exception firstException = null; for(int attempt = 0; attempt < 2; attempt++){ try{ LoadInternal(attempt > 0); if (firstException != null){ // silently log exception that caused a backup restore Program.Reporter.LogImportant(firstException.ToString()); } return; }catch(FileNotFoundException){ }catch(DirectoryNotFoundException){ break; }catch(Exception e){ if (firstException == null){ firstException = e; } } } if (firstException is FormatException){ Program.Reporter.HandleException(ErrorTitle, "The configuration file for "+errorIdentifier+" is outdated or corrupted. If you continue, your "+errorIdentifier+" will be reset.", true, firstException); } else if (firstException is SerializationSoftException sse){ Program.Reporter.HandleException(ErrorTitle, $"{sse.Errors.Count} error{(sse.Errors.Count == 1 ? " was" : "s were")} encountered while loading the configuration file for "+errorIdentifier+". If you continue, some of your "+errorIdentifier+" will be reset.", true, firstException); } else if (firstException != null){ Program.Reporter.HandleException(ErrorTitle, "Could not open the configuration file for "+errorIdentifier+". If you continue, your "+errorIdentifier+" will be reset.", true, firstException); } } public void Save(){ try{ if (File.Exists(filenameMain)){ File.Delete(filenameBackup); File.Move(filenameMain, filenameBackup); } Serializer.Write(filenameMain, Instance); }catch(SerializationSoftException e){ Program.Reporter.HandleException(ErrorTitle, $"{e.Errors.Count} error{(e.Errors.Count == 1 ? " was" : "s were")} encountered while saving the configuration file for "+errorIdentifier+".", true, e); }catch(Exception e){ Program.Reporter.HandleException(ErrorTitle, "Could not save the configuration file for "+errorIdentifier+".", true, e); } } public void Reload(){ try{ LoadInternal(false); }catch(FileNotFoundException){ try{ Serializer.Write(filenameMain, Instance.ConstructWithDefaults<T>()); LoadInternal(false); }catch(Exception e){ Program.Reporter.HandleException(ErrorTitle, "Could not regenerate the configuration file for "+errorIdentifier+".", true, e); } }catch(Exception e){ Program.Reporter.HandleException(ErrorTitle, "Could not reload the configuration file for "+errorIdentifier+".", true, e); } } public void Reset(){ try{ File.Delete(filenameMain); File.Delete(filenameBackup); }catch(Exception e){ Program.Reporter.HandleException(ErrorTitle, "Could not delete configuration files to reset "+errorIdentifier+".", true, e); return; } Reload(); } } }