aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Common.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Common.Implementations')
-rw-r--r--MediaBrowser.Common.Implementations/Archiving/ZipClient.cs16
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationHost.cs130
-rw-r--r--MediaBrowser.Common.Implementations/BaseApplicationPaths.cs65
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs51
-rw-r--r--MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs59
-rw-r--r--MediaBrowser.Common.Implementations/Devices/DeviceId.cs5
-rw-r--r--MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs268
-rw-r--r--MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs61
-rw-r--r--MediaBrowser.Common.Implementations/Logging/LogHelper.cs5
-rw-r--r--MediaBrowser.Common.Implementations/Logging/NLogger.cs13
-rw-r--r--MediaBrowser.Common.Implementations/Logging/NlogManager.cs36
-rw-r--r--MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj33
-rw-r--r--MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs59
-rw-r--r--MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs4
-rw-r--r--MediaBrowser.Common.Implementations/Security/MbAdmin.cs13
-rw-r--r--MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs14
-rw-r--r--MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs17
-rw-r--r--MediaBrowser.Common.Implementations/Updates/InstallationManager.cs5
-rw-r--r--MediaBrowser.Common.Implementations/packages.config3
19 files changed, 584 insertions, 273 deletions
diff --git a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
index 23d40cf67f..3d759ca545 100644
--- a/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
+++ b/MediaBrowser.Common.Implementations/Archiving/ZipClient.cs
@@ -4,6 +4,7 @@ using SharpCompress.Archive.SevenZip;
using SharpCompress.Archive.Tar;
using SharpCompress.Common;
using SharpCompress.Reader;
+using SharpCompress.Reader.Zip;
using System.IO;
namespace MediaBrowser.Common.Implementations.Archiving
@@ -48,6 +49,21 @@ namespace MediaBrowser.Common.Implementations.Archiving
}
}
+ public void ExtractAllFromZip(Stream source, string targetPath, bool overwriteExistingFiles)
+ {
+ using (var reader = ZipReader.Open(source))
+ {
+ var options = ExtractOptions.ExtractFullPath;
+
+ if (overwriteExistingFiles)
+ {
+ options = options | ExtractOptions.Overwrite;
+ }
+
+ reader.WriteAllToDirectory(targetPath, options);
+ }
+ }
+
/// <summary>
/// Extracts all from7z.
/// </summary>
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
index c59d1a3b00..4de1adcfa8 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs
@@ -193,17 +193,28 @@ namespace MediaBrowser.Common.Implementations
}
}
+ public virtual string OperatingSystemDisplayName
+ {
+ get { return Environment.OSVersion.VersionString; }
+ }
+
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
/// </summary>
- protected BaseApplicationHost(TApplicationPathsType applicationPaths, ILogManager logManager)
+ protected BaseApplicationHost(TApplicationPathsType applicationPaths,
+ ILogManager logManager,
+ IFileSystem fileSystem)
{
FailedAssemblies = new List<string>();
ApplicationPaths = applicationPaths;
LogManager = logManager;
+ FileSystemManager = fileSystem;
ConfigurationManager = GetConfigurationManager();
+
+ // Initialize this early in case the -v command line option is used
+ Logger = LogManager.GetLogger("App");
}
/// <summary>
@@ -225,7 +236,6 @@ namespace MediaBrowser.Common.Implementations
JsonSerializer = CreateJsonSerializer();
- Logger = LogManager.GetLogger("App");
OnLoggerLoaded(true);
LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
@@ -263,7 +273,7 @@ namespace MediaBrowser.Common.Implementations
if (!isFirstLoad)
{
- LogEnvironmentInfo(Logger, ApplicationPaths);
+ LogEnvironmentInfo(Logger, ApplicationPaths, false);
}
// Put the app config in the log for troubleshooting purposes
@@ -282,20 +292,36 @@ namespace MediaBrowser.Common.Implementations
}
}
- public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths)
+ public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
{
- logger.Info("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs()));
+ logger.LogMultiline("Media Browser", LogSeverity.Info, GetBaseExceptionMessage(appPaths));
+ }
- logger.Info("Server: {0}", Environment.MachineName);
- logger.Info("Operating system: {0}", Environment.OSVersion.ToString());
- logger.Info("Processor count: {0}", Environment.ProcessorCount);
- logger.Info("64-Bit OS: {0}", Environment.Is64BitOperatingSystem);
- logger.Info("64-Bit Process: {0}", Environment.Is64BitProcess);
- logger.Info("Program data path: {0}", appPaths.ProgramDataPath);
+ protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths)
+ {
+ var builder = new StringBuilder();
+
+ builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())));
+
+ builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion));
+ builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount));
+ builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem));
+ builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess));
+ builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath));
+
+ Type type = Type.GetType("Mono.Runtime");
+ if (type != null)
+ {
+ MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
+ if (displayName != null)
+ {
+ builder.AppendLine("Mono: " + displayName.Invoke(null, null));
+ }
+ }
- logger.Info("Application Path: {0}", appPaths.ApplicationPath);
+ builder.AppendLine(string.Format("Application Path: {0}", appPaths.ApplicationPath));
- logger.Info("*** When reporting issues please include the entire log file. ***".ToUpper());
+ return builder;
}
protected virtual IJsonSerializer CreateJsonSerializer()
@@ -353,14 +379,13 @@ namespace MediaBrowser.Common.Implementations
/// <returns>Task.</returns>
public virtual Task RunStartupTasks()
{
- return Task.Run(() =>
- {
- Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
+ Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
+
+ ConfigureAutorun ();
- Task.Run(() => ConfigureAutorun());
+ ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
- ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
- });
+ return Task.FromResult (true);
}
/// <summary>
@@ -424,46 +449,43 @@ namespace MediaBrowser.Common.Implementations
/// <returns>Task.</returns>
protected virtual Task RegisterResources(IProgress<double> progress)
{
- return Task.Run(() =>
- {
- RegisterSingleInstance(ConfigurationManager);
- RegisterSingleInstance<IApplicationHost>(this);
+ RegisterSingleInstance(ConfigurationManager);
+ RegisterSingleInstance<IApplicationHost>(this);
- RegisterSingleInstance<IApplicationPaths>(ApplicationPaths);
+ RegisterSingleInstance<IApplicationPaths>(ApplicationPaths);
- TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, Logger);
+ TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, Logger);
- RegisterSingleInstance(JsonSerializer);
- RegisterSingleInstance(XmlSerializer);
+ RegisterSingleInstance(JsonSerializer);
+ RegisterSingleInstance(XmlSerializer);
- RegisterSingleInstance(LogManager);
- RegisterSingleInstance(Logger);
+ RegisterSingleInstance(LogManager);
+ RegisterSingleInstance(Logger);
- RegisterSingleInstance(TaskManager);
+ RegisterSingleInstance(TaskManager);
- FileSystemManager = CreateFileSystemManager();
- RegisterSingleInstance(FileSystemManager);
+ RegisterSingleInstance(FileSystemManager);
- HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager, ConfigurationManager);
- RegisterSingleInstance(HttpClient);
+ HttpClient = new HttpClientManager.HttpClientManager(ApplicationPaths, Logger, FileSystemManager);
+ RegisterSingleInstance(HttpClient);
- NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager"));
- RegisterSingleInstance(NetworkManager);
+ NetworkManager = CreateNetworkManager(LogManager.GetLogger("NetworkManager"));
+ RegisterSingleInstance(NetworkManager);
- SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, NetworkManager, LogManager);
- RegisterSingleInstance(SecurityManager);
+ SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, NetworkManager, LogManager);
+ RegisterSingleInstance(SecurityManager);
- InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, NetworkManager, ConfigurationManager);
- RegisterSingleInstance(InstallationManager);
+ InstallationManager = new InstallationManager(Logger, this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, NetworkManager, ConfigurationManager);
+ RegisterSingleInstance(InstallationManager);
- ZipClient = new ZipClient();
- RegisterSingleInstance(ZipClient);
+ ZipClient = new ZipClient();
+ RegisterSingleInstance(ZipClient);
- IsoManager = new IsoManager();
- RegisterSingleInstance(IsoManager);
+ IsoManager = new IsoManager();
+ RegisterSingleInstance(IsoManager);
- RegisterModules();
- });
+ RegisterModules();
+ return Task.FromResult (true);
}
private void RegisterModules()
@@ -485,11 +507,6 @@ namespace MediaBrowser.Common.Implementations
}
}
- protected virtual IFileSystem CreateFileSystemManager()
- {
- return new CommonFileSystem(Logger, true);
- }
-
/// <summary>
/// Gets a list of types within an assembly
/// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
@@ -685,18 +702,11 @@ namespace MediaBrowser.Common.Implementations
return parts;
}
- private Version _version;
/// <summary>
- /// Gets the current application version
+ /// Gets the application version.
/// </summary>
/// <value>The application version.</value>
- public Version ApplicationVersion
- {
- get
- {
- return _version ?? (_version = GetType().Assembly.GetName().Version);
- }
- }
+ public abstract Version ApplicationVersion { get; }
/// <summary>
/// Handles the ConfigurationUpdated event of the ConfigurationManager control.
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
index 668b1395d8..4ad63b2e3f 100644
--- a/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
+++ b/MediaBrowser.Common.Implementations/BaseApplicationPaths.cs
@@ -1,6 +1,4 @@
using MediaBrowser.Common.Configuration;
-using System;
-using System.Configuration;
using System.IO;
namespace MediaBrowser.Common.Implementations
@@ -12,45 +10,16 @@ namespace MediaBrowser.Common.Implementations
public abstract class BaseApplicationPaths : IApplicationPaths
{
/// <summary>
- /// The _use debug path
- /// </summary>
- private readonly bool _useDebugPath;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class.
- /// </summary>
- protected BaseApplicationPaths(bool useDebugPath, string applicationPath)
- {
- _useDebugPath = useDebugPath;
- ApplicationPath = applicationPath;
- }
-
- /// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
/// </summary>
protected BaseApplicationPaths(string programDataPath, string applicationPath)
{
- _programDataPath = programDataPath;
+ ProgramDataPath = programDataPath;
ApplicationPath = applicationPath;
}
public string ApplicationPath { get; private set; }
-
- /// <summary>
- /// The _program data path
- /// </summary>
- private string _programDataPath;
- /// <summary>
- /// Gets the path to the program data folder
- /// </summary>
- /// <value>The program data path.</value>
- public string ProgramDataPath
- {
- get
- {
- return _programDataPath ?? (_programDataPath = GetProgramDataPath());
- }
- }
+ public string ProgramDataPath { get; private set; }
/// <summary>
/// Gets the path to the system folder
@@ -202,35 +171,5 @@ namespace MediaBrowser.Common.Implementations
return Path.Combine(CachePath, "temp");
}
}
-
- /// <summary>
- /// Gets the path to the application's ProgramDataFolder
- /// </summary>
- /// <returns>System.String.</returns>
- private string GetProgramDataPath()
- {
- var programDataPath = _useDebugPath ? ConfigurationManager.AppSettings["DebugProgramDataPath"] : ConfigurationManager.AppSettings["ReleaseProgramDataPath"];
-
- programDataPath = programDataPath.Replace("%ApplicationData%", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
-
- // If it's a relative path, e.g. "..\"
- if (!Path.IsPathRooted(programDataPath))
- {
- var path = Path.GetDirectoryName(ApplicationPath);
-
- if (string.IsNullOrEmpty(path))
- {
- throw new ApplicationException("Unable to determine running assembly location");
- }
-
- programDataPath = Path.Combine(path, programDataPath);
-
- programDataPath = Path.GetFullPath(programDataPath);
- }
-
- Directory.CreateDirectory(programDataPath);
-
- return programDataPath;
- }
}
}
diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
index 4a70697fa2..c53947e443 100644
--- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
+++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs
@@ -105,7 +105,7 @@ namespace MediaBrowser.Common.Implementations.Configuration
UpdateCachePath();
}
- public void AddParts(IEnumerable<IConfigurationFactory> factories)
+ public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
{
_configurationFactories = factories.ToArray();
@@ -208,20 +208,51 @@ namespace MediaBrowser.Common.Implementations.Configuration
lock (_configurationSyncLock)
{
- return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer);
+ return LoadConfiguration(file, configurationType);
}
});
}
+ private object LoadConfiguration(string path, Type configurationType)
+ {
+ try
+ {
+ return XmlSerializer.DeserializeFromFile(configurationType, path);
+ }
+ catch (FileNotFoundException)
+ {
+ return Activator.CreateInstance(configurationType);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return Activator.CreateInstance(configurationType);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error loading configuration file: {0}", ex, path);
+
+ return Activator.CreateInstance(configurationType);
+ }
+ }
+
public void SaveConfiguration(string key, object configuration)
{
- var configurationType = GetConfigurationType(key);
+ var configurationStore = GetConfigurationStore(key);
+ var configurationType = configurationStore.ConfigurationType;
if (configuration.GetType() != configurationType)
{
throw new ArgumentException("Expected configuration type is " + configurationType.Name);
}
+ var validatingStore = configurationStore as IValidatingConfiguration;
+ if (validatingStore != null)
+ {
+ var currentConfiguration = GetConfiguration(key);
+
+ validatingStore.Validate(currentConfiguration, configuration);
+ }
+
EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs
{
Key = key,
@@ -239,6 +270,11 @@ namespace MediaBrowser.Common.Implementations.Configuration
XmlSerializer.SerializeToFile(configuration, path);
}
+ OnNamedConfigurationUpdated(key, configuration);
+ }
+
+ protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
+ {
EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs
{
Key = key,
@@ -249,9 +285,14 @@ namespace MediaBrowser.Common.Implementations.Configuration
public Type GetConfigurationType(string key)
{
- return _configurationStores
- .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase))
+ return GetConfigurationStore(key)
.ConfigurationType;
}
+
+ private ConfigurationStore GetConfigurationStore(string key)
+ {
+ return _configurationStores
+ .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase));
+ }
}
}
diff --git a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
new file mode 100644
index 0000000000..ff5b8bd599
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs
@@ -0,0 +1,59 @@
+using MediaBrowser.Model.Serialization;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace MediaBrowser.Common.Implementations.Configuration
+{
+ /// <summary>
+ /// Class ConfigurationHelper
+ /// </summary>
+ public static class ConfigurationHelper
+ {
+ /// <summary>
+ /// Reads an xml configuration file from the file system
+ /// It will immediately re-serialize and save if new serialization data is available due to property changes
+ /// </summary>
+ /// <param name="type">The type.</param>
+ /// <param name="path">The path.</param>
+ /// <param name="xmlSerializer">The XML serializer.</param>
+ /// <returns>System.Object.</returns>
+ public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer)
+ {
+ object configuration;
+
+ byte[] buffer = null;
+
+ // Use try/catch to avoid the extra file system lookup using File.Exists
+ try
+ {
+ buffer = File.ReadAllBytes(path);
+
+ configuration = xmlSerializer.DeserializeFromBytes(type, buffer);
+ }
+ catch (Exception)
+ {
+ configuration = Activator.CreateInstance(type);
+ }
+
+ using (var stream = new MemoryStream())
+ {
+ xmlSerializer.SerializeToStream(configuration, stream);
+
+ // Take the object we just got and serialize it back to bytes
+ var newBytes = stream.ToArray();
+
+ // If the file didn't exist before, or if something has changed, re-save
+ if (buffer == null || !buffer.SequenceEqual(newBytes))
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ // Save it after load in case we got new items
+ File.WriteAllBytes(path, newBytes);
+ }
+
+ return configuration;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
index 5af236026e..7c0dc1e1f0 100644
--- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
+++ b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs
@@ -38,7 +38,10 @@ namespace MediaBrowser.Common.Implementations.Devices
_logger.Error("Invalid value found in device id file");
}
}
- catch (FileNotFoundException ex)
+ catch (DirectoryNotFoundException)
+ {
+ }
+ catch (FileNotFoundException)
{
}
catch (Exception ex)
diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
index 5702af6d1c..1f82c5eb0c 100644
--- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs
@@ -1,4 +1,6 @@
-using MediaBrowser.Common.Configuration;
+using System.Net.Sockets;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Logging;
@@ -12,7 +14,6 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Cache;
-using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -40,7 +41,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
- private readonly IConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="HttpClientManager" /> class.
@@ -51,7 +51,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// <exception cref="System.ArgumentNullException">appPaths
/// or
/// logger</exception>
- public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem, IConfigurationManager config)
+ public HttpClientManager(IApplicationPaths appPaths, ILogger logger, IFileSystem fileSystem)
{
if (appPaths == null)
{
@@ -64,7 +64,6 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
_logger = logger;
_fileSystem = fileSystem;
- _config = config;
_appPaths = appPaths;
// http://stackoverflow.com/questions/566437/http-post-returns-the-error-417-expectation-failed-c
@@ -122,7 +121,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
request.Method = method;
- request.Timeout = 20000;
+ request.Timeout = options.TimeoutMs;
if (!string.IsNullOrEmpty(options.Host))
{
@@ -134,9 +133,22 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
request.Referer = options.Referer;
}
+ //request.ServicePoint.BindIPEndPointDelegate = BindIPEndPointCallback;
+
return request;
}
+ private static IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
+ {
+ // Prefer local ipv4
+ if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
+ {
+ return new IPEndPoint(IPAddress.IPv6Any, 0);
+ }
+
+ return new IPEndPoint(IPAddress.Any, 0);
+ }
+
private void AddRequestHeaders(HttpWebRequest request, HttpRequestOptions options)
{
foreach (var header in options.RequestHeaders.ToList())
@@ -157,6 +169,20 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
}
/// <summary>
+ /// The _semaphoreLocks
+ /// </summary>
+ private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = new ConcurrentDictionary<string, SemaphoreSlim>(StringComparer.OrdinalIgnoreCase);
+ /// <summary>
+ /// Gets the lock.
+ /// </summary>
+ /// <param name="url">The filename.</param>
+ /// <returns>System.Object.</returns>
+ private SemaphoreSlim GetLock(string url)
+ {
+ return _semaphoreLocks.GetOrAdd(url, key => new SemaphoreSlim(1, 1));
+ }
+
+ /// <summary>
/// Gets the response internal.
/// </summary>
/// <param name="options">The options.</param>
@@ -216,6 +242,110 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
/// </exception>
public async Task<HttpResponseInfo> SendAsync(HttpRequestOptions options, string httpMethod)
{
+ HttpResponseInfo response;
+
+ if (options.CacheMode == CacheMode.None)
+ {
+ response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
+ return response;
+ }
+
+ var url = options.Url;
+ var urlHash = url.ToLower().GetMD5().ToString("N");
+ var semaphore = GetLock(url);
+
+ var responseCachePath = Path.Combine(_appPaths.CachePath, "httpclient", urlHash);
+
+ response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false);
+ if (response != null)
+ {
+ return response;
+ }
+
+ await semaphore.WaitAsync(options.CancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ response = await GetCachedResponse(responseCachePath, options.CacheLength, url).ConfigureAwait(false);
+ if (response != null)
+ {
+ return response;
+ }
+
+ response = await SendAsyncInternal(options, httpMethod).ConfigureAwait(false);
+
+ if (response.StatusCode == HttpStatusCode.OK)
+ {
+ await CacheResponse(response, responseCachePath).ConfigureAwait(false);
+ }
+
+ return response;
+ }
+ finally
+ {
+ semaphore.Release();
+ }
+ }
+
+ private async Task<HttpResponseInfo> GetCachedResponse(string responseCachePath, TimeSpan cacheLength, string url)
+ {
+ try
+ {
+ if (_fileSystem.GetLastWriteTimeUtc(responseCachePath).Add(cacheLength) > DateTime.UtcNow)
+ {
+ using (var stream = _fileSystem.GetFileStream(responseCachePath, FileMode.Open, FileAccess.Read, FileShare.Read, true))
+ {
+ var memoryStream = new MemoryStream();
+
+ await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
+ memoryStream.Position = 0;
+
+ return new HttpResponseInfo
+ {
+ ResponseUrl = url,
+ Content = memoryStream,
+ StatusCode = HttpStatusCode.OK,
+ Headers = new NameValueCollection(),
+ ContentLength = memoryStream.Length
+ };
+ }
+ }
+ }
+ catch (FileNotFoundException)
+ {
+
+ }
+ catch (DirectoryNotFoundException)
+ {
+
+ }
+
+ return null;
+ }
+
+ private async Task CacheResponse(HttpResponseInfo response, string responseCachePath)
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(responseCachePath));
+
+ using (var responseStream = response.Content)
+ {
+ using (var fileStream = _fileSystem.GetFileStream(responseCachePath, FileMode.Create, FileAccess.Write, FileShare.Read, true))
+ {
+ var memoryStream = new MemoryStream();
+
+ await responseStream.CopyToAsync(memoryStream).ConfigureAwait(false);
+
+ memoryStream.Position = 0;
+ await memoryStream.CopyToAsync(fileStream).ConfigureAwait(false);
+
+ memoryStream.Position = 0;
+ response.Content = memoryStream;
+ }
+ }
+ }
+
+ private async Task<HttpResponseInfo> SendAsyncInternal(HttpRequestOptions options, string httpMethod)
+ {
ValidateParams(options);
options.CancellationToken.ThrowIfCancellationRequested();
@@ -236,11 +366,11 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
!string.IsNullOrEmpty(options.RequestContent) ||
string.Equals(httpMethod, "post", StringComparison.OrdinalIgnoreCase))
{
- var bytes = options.RequestContentBytes ??
+ var bytes = options.RequestContentBytes ??
Encoding.UTF8.GetBytes(options.RequestContent ?? string.Empty);
httpWebRequest.ContentType = options.RequestContentType ?? "application/x-www-form-urlencoded";
-
+
httpWebRequest.ContentLength = bytes.Length;
httpWebRequest.GetRequestStream().Write(bytes, 0, bytes.Length);
}
@@ -271,7 +401,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
if (!options.BufferContent)
{
- var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false);
+ var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false);
var httpResponse = (HttpWebResponse)response;
@@ -279,10 +409,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
options.CancellationToken.ThrowIfCancellationRequested();
- return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse));
+ return GetResponseInfo(httpResponse, httpResponse.GetResponseStream(), GetContentLength(httpResponse), httpResponse);
}
- using (var response = await httpWebRequest.GetResponseAsync().ConfigureAwait(false))
+ using (var response = await GetResponseAsync(httpWebRequest, TimeSpan.FromMilliseconds(options.TimeoutMs)).ConfigureAwait(false))
{
var httpResponse = (HttpWebResponse)response;
@@ -298,7 +428,7 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
memoryStream.Position = 0;
- return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length);
+ return GetResponseInfo(httpResponse, memoryStream, memoryStream.Length, null);
}
}
}
@@ -315,21 +445,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
throw exception;
}
- catch (HttpRequestException ex)
- {
- _logger.ErrorException("Error getting response from " + options.Url, ex);
-
- throw new HttpException(ex.Message, ex);
- }
- catch (WebException ex)
- {
- throw GetException(ex, options);
- }
catch (Exception ex)
{
- _logger.ErrorException("Error getting response from " + options.Url, ex);
-
- throw;
+ throw GetException(ex, options);
}
finally
{
@@ -361,9 +479,9 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
return exception;
}
- private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength)
+ private HttpResponseInfo GetResponseInfo(HttpWebResponse httpResponse, Stream content, long? contentLength, IDisposable disposable)
{
- return new HttpResponseInfo
+ return new HttpResponseInfo(disposable)
{
Content = content,
@@ -517,21 +635,10 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
return GetResponseInfo(httpResponse, tempFile, contentLength);
}
}
- catch (OperationCanceledException ex)
- {
- throw GetTempFileException(ex, options, tempFile);
- }
- catch (HttpRequestException ex)
- {
- throw GetTempFileException(ex, options, tempFile);
- }
- catch (WebException ex)
- {
- throw GetTempFileException(ex, options, tempFile);
- }
catch (Exception ex)
{
- throw GetTempFileException(ex, options, tempFile);
+ DeleteTempFile(tempFile);
+ throw GetException(ex, options);
}
finally
{
@@ -556,44 +663,25 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
- /// <summary>
- /// Handles the temp file exception.
- /// </summary>
- /// <param name="ex">The ex.</param>
- /// <param name="options">The options.</param>
- /// <param name="tempFile">The temp file.</param>
- /// <returns>Task.</returns>
- /// <exception cref="HttpException"></exception>
- private Exception GetTempFileException(Exception ex, HttpRequestOptions options, string tempFile)
+ private Exception GetException(Exception ex, HttpRequestOptions options)
{
- var operationCanceledException = ex as OperationCanceledException;
+ var webException = ex as WebException
+ ?? ex.InnerException as WebException;
- if (operationCanceledException != null)
+ if (webException != null)
{
- // Cleanup
- DeleteTempFile(tempFile);
-
- return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException);
+ return GetException(webException, options);
}
- _logger.ErrorException("Error getting response from " + options.Url, ex);
-
- // Cleanup
- DeleteTempFile(tempFile);
+ var operationCanceledException = ex as OperationCanceledException
+ ?? ex.InnerException as OperationCanceledException;
- var httpRequestException = ex as HttpRequestException;
-
- if (httpRequestException != null)
+ if (operationCanceledException != null)
{
- return new HttpException(ex.Message, ex);
+ return GetCancellationException(options.Url, options.CancellationToken, operationCanceledException);
}
- var webException = ex as WebException;
-
- if (webException != null)
- {
- throw GetException(webException, options);
- }
+ _logger.ErrorException("Error getting response from " + options.Url, ex);
return ex;
}
@@ -724,5 +812,47 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager
{
return Post(url, postData, null, cancellationToken);
}
+
+ private Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout)
+ {
+ var taskCompletion = new TaskCompletionSource<WebResponse>();
+
+ Task<WebResponse> asyncTask = Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
+
+ ThreadPool.RegisterWaitForSingleObject((asyncTask as IAsyncResult).AsyncWaitHandle, TimeoutCallback, request, timeout, true);
+ asyncTask.ContinueWith(task =>
+ {
+ taskCompletion.TrySetResult(task.Result);
+
+ }, TaskContinuationOptions.NotOnFaulted);
+
+ // Handle errors
+ asyncTask.ContinueWith(task =>
+ {
+ if (task.Exception != null)
+ {
+ taskCompletion.TrySetException(task.Exception);
+ }
+ else
+ {
+ taskCompletion.TrySetException(new List<Exception>());
+ }
+
+ }, TaskContinuationOptions.OnlyOnFaulted);
+
+ return taskCompletion.Task;
+ }
+
+ private static void TimeoutCallback(object state, bool timedOut)
+ {
+ if (timedOut)
+ {
+ WebRequest request = (WebRequest)state;
+ if (state != null)
+ {
+ request.Abort();
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
index 2d67ec9756..68df0e52ac 100644
--- a/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
+++ b/MediaBrowser.Common.Implementations/IO/CommonFileSystem.cs
@@ -15,11 +15,31 @@ namespace MediaBrowser.Common.Implementations.IO
protected ILogger Logger;
private readonly bool _supportsAsyncFileStreams;
+ private char[] _invalidFileNameChars;
- public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams)
+ public CommonFileSystem(ILogger logger, bool supportsAsyncFileStreams, bool usePresetInvalidFileNameChars)
{
Logger = logger;
_supportsAsyncFileStreams = supportsAsyncFileStreams;
+
+ SetInvalidFileNameChars(usePresetInvalidFileNameChars);
+ }
+
+ private void SetInvalidFileNameChars(bool usePresetInvalidFileNameChars)
+ {
+ // GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac.
+
+ if (usePresetInvalidFileNameChars)
+ {
+ _invalidFileNameChars = new char[41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
+ '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
+ '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
+ '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' };
+ }
+ else
+ {
+ _invalidFileNameChars = Path.GetInvalidFileNameChars();
+ }
}
/// <summary>
@@ -129,18 +149,6 @@ namespace MediaBrowser.Common.Implementations.IO
/// The space char
/// </summary>
private const char SpaceChar = ' ';
- /// <summary>
- /// The invalid file name chars
- /// </summary>
- #if __MonoCS__
- //GetInvalidFileNameChars is less restrictive in Linux/Mac than Windows, this mimic Windows behavior for mono under Linux/Mac.
- private static readonly char[] InvalidFileNameChars = new char [41] { '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
- '\x08', '\x09', '\x0A', '\x0B', '\x0C', '\x0D', '\x0E', '\x0F', '\x10', '\x11', '\x12',
- '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1A', '\x1B', '\x1C', '\x1D',
- '\x1E', '\x1F', '\x22', '\x3C', '\x3E', '\x7C', ':', '*', '?', '\\', '/' };
- #else
- private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars();
- #endif
/// <summary>
/// Takes a filename and removes invalid characters
@@ -157,7 +165,7 @@ namespace MediaBrowser.Common.Implementations.IO
var builder = new StringBuilder(filename);
- foreach (var c in InvalidFileNameChars)
+ foreach (var c in _invalidFileNameChars)
{
builder = builder.Replace(c, SpaceChar);
}
@@ -300,7 +308,7 @@ namespace MediaBrowser.Common.Implementations.IO
{
throw new ArgumentNullException("path");
}
-
+
return path.IndexOf(parentPath.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase) != -1;
}
@@ -310,12 +318,12 @@ namespace MediaBrowser.Common.Implementations.IO
{
throw new ArgumentNullException("path");
}
-
+
var parent = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(parent))
{
- return false;
+ return false;
}
return true;
@@ -382,5 +390,24 @@ namespace MediaBrowser.Common.Implementations.IO
{
return Path.GetFileNameWithoutExtension(path);
}
+
+ public bool IsPathFile(string path)
+ {
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ throw new ArgumentNullException("path");
+ }
+
+ // Cannot use Path.IsPathRooted because it returns false under mono when using windows-based paths, e.g. C:\\
+
+ if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) != -1 &&
+ !path.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ return true;
+
+ //return Path.IsPathRooted(path);
+ }
}
}
diff --git a/MediaBrowser.Common.Implementations/Logging/LogHelper.cs b/MediaBrowser.Common.Implementations/Logging/LogHelper.cs
index 91e937ca7c..8080c2111c 100644
--- a/MediaBrowser.Common.Implementations/Logging/LogHelper.cs
+++ b/MediaBrowser.Common.Implementations/Logging/LogHelper.cs
@@ -15,6 +15,11 @@ namespace MediaBrowser.Common.Implementations.Logging
/// <returns>StringBuilder.</returns>
public static StringBuilder GetLogMessage(Exception exception)
{
+ if (exception == null)
+ {
+ throw new ArgumentNullException("exception");
+ }
+
var messageText = new StringBuilder();
messageText.AppendLine(exception.Message);
diff --git a/MediaBrowser.Common.Implementations/Logging/NLogger.cs b/MediaBrowser.Common.Implementations/Logging/NLogger.cs
index c87b58f70a..29b6188903 100644
--- a/MediaBrowser.Common.Implementations/Logging/NLogger.cs
+++ b/MediaBrowser.Common.Implementations/Logging/NLogger.cs
@@ -14,6 +14,8 @@ namespace MediaBrowser.Common.Implementations.Logging
/// </summary>
private readonly NLog.Logger _logger;
+ private readonly ILogManager _logManager;
+
/// <summary>
/// The _lock object
/// </summary>
@@ -23,8 +25,10 @@ namespace MediaBrowser.Common.Implementations.Logging
/// Initializes a new instance of the <see cref="NLogger" /> class.
/// </summary>
/// <param name="name">The name.</param>
- public NLogger(string name)
+ /// <param name="logManager">The log manager.</param>
+ public NLogger(string name, ILogManager logManager)
{
+ _logManager = logManager;
lock (LockObject)
{
_logger = NLog.LogManager.GetLogger(name);
@@ -96,6 +100,13 @@ namespace MediaBrowser.Common.Implementations.Logging
var messageText = LogHelper.GetLogMessage(exception);
+ var prefix = _logManager.ExceptionMessagePrefix;
+
+ if (!string.IsNullOrWhiteSpace(prefix))
+ {
+ messageText.Insert(0, prefix);
+ }
+
LogMultiline(message, level, messageText);
}
diff --git a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
index b8ee60f018..77d9f80f9f 100644
--- a/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
+++ b/MediaBrowser.Common.Implementations/Logging/NlogManager.cs
@@ -2,6 +2,7 @@
using NLog;
using NLog.Config;
using NLog.Targets;
+using NLog.Targets.Wrappers;
using System;
using System.IO;
using System.Linq;
@@ -34,6 +35,12 @@ namespace MediaBrowser.Common.Implementations.Logging
public string LogFilePath { get; private set; }
/// <summary>
+ /// Gets or sets the exception message prefix.
+ /// </summary>
+ /// <value>The exception message prefix.</value>
+ public string ExceptionMessagePrefix { get; set; }
+
+ /// <summary>
/// Initializes a new instance of the <see cref="NlogManager" /> class.
/// </summary>
/// <param name="logDirectory">The log directory.</param>
@@ -42,6 +49,8 @@ namespace MediaBrowser.Common.Implementations.Logging
{
LogDirectory = logDirectory;
LogFilePrefix = logFileNamePrefix;
+
+ LogManager.Configuration = new LoggingConfiguration ();
}
private LogSeverity _severity = LogSeverity.Debug;
@@ -86,16 +95,22 @@ namespace MediaBrowser.Common.Implementations.Logging
/// <param name="level">The level.</param>
private void AddFileTarget(string path, LogSeverity level)
{
- var logFile = new FileTarget
+ RemoveTarget("ApplicationLogFileWrapper");
+
+ var wrapper = new AsyncTargetWrapper ();
+ wrapper.Name = "ApplicationLogFileWrapper";
+
+ var logFile = new FileTarget
{
FileName = path,
Layout = "${longdate} ${level} - ${logger}: ${message}"
};
- RemoveTarget("ApplicationLogFile");
logFile.Name = "ApplicationLogFile";
- AddLogTarget(logFile, level);
+ wrapper.WrappedTarget = logFile;
+
+ AddLogTarget(wrapper, level);
}
/// <summary>
@@ -150,7 +165,7 @@ namespace MediaBrowser.Common.Implementations.Logging
/// <returns>ILogger.</returns>
public ILogger GetLogger(string name)
{
- return new NLogger(name);
+ return new NLogger(name, this);
}
/// <summary>
@@ -216,22 +231,27 @@ namespace MediaBrowser.Common.Implementations.Logging
public void AddConsoleOutput()
{
+ RemoveTarget("ConsoleTargetWrapper");
+
+ var wrapper = new AsyncTargetWrapper ();
+ wrapper.Name = "ConsoleTargetWrapper";
+
var target = new ConsoleTarget()
{
Layout = "${level}, ${logger}, ${message}",
Error = false
};
- RemoveTarget("ConsoleTarget");
-
target.Name = "ConsoleTarget";
- AddLogTarget(target, LogSeverity);
+ wrapper.WrappedTarget = target;
+
+ AddLogTarget(wrapper, LogSeverity);
}
public void RemoveConsoleOutput()
{
- RemoveTarget("ConsoleTarget");
+ RemoveTarget("ConsoleTargetWrapper");
}
}
}
diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
index 81df199241..ff08c31bce 100644
--- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
+++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
@@ -11,10 +11,10 @@
<AssemblyName>MediaBrowser.Common.Implementations</AssemblyName>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
- <RestorePackages>true</RestorePackages>
<ProductVersion>10.0.0</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -27,7 +27,7 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
+ <DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
@@ -36,7 +36,7 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release Mono|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
+ <DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release Mono\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
@@ -52,24 +52,23 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\NLog.3.1.0.0\lib\net45\NLog.dll</HintPath>
</Reference>
- <Reference Include="SimpleInjector, Version=2.5.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\ThirdParty\SharpCompress\SharpCompress.dll</HintPath>
+ </Reference>
+ <Reference Include="SimpleInjector, Version=2.6.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SimpleInjector.2.5.2\lib\net45\SimpleInjector.dll</HintPath>
+ <HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.dll</HintPath>
</Reference>
- <Reference Include="SimpleInjector.Diagnostics, Version=2.5.2.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
+ <Reference Include="SimpleInjector.Diagnostics, Version=2.6.1.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
- <HintPath>..\packages\SimpleInjector.2.5.2\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
+ <HintPath>..\packages\SimpleInjector.2.6.1\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
</Reference>
<Reference Include="System" />
- <Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net" />
- <Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
- <Reference Include="SharpCompress">
- <HintPath>..\packages\sharpcompress.0.10.2\lib\net40\SharpCompress.dll</HintPath>
- </Reference>
<Reference Include="ServiceStack.Text">
<HintPath>..\ThirdParty\ServiceStack.Text\ServiceStack.Text.dll</HintPath>
</Reference>
@@ -82,6 +81,7 @@
<Compile Include="BaseApplicationHost.cs" />
<Compile Include="BaseApplicationPaths.cs" />
<Compile Include="Configuration\BaseConfigurationManager.cs" />
+ <Compile Include="Configuration\ConfigurationHelper.cs" />
<Compile Include="Devices\DeviceId.cs" />
<Compile Include="HttpClientManager\HttpClientInfo.cs" />
<Compile Include="HttpClientManager\HttpClientManager.cs" />
@@ -97,6 +97,7 @@
<Compile Include="ScheduledTasks\Tasks\DeleteCacheFileTask.cs" />
<Compile Include="ScheduledTasks\Tasks\DeleteLogFileTask.cs" />
<Compile Include="ScheduledTasks\Tasks\ReloadLoggerFileTask.cs" />
+ <Compile Include="Security\MbAdmin.cs" />
<Compile Include="Security\MBLicenseFile.cs" />
<Compile Include="Security\PluginSecurityManager.cs" />
<Compile Include="Security\RegRecord.cs" />
@@ -120,11 +121,11 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
- <Import Project="$(SolutionDir)\.nuget\NuGet.targets" />
<PropertyGroup>
- <PostBuildEvent Condition=" '$(ConfigurationName)' != 'Release Mono' ">if '$(ConfigurationName)' == 'Release' (
-xcopy "$(TargetPath)" "$(SolutionDir)\Nuget\dlls\" /y /d /r /i
-)</PostBuildEvent>
+ <PostBuildEvent />
+ </PropertyGroup>
+ <PropertyGroup>
+ <PostBuildEvent />
</PropertyGroup>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
index 8159be6340..bf6ebf7ef7 100644
--- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
+++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
@@ -24,14 +24,46 @@ namespace MediaBrowser.Common.Implementations.Networking
/// <returns>IPAddress.</returns>
public IEnumerable<string> GetLocalIpAddresses()
{
- var list = GetIPsDefault().Where(i => !IPAddress.IsLoopback(i)).Select(i => i.ToString()).ToList();
+ var list = GetIPsDefault()
+ .Where(i => !IPAddress.IsLoopback(i))
+ .Select(i => i.ToString())
+ .Where(FilterIpAddress)
+ .ToList();
if (list.Count > 0)
{
return list;
}
- return GetLocalIpAddressesFallback();
+ return GetLocalIpAddressesFallback().Where(FilterIpAddress);
+ }
+
+ private bool FilterIpAddress(string address)
+ {
+ if (address.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private bool IsInPrivateAddressSpace(string endpoint)
+ {
+ // Private address space:
+ // http://en.wikipedia.org/wiki/Private_network
+
+ return
+
+ // If url was requested with computer name, we may see this
+ endpoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 ||
+
+ endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
+ endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
+ endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
+ endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
+ endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
+ endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
}
public bool IsInLocalNetwork(string endpoint)
@@ -46,6 +78,11 @@ namespace MediaBrowser.Common.Implementations.Networking
throw new ArgumentNullException("endpoint");
}
+ if (IsInPrivateAddressSpace(endpoint))
+ {
+ return true;
+ }
+
const int lengthMatch = 4;
if (endpoint.Length >= lengthMatch)
@@ -59,24 +96,6 @@ namespace MediaBrowser.Common.Implementations.Networking
}
}
- // Private address space:
- // http://en.wikipedia.org/wiki/Private_network
-
- var isPrivate =
-
- // If url was requested with computer name, we may see this
- endpoint.IndexOf("::", StringComparison.OrdinalIgnoreCase) != -1 ||
-
- endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase);
-
- if (isPrivate)
- {
- return true;
- }
-
IPAddress address;
if (resolveHost && !IPAddress.TryParse(endpoint, out address))
{
diff --git a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
index 8f3225f4e9..63381efcdf 100644
--- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
+++ b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs
@@ -101,6 +101,10 @@ namespace MediaBrowser.Common.Implementations.Security
{
contents = File.ReadAllLines(licenseFile);
}
+ catch (DirectoryNotFoundException)
+ {
+ (File.Create(licenseFile)).Close();
+ }
catch (FileNotFoundException)
{
(File.Create(licenseFile)).Close();
diff --git a/MediaBrowser.Common.Implementations/Security/MbAdmin.cs b/MediaBrowser.Common.Implementations/Security/MbAdmin.cs
new file mode 100644
index 0000000000..ab4a83257c
--- /dev/null
+++ b/MediaBrowser.Common.Implementations/Security/MbAdmin.cs
@@ -0,0 +1,13 @@
+
+namespace MediaBrowser.Common.Implementations.Security
+{
+ public class MbAdmin
+ {
+ public const string HttpUrl = "http://www.mb3admin.com/admin/";
+
+ /// <summary>
+ /// Leaving as http for now until we get it squared away
+ /// </summary>
+ public const string HttpsUrl = "http://www.mb3admin.com/admin/";
+ }
+}
diff --git a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
index 4d693e40c3..3e81e839fc 100644
--- a/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
+++ b/MediaBrowser.Common.Implementations/Security/PluginSecurityManager.cs
@@ -17,7 +17,7 @@ namespace MediaBrowser.Common.Implementations.Security
/// </summary>
public class PluginSecurityManager : ISecurityManager
{
- private const string MBValidateUrl = Constants.Constants.MbAdminUrl + "service/registration/validate";
+ private const string MBValidateUrl = MbAdmin.HttpsUrl + "service/registration/validate";
/// <summary>
/// The _is MB supporter
@@ -160,13 +160,12 @@ namespace MediaBrowser.Common.Implementations.Security
return new SupporterInfo();
}
- var url = Constants.Constants.MbAdminUrl + "/service/supporter/retrieve?key=" + key;
+ var url = MbAdmin.HttpsUrl + "/service/supporter/retrieve?key=" + key;
using (var stream = await _httpClient.Get(url, CancellationToken.None).ConfigureAwait(false))
{
var response = _jsonSerializer.DeserializeFromStream<SuppporterInfoResponse>(stream);
-
var info = new SupporterInfo
{
Email = response.email,
@@ -187,15 +186,18 @@ namespace MediaBrowser.Common.Implementations.Security
string mb2Equivalent = null,
string version = null)
{
+ var lastChecked = LicenseFile.LastChecked(feature);
+
//check the reg file first to alleviate strain on the MB admin server - must actually check in every 30 days tho
var reg = new RegRecord
{
- registered = LicenseFile.LastChecked(feature) > DateTime.UtcNow.AddDays(-3)
+ // Cache the result for up to a week
+ registered = lastChecked > DateTime.UtcNow.AddDays(-7)
};
var success = reg.registered;
- if (!reg.registered)
+ if (!(lastChecked > DateTime.UtcNow.AddDays(-1)))
{
var mac = _networkManager.GetMacAddress();
var data = new Dictionary<string, string>
@@ -206,7 +208,7 @@ namespace MediaBrowser.Common.Implementations.Security
{ "systemid", _appHost.SystemId },
{ "mb2equiv", mb2Equivalent },
{ "ver", version },
- { "platform", Environment.OSVersion.VersionString },
+ { "platform", _appHost.OperatingSystemDisplayName },
{ "isservice", _appHost.IsRunningAsService.ToString().ToLower() }
};
diff --git a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
index cef744753a..04030522f3 100644
--- a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
+++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Model.Serialization;
using System;
+using System.Collections.Concurrent;
using System.IO;
using System.Xml;
@@ -10,6 +11,17 @@ namespace MediaBrowser.Common.Implementations.Serialization
/// </summary>
public class XmlSerializer : IXmlSerializer
{
+ // Need to cache these
+ // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
+ private readonly ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer> _serializers =
+ new ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer>();
+
+ private System.Xml.Serialization.XmlSerializer GetSerializer(Type type)
+ {
+ var key = type.FullName;
+ return _serializers.GetOrAdd(key, k => new System.Xml.Serialization.XmlSerializer(type));
+ }
+
/// <summary>
/// Serializes to writer.
/// </summary>
@@ -18,7 +30,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
private void SerializeToWriter(object obj, XmlTextWriter writer)
{
writer.Formatting = Formatting.Indented;
- var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
+ var netSerializer = GetSerializer(obj.GetType());
netSerializer.Serialize(writer, obj);
}
@@ -32,8 +44,7 @@ namespace MediaBrowser.Common.Implementations.Serialization
{
using (var reader = new XmlTextReader(stream))
{
- var netSerializer = new System.Xml.Serialization.XmlSerializer(type);
-
+ var netSerializer = GetSerializer(type);
return netSerializer.Deserialize(reader);
}
}
diff --git a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
index b022dc6719..f3a9859681 100644
--- a/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
+++ b/MediaBrowser.Common.Implementations/Updates/InstallationManager.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Implementations.Security;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Progress;
@@ -161,7 +162,7 @@ namespace MediaBrowser.Common.Implementations.Updates
{ "systemid", _applicationHost.SystemId }
};
- using (var json = await _httpClient.Post(Constants.Constants.MbAdminUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false))
+ using (var json = await _httpClient.Post(MbAdmin.HttpsUrl + "service/package/retrieveall", data, cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
@@ -203,7 +204,7 @@ namespace MediaBrowser.Common.Implementations.Updates
}
}
- using (var json = await _httpClient.Get(Constants.Constants.MbAdminUrl + "service/MB3Packages.json", cancellationToken).ConfigureAwait(false))
+ using (var json = await _httpClient.Get(MbAdmin.HttpUrl + "service/MB3Packages.json", cancellationToken).ConfigureAwait(false))
{
cancellationToken.ThrowIfCancellationRequested();
diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config
index adc4fe562e..63d288bbbb 100644
--- a/MediaBrowser.Common.Implementations/packages.config
+++ b/MediaBrowser.Common.Implementations/packages.config
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="NLog" version="3.1.0.0" targetFramework="net45" />
- <package id="SharpCompress" version="0.10.2" targetFramework="net45" />
- <package id="SimpleInjector" version="2.5.2" targetFramework="net45" />
+ <package id="SimpleInjector" version="2.6.1" targetFramework="net45" />
</packages>