1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.Logging;
namespace Tango.Settings
{
/// <summary>
/// Represents a settings manager capable of holding a collection of settings objects, saving and loading them using JSON.
/// </summary>
public class SettingsManager
{
#region Singleton
private static object _syncLock = new object();
private static String MUTEX_NAME = Assembly.GetEntryAssembly().GetName().Name;
private static SettingsManager _default;
/// <summary>
/// Gets the default settings manager instance.
/// </summary>
public static SettingsManager Default
{
get
{
lock (_syncLock)
{
if (_default == null)
{
_default = new SettingsManager();
}
}
return _default;
}
}
#endregion
private List<SettingsBase> _settingsCollection;
private JsonSerializerSettings _jsonSettings;
private LogManager _logManager;
private bool _loaded;
/// <summary>
/// Gets or sets the settings file path.
/// </summary>
public String FilePath { get; protected set; }
/// <summary>
/// Gets or sets the settings folder.
/// </summary>
public String Folder { get; protected set; }
/// <summary>
/// Prevents a default instance of the <see cref="SettingsManager"/> class from being created.
/// </summary>
private SettingsManager()
{
_logManager = LogManager.Default;
FilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Settings", Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName) + ".json");
Folder = Path.GetDirectoryName(FilePath);
Directory.CreateDirectory(Folder);
_settingsCollection = new List<SettingsBase>();
_jsonSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented,
Error = (sender, args) =>
{
args.ErrorContext.Handled = true;
LogManager.Default.Log(args.ErrorContext.Error.Message, LogCategory.Error);
}
};
_jsonSettings.Converters.Add(new StringEnumConverter(false));
}
private void EnsureLoaded()
{
if (!_loaded)
{
Load();
}
}
/// <summary>
/// Gets or creates the specified settings object type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T GetOrCreate<T>() where T : SettingsBase
{
try
{
EnsureLoaded();
}
catch (Exception ex)
{
_logManager.Log(ex, "Error deserializing settings for " + typeof(T).Name);
}
var settings = _settingsCollection.SingleOrDefault(x => x.GetType() == typeof(T)) as T;
if (settings == null)
{
_logManager.Log("Settings for " + typeof(T).Name + " were not found. Initializing default settings.");
settings = Activator.CreateInstance<T>();
settings.SaveAction = Save;
_settingsCollection.Add(settings);
}
return settings;
}
/// <summary>
/// Loads the settings from the <see cref="FilePath"/>.
/// </summary>
protected virtual void Load()
{
if (File.Exists(FilePath))
{
_logManager.Log("Loading settings from " + FilePath + "...");
_settingsCollection = JsonConvert.DeserializeObject<List<SettingsBase>>(File.ReadAllText(FilePath), _jsonSettings);
foreach (var settings in _settingsCollection)
{
settings.SaveAction = Save;
}
}
_loaded = true;
}
/// <summary>
/// Determines whether a settings file exists.
/// </summary>
public virtual bool IsFileExists()
{
return File.Exists(FilePath);
}
/// <summary>
/// Saves settings.
/// </summary>
public virtual void Save()
{
EnsureLoaded();
using (var mutex = new Mutex(false, MUTEX_NAME))
{
var mutexAcquired = false;
try
{
mutexAcquired = mutex.WaitOne(5000);
}
catch (AbandonedMutexException)
{
mutexAcquired = true;
}
// if it wasn't acquired, it timed out, so can handle that how ever we want
if (!mutexAcquired)
{
_logManager.Log("Error saving settings due to Mutex not acquired");
return;
}
// otherwise, we've acquired the mutex and should do what we need to do,
// then ensure that we always release the mutex
try
{
_logManager.Log("Saving settings to " + FilePath + "...");
String json = JsonConvert.SerializeObject(_settingsCollection, _jsonSettings);
File.WriteAllText(FilePath, json);
}
finally
{
mutex.ReleaseMutex();
}
}
}
}
}
|