Skip to content

Commit b042111

Browse files
added modular configuration
1 parent 69e9f9a commit b042111

39 files changed

+635
-165
lines changed

MediaBrowser.Api/ConfigurationService.cs

+37-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
using MediaBrowser.Model.Configuration;
99
using MediaBrowser.Model.Serialization;
1010
using ServiceStack;
11+
using ServiceStack.Text.Controller;
12+
using ServiceStack.Web;
1113
using System;
1214
using System.Collections.Generic;
15+
using System.IO;
1316
using System.Linq;
1417

1518
namespace MediaBrowser.Api
@@ -23,6 +26,13 @@ public class GetConfiguration : IReturn<ServerConfiguration>
2326

2427
}
2528

29+
[Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")]
30+
public class GetNamedConfiguration
31+
{
32+
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
33+
public string Key { get; set; }
34+
}
35+
2636
/// <summary>
2737
/// Class UpdateConfiguration
2838
/// </summary>
@@ -31,6 +41,15 @@ public class UpdateConfiguration : ServerConfiguration, IReturnVoid
3141
{
3242
}
3343

44+
[Route("/System/Configuration/{Key}", "POST", Summary = "Updates named configuration")]
45+
public class UpdateNamedConfiguration : IReturnVoid, IRequiresRequestStream
46+
{
47+
[ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
48+
public string Key { get; set; }
49+
50+
public Stream RequestStream { get; set; }
51+
}
52+
3453
[Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")]
3554
public class GetDefaultMetadataOptions : IReturn<MetadataOptions>
3655
{
@@ -88,21 +107,38 @@ public object Get(GetConfiguration request)
88107
return ToOptimizedResultUsingCache(cacheKey, dateModified, null, () => _configurationManager.Configuration);
89108
}
90109

110+
public object Get(GetNamedConfiguration request)
111+
{
112+
var result = _configurationManager.GetConfiguration(request.Key);
113+
114+
return ToOptimizedResult(result);
115+
}
116+
91117
/// <summary>
92118
/// Posts the specified configuraiton.
93119
/// </summary>
94120
/// <param name="request">The request.</param>
95121
public void Post(UpdateConfiguration request)
96122
{
97123
// Silly, but we need to serialize and deserialize or the XmlSerializer will write the xml with an element name of UpdateConfiguration
98-
99124
var json = _jsonSerializer.SerializeToString(request);
100125

101126
var config = _jsonSerializer.DeserializeFromString<ServerConfiguration>(json);
102127

103128
_configurationManager.ReplaceConfiguration(config);
104129
}
105130

131+
public void Post(UpdateNamedConfiguration request)
132+
{
133+
var pathInfo = PathInfo.Parse(Request.PathInfo);
134+
var key = pathInfo.GetArgumentValue<string>(2);
135+
136+
var configurationType = _configurationManager.GetConfigurationType(key);
137+
var configuration = _jsonSerializer.DeserializeFromStream(request.RequestStream, configurationType);
138+
139+
_configurationManager.SaveConfiguration(key, configuration);
140+
}
141+
106142
public object Get(GetDefaultMetadataOptions request)
107143
{
108144
return ToOptimizedSerializedResultUsingCache(new MetadataOptions());

MediaBrowser.Api/Dlna/DlnaServerService.cs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using MediaBrowser.Controller.Dlna;
1+
using MediaBrowser.Common.Configuration;
2+
using MediaBrowser.Controller.Dlna;
3+
using MediaBrowser.Model.Configuration;
24
using ServiceStack;
35
using ServiceStack.Text.Controller;
46
using ServiceStack.Web;
@@ -76,11 +78,14 @@ public class DlnaServerService : BaseApiService
7678
private readonly IContentDirectory _contentDirectory;
7779
private readonly IConnectionManager _connectionManager;
7880

79-
public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager)
81+
private readonly IConfigurationManager _config;
82+
83+
public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IConnectionManager connectionManager, IConfigurationManager config)
8084
{
8185
_dlnaManager = dlnaManager;
8286
_contentDirectory = contentDirectory;
8387
_connectionManager = connectionManager;
88+
_config = config;
8489
}
8590

8691
public object Get(GetDescriptionXml request)

MediaBrowser.Api/MediaBrowser.Api.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
<Compile Include="NotificationsService.cs" />
102102
<Compile Include="PackageReviewService.cs" />
103103
<Compile Include="PackageService.cs" />
104+
<Compile Include="Playback\BifService.cs" />
104105
<Compile Include="Playback\EndlessStreamCopy.cs" />
105106
<Compile Include="Playback\Hls\BaseHlsService.cs" />
106107
<Compile Include="Playback\Hls\DynamicHlsService.cs" />

MediaBrowser.Common.Implementations/BaseApplicationHost.cs

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ private void ConfigureAutorun()
342342
/// </summary>
343343
protected virtual void FindParts()
344344
{
345+
ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
345346
Plugins = GetExports<IPlugin>();
346347
}
347348

MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs

+82-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
using System.IO;
2-
using MediaBrowser.Common.Configuration;
1+
using MediaBrowser.Common.Configuration;
32
using MediaBrowser.Common.Events;
43
using MediaBrowser.Model.Configuration;
54
using MediaBrowser.Model.Logging;
65
using MediaBrowser.Model.Serialization;
76
using System;
7+
using System.Collections.Concurrent;
8+
using System.Collections.Generic;
9+
using System.IO;
10+
using System.Linq;
811
using System.Threading;
912

1013
namespace MediaBrowser.Common.Implementations.Configuration
@@ -25,6 +28,11 @@ public abstract class BaseConfigurationManager : IConfigurationManager
2528
/// </summary>
2629
public event EventHandler<EventArgs> ConfigurationUpdated;
2730

31+
/// <summary>
32+
/// Occurs when [named configuration updated].
33+
/// </summary>
34+
public event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
35+
2836
/// <summary>
2937
/// Gets the logger.
3038
/// </summary>
@@ -74,6 +82,9 @@ protected set
7482
}
7583
}
7684

