diff --git a/IPA.Loader/Config/Config.cs b/IPA.Loader/Config/Config.cs index 90564ea9..a9114a19 100644 --- a/IPA.Loader/Config/Config.cs +++ b/IPA.Loader/Config/Config.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using IPA.Config.Providers; using IPA.Utilities; #if NET3 @@ -19,7 +20,7 @@ namespace IPA.Config { static Config() { - JsonConfigProvider.RegisterConfig(); + //JsonConfigProvider.RegisterConfig(); } /// @@ -110,19 +111,18 @@ namespace IPA.Config /// the type to register public static void Register(Type type) { - if (!(type.GetCustomAttribute(typeof(TypeAttribute)) is TypeAttribute ext)) - throw new InvalidOperationException("Type does not have TypeAttribute"); + var inst = Activator.CreateInstance(type) as IConfigProvider; + if (inst == null) + throw new ArgumentException($"Type not an {nameof(IConfigProvider)}"); - if (!typeof(IConfigProvider).IsAssignableFrom(type)) - throw new InvalidOperationException("Type not IConfigProvider"); + if (registeredProviders.ContainsKey(inst.Extension)) + throw new InvalidOperationException($"Extension provider for {inst.Extension} already exists"); - if (registeredProviders.ContainsKey(ext.Extension)) - throw new InvalidOperationException($"Extension provider for {ext.Extension} already exists"); - - registeredProviders.Add(ext.Extension, type); + registeredProviders.Add(inst.Extension, type); } - private static List, IConfigProvider>> configProviders = new List, IConfigProvider>>(); + private static List configProviders = new List(); + private static ConditionalWeakTable file = new ConditionalWeakTable(); /// /// Gets an using the specified list of preferred config types. @@ -135,11 +135,9 @@ namespace IPA.Config var chosenExt = extensions.FirstOrDefault(s => registeredProviders.ContainsKey(s)) ?? "json"; var type = registeredProviders[chosenExt]; var provider = Activator.CreateInstance(type) as IConfigProvider; - if (provider != null) - { - provider.Filename = Path.Combine(BeatSaber.UserDataPath, configName); - configProviders.Add(Tuple.Create(Ref.Create(provider.LastModified), provider)); - } + configProviders.Add(provider); + + // TODO: rething this one a bit return provider; } @@ -154,108 +152,5 @@ namespace IPA.Config return GetProviderFor(modName, prefs); } - - private static Dictionary linkedProviders = - new Dictionary(); - - /// - /// Creates a linked for the config provider. This will be automatically updated whenever the file on-disk changes. - /// - /// the type of the parsed value - /// the to create a link to - /// an action to perform on value change - /// a to an ever-changing value, mirroring whatever the file contains. - public static Ref MakeLink(this IConfigProvider config, Action> onChange = null) - { // TODO: rework this stuff - Ref @ref = config.Parse(); - void ChangeDelegate() - { - @ref.Value = config.Parse(); - onChange?.Invoke(config, @ref); - } - - if (linkedProviders.ContainsKey(config)) - linkedProviders[config] = (Action) Delegate.Combine(linkedProviders[config], (Action) ChangeDelegate); - else - linkedProviders.Add(config, ChangeDelegate); - - ChangeDelegate(); - - return @ref; - } - - /// - /// Removes all linked such that they are no longer updated. - /// - /// the to unlink - public static void RemoveLinks(this IConfigProvider config) - { - if (linkedProviders.ContainsKey(config)) - linkedProviders.Remove(config); - } - - internal static void Update() - { - foreach (var provider in configProviders) - { - if (provider.Item2.LastModified > provider.Item1.Value) - { - try - { - provider.Item2.Load(); // auto reload if it changes - provider.Item1.Value = provider.Item2.LastModified; - } - catch (Exception e) - { - Logging.Logger.config.Error("Error when trying to load config"); - Logging.Logger.config.Error(e); - } - } - if (provider.Item2.HasChanged) - { - try - { - provider.Item2.Save(); - provider.Item1.Value = Utils.CurrentTime(); - } - catch (Exception e) - { - Logging.Logger.config.Error("Error when trying to save config"); - Logging.Logger.config.Error(e); - } - } - - if (provider.Item2.InMemoryChanged) - { - provider.Item2.InMemoryChanged = false; - try - { - if (linkedProviders.ContainsKey(provider.Item2)) - linkedProviders[provider.Item2](); - } - catch (Exception e) - { - Logging.Logger.config.Error("Error running link change events"); - Logging.Logger.config.Error(e); - } - } - } - } - - internal static void Save() - { - foreach (var provider in configProviders) - if (provider.Item2.HasChanged) - try - { - provider.Item2.Save(); - } - catch (Exception e) - { - Logging.Logger.config.Error("Error when trying to save config"); - Logging.Logger.config.Error(e); - } - } - } } diff --git a/IPA.Loader/Config/IConfigProvider.cs b/IPA.Loader/Config/IConfigProvider.cs index 69ff72c8..710145f6 100644 --- a/IPA.Loader/Config/IConfigProvider.cs +++ b/IPA.Loader/Config/IConfigProvider.cs @@ -1,63 +1,49 @@ using System; -// ReSharper disable UnusedMember.Global +using System.IO; +using IPA.Config.Data; namespace IPA.Config { /// /// An interface for configuration providers. /// + /// + /// Implementers must provide a default constructor. Do not assume that will ever be set for a given object. + /// public interface IConfigProvider - { // TODO: rework this + { /// - /// Loads the data provided by this into an object of type . + /// Gets the extension without a dot to use for files handled by this provider. /// - /// the type of the object to parse into - /// the values from the config provider parsed into the object - T Parse(); - /// - /// Stores the data from into the . - /// - /// the type of - /// the object containing the data to save - void Store(T obj); + /// + /// This must work immediately, and is used to generate the used to set + /// . + /// + string Extension { get; } -#if NET4 /// - /// Gets a dynamic object providing access to the configuration. + /// Sets the file that this provider will read and write to. /// - /// a dynamically bound object to use to access config values directly - dynamic Dynamic { get; } -#endif + /// + /// The provider is expected to gracefully handle this changing at any point, + /// and is expected to close any old file handles when this is reassigned. + /// This may be set to the same file multiple times in this object's lifetime. + /// This will always have been set at least once before any calls to + /// or are made. + /// + FileInfo File { set; } -#region State getters - /// - /// Returns if object has changed since the last save - /// - /// if object has changed since the last save, else - bool HasChanged { get; } - /// - /// Returns if the data in memory has been changed - notably including loads. - /// - /// if the data in memory has been changed, else - bool InMemoryChanged { get; set; } /// - /// Will be set with the filename (no extension) to save to. When saving, the implementation should add the appropriate extension. Should error if set multiple times. + /// Stores the given to disk in the format specified. /// - /// the extensionless filename to save to - string Filename { set; } - /// - /// Gets the last time the config was modified. - /// - /// the last time the config file was modified - DateTime LastModified { get; } - /// - /// Saves configuration to file. Should error if not a root object. - /// - void Save(); + /// the to store + void Store(Value value); + /// - /// Loads the state of the file on disk. + /// Loads a from disk in whatever format this provider provides + /// and returns it. /// - void Load(); -#endregion + /// the loaded + Value Load(); } } diff --git a/IPA.Loader/Config/Providers/JsonConfigProvider.cs b/IPA.Loader/Config/Providers/JsonConfigProvider.cs index 7daa9227..1ef6e04a 100644 --- a/IPA.Loader/Config/Providers/JsonConfigProvider.cs +++ b/IPA.Loader/Config/Providers/JsonConfigProvider.cs @@ -7,8 +7,8 @@ using System.ComponentModel; using System.IO; namespace IPA.Config.Providers -{ - [Config.Type("json")] +{ // TODO: implement this for the new provider system + /*[Config.Type("json")] internal class JsonConfigProvider : IConfigProvider { public static void RegisterConfig() @@ -123,5 +123,5 @@ namespace IPA.Config.Providers HasChanged = true; InMemoryChanged = true; } - } + }*/ } \ No newline at end of file