85+
private ConfigurationStore[] _configurationStores = {};
86+
private IConfigurationFactory[] _configurationFactories;
87+
7788
/// <summary>
7889
/// Initializes a new instance of the <see cref="BaseConfigurationManager" /> class.
7990
/// </summary>
@@ -89,10 +100,14 @@ protected BaseConfigurationManager(IApplicationPaths applicationPaths, ILogManag
89100
UpdateCachePath();
90101
}
91102

92-
/// <summary>
93-
/// The _save lock
94-
/// </summary>
95-
private readonly object _configurationSaveLock = new object();
103+
public void AddParts(IEnumerable<IConfigurationFactory> factories)
104+
{
105+
_configurationFactories = factories.ToArray();
106+
107+
_configurationStores = _configurationFactories
108+
.SelectMany(i => i.GetConfigurations())
109+
.ToArray();
110+
}
96111

97112
/// <summary>
98113
/// Saves the configuration.
@@ -103,7 +118,7 @@ public void SaveConfiguration()
103118

104119
Directory.CreateDirectory(Path.GetDirectoryName(path));
105120

106-
lock (_configurationSaveLock)
121+
lock (_configurationSyncLock)
107122
{
108123
XmlSerializer.SerializeToFile(CommonConfiguration, path);
109124
}
@@ -144,8 +159,8 @@ public virtual void ReplaceConfiguration(BaseApplicationConfiguration newConfigu
144159
/// </summary>
145160
private void UpdateCachePath()
146161
{
147-
((BaseApplicationPaths)CommonApplicationPaths).CachePath = string.IsNullOrEmpty(CommonConfiguration.CachePath) ?
148-
null :
162+
((BaseApplicationPaths)CommonApplicationPaths).CachePath = string.IsNullOrEmpty(CommonConfiguration.CachePath) ?
163+
null :
149164
CommonConfiguration.CachePath;
150165
}
151166

@@ -168,5 +183,63 @@ private void ValidateCachePath(BaseApplicationConfiguration newConfig)
168183
}
169184
}
170185
}
186+
187+
private readonly ConcurrentDictionary<string, object> _configurations = new ConcurrentDictionary<string, object>();
188+
189+
private string GetConfigurationFile(string key)
190+
{
191+
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLower() + ".xml");
192+
}
193+
194+
public object GetConfiguration(string key)
195+
{
196+
return _configurations.GetOrAdd(key, k =>
197+
{
198+
var file = GetConfigurationFile(key);
199+
200+
var configurationType = _configurationStores
201+
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
202+
.ConfigurationType;
203+
204+
lock (_configurationSyncLock)
205+
{
206+
return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer);
207+
}
208+
});
209+
}
210+
211+
public void SaveConfiguration(string key, object configuration)
212+
{
213+
var configurationType = GetConfigurationType(key);
214+
215+
if (configuration.GetType() != configurationType)
216+
{
217+
throw new ArgumentException("Expected configuration type is " + configurationType.Name);
218+
}
219+
220+
_configurations.AddOrUpdate(key, configuration, (k, v) => configuration);
221+
222+
var path = GetConfigurationFile(key);
223+
Directory.CreateDirectory(Path.GetDirectoryName(path));
224+
225+
lock (_configurationSyncLock)
226+
{
227+
XmlSerializer.SerializeToFile(configuration, path);
228+
}
229+
230+
EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
231+
{
232+
Key = key,
233+
NewConfiguration = configuration
234+
235+
}, Logger);
236+
}
237+
238+
public Type GetConfigurationType(string key)
239+
{
240+
return _configurationStores
241+
.First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
242+
.ConfigurationType;
243+
}
171244
}
172245
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
3+
namespace MediaBrowser.Common.Configuration
4+
{
5+
public class ConfigurationUpdateEventArgs : EventArgs
6+
{
7+
/// <summary>
8+
/// Gets or sets the key.
9+
/// </summary>
10+
/// <value>The key.</value>
11+
public string Key { get; set; }
12+
/// <summary>
13+
/// Gets or sets the new configuration.
14+
/// </summary>
15+
/// <value>The new configuration.</value>
16+
public object NewConfiguration { get; set; }
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace MediaBrowser.Common.Configuration
5+
{
6+
public interface IConfigurationFactory
7+
{
8+
IEnumerable<ConfigurationStore> GetConfigurations();
9+
}
10+
11+
public class ConfigurationStore
12+
{
13+
public string Key { get; set; }
14+
15+
public Type ConfigurationType { get; set; }
16+
}
17+
}

MediaBrowser.Common/Configuration/IConfigurationManager.cs

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using MediaBrowser.Model.Configuration;
22
using System;
3+
using System.Collections.Generic;
34

45
namespace MediaBrowser.Common.Configuration
56
{
@@ -9,7 +10,12 @@ public interface IConfigurationManager
910
/// Occurs when [configuration updated].
1011
/// </summary>
1112
event EventHandler<EventArgs> ConfigurationUpdated;
12-
13+
14+
/// <summary>
15+
/// Occurs when [named configuration updated].
16+
/// </summary>
17+
event EventHandler<ConfigurationUpdateEventArgs> NamedConfigurationUpdated;
18+
1319
/// <summary>
1420
/// Gets or sets the application paths.
1521
/// </summary>
@@ -32,5 +38,40 @@ public interface IConfigurationManager
3238
/// </summary>
3339
/// <param name="newConfiguration">The new configuration.</param>
3440
void ReplaceConfiguration(BaseApplicationConfiguration newConfiguration);
41+
42+
/// <summary>
43+
/// Gets the configuration.
44+
/// </summary>
45+
/// <param name="key">The key.</param>
46+
/// <returns>System.Object.</returns>
47+
object GetConfiguration(string key);
48+
49+
/// <summary>
50+
/// Gets the type of the configuration.
51+
/// </summary>
52+
/// <param name="key">The key.</param>
53+
/// <returns>Type.</returns>
54+
Type GetConfigurationType(string key);
55+
56+
/// <summary>
57+
/// Saves the configuration.
58+
/// </summary>
59+
/// <param name="key">The key.</param>
60+
/// <param name="configuration">The configuration.</param>
61+
void SaveConfiguration(string key, object configuration);
62+
63+
/// <summary>
64+
/// Adds the parts.
65+
/// </summary>
66+
/// <param name="factories">The factories.</param>
67+
void AddParts(IEnumerable<IConfigurationFactory> factories);
68+
}
69+
70+
public static class ConfigurationManagerExtensions
71+
{
72+
public static T GetConfiguration<T>(this IConfigurationManager manager, string key)
73+
{
74+
return (T)manager.GetConfiguration(key);
75+
}
3576
}
3677
}

MediaBrowser.Common/MediaBrowser.Common.csproj

+2
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@
5555
<Link>Properties\SharedVersion.cs</Link>
5656
</Compile>
5757
<Compile Include="Configuration\ConfigurationHelper.cs" />
58+
<Compile Include="Configuration\ConfigurationUpdateEventArgs.cs" />
5859
<Compile Include="Configuration\IConfigurationManager.cs" />
60+
<Compile Include="Configuration\IConfigurationFactory.cs" />
5961
<Compile Include="Constants\Constants.cs" />
6062
<Compile Include="Events\EventHelper.cs" />
6163
<Compile Include="Extensions\BaseExtensions.cs" />

MediaBrowser.Common/Net/MimeTypes.cs

+5
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,11 @@ public static string GetMimeType(string path)
228228
return "text/vtt";
229229
}
230230

231+
if (ext.Equals(".bif", StringComparison.OrdinalIgnoreCase))
232+
{
233+
return "application/octet-stream";
234+
}
235+
231236
throw new ArgumentException("Argument not supported: " + path);
232237
}
233238
}

0 commit comments

Comments
 (0)