diff --git a/Emby.Common.Implementations/BaseApplicationHost.cs b/Emby.Common.Implementations/BaseApplicationHost.cs
index f53433511..13bb85087 100644
--- a/Emby.Common.Implementations/BaseApplicationHost.cs
+++ b/Emby.Common.Implementations/BaseApplicationHost.cs
@@ -147,7 +147,7 @@ namespace Emby.Common.Implementations
/// The configuration manager.
protected IConfigurationManager ConfigurationManager { get; private set; }
- protected IFileSystem FileSystemManager { get; private set; }
+ public IFileSystem FileSystemManager { get; private set; }
protected IIsoManager IsoManager { get; private set; }
diff --git a/Emby.Server.Core/ApplicationHost.cs b/Emby.Server.Core/ApplicationHost.cs
index c3d88eeab..a8866fc97 100644
--- a/Emby.Server.Core/ApplicationHost.cs
+++ b/Emby.Server.Core/ApplicationHost.cs
@@ -83,7 +83,6 @@ using Emby.Dlna.MediaReceiverRegistrar;
using Emby.Dlna.Ssdp;
using Emby.Server.Core;
using Emby.Server.Implementations.Activity;
-using Emby.Server.Core.Configuration;
using Emby.Server.Implementations.Devices;
using Emby.Server.Implementations.FFMpeg;
using Emby.Server.Core.IO;
@@ -94,7 +93,6 @@ using Emby.Server.Implementations.Social;
using Emby.Server.Implementations.Sync;
using Emby.Server.Implementations.Channels;
using Emby.Server.Implementations.Collections;
-using Emby.Server.Implementations.Connect;
using Emby.Server.Implementations.Dto;
using Emby.Server.Implementations.EntryPoints;
using Emby.Server.Implementations.FileOrganization;
@@ -134,6 +132,7 @@ using Emby.Drawing;
using Emby.Server.Implementations.Migrations;
using MediaBrowser.Model.Diagnostics;
using Emby.Common.Implementations.Diagnostics;
+using Emby.Server.Implementations.Configuration;
namespace Emby.Server.Core
{
@@ -526,6 +525,8 @@ namespace Emby.Server.Core
}
}
+ protected abstract IConnectManager CreateConnectManager();
+
///
/// Registers resources that classes will depend on
///
@@ -635,7 +636,7 @@ namespace Emby.Server.Core
var encryptionManager = new EncryptionManager();
RegisterSingleInstance(encryptionManager);
- ConnectManager = new ConnectManager(LogManager.GetLogger("ConnectManager"), ApplicationPaths, JsonSerializer, encryptionManager, HttpClient, this, ServerConfigurationManager, UserManager, ProviderManager, SecurityManager, FileSystemManager);
+ ConnectManager = CreateConnectManager();
RegisterSingleInstance(ConnectManager);
DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, LogManager.GetLogger("DeviceManager"), FileSystemManager), UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
diff --git a/Emby.Server.Core/Logging/ConsoleLogger.cs b/Emby.Server.Core/Logging/ConsoleLogger.cs
new file mode 100644
index 000000000..01eca7b7e
--- /dev/null
+++ b/Emby.Server.Core/Logging/ConsoleLogger.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using MediaBrowser.Model.Logging;
+
+namespace Emby.Server.Core.Logging
+{
+ public class ConsoleLogger : IConsoleLogger
+ {
+ public void WriteLine(string message)
+ {
+ Console.WriteLine(message);
+ }
+ }
+}
diff --git a/Emby.Common.Implementations/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
similarity index 93%
rename from Emby.Common.Implementations/BaseApplicationPaths.cs
rename to Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
index 8792778ba..54d1d5302 100644
--- a/Emby.Common.Implementations/BaseApplicationPaths.cs
+++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs
@@ -1,7 +1,8 @@
-using System.IO;
+using System;
+using System.IO;
using MediaBrowser.Common.Configuration;
-namespace Emby.Common.Implementations
+namespace Emby.Server.Implementations.AppBase
{
///
/// Provides a base class to hold common application paths used by both the Ui and Server.
@@ -12,12 +13,15 @@ namespace Emby.Common.Implementations
///
/// Initializes a new instance of the class.
///
- protected BaseApplicationPaths(string programDataPath, string appFolderPath)
+ protected BaseApplicationPaths(string programDataPath, string appFolderPath, Action createDirectoryFn)
{
ProgramDataPath = programDataPath;
ProgramSystemPath = appFolderPath;
+ CreateDirectoryFn = createDirectoryFn;
}
+ protected Action CreateDirectoryFn;
+
public string ProgramDataPath { get; private set; }
///
@@ -41,7 +45,7 @@ namespace Emby.Common.Implementations
{
_dataDirectory = Path.Combine(ProgramDataPath, "data");
- Directory.CreateDirectory(_dataDirectory);
+ CreateDirectoryFn(_dataDirectory);
}
return _dataDirectory;
@@ -148,7 +152,7 @@ namespace Emby.Common.Implementations
{
_cachePath = Path.Combine(ProgramDataPath, "cache");
- Directory.CreateDirectory(_cachePath);
+ CreateDirectoryFn(_cachePath);
}
return _cachePath;
diff --git a/Emby.Common.Implementations/Configuration/BaseConfigurationManager.cs b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
similarity index 99%
rename from Emby.Common.Implementations/Configuration/BaseConfigurationManager.cs
rename to Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
index 27c9fe615..13874223c 100644
--- a/Emby.Common.Implementations/Configuration/BaseConfigurationManager.cs
+++ b/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs
@@ -7,13 +7,12 @@ using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
-using Emby.Common.Implementations;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
-namespace Emby.Common.Implementations.Configuration
+namespace Emby.Server.Implementations.AppBase
{
///
/// Class BaseConfigurationManager
diff --git a/Emby.Common.Implementations/Configuration/ConfigurationHelper.cs b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
similarity index 97%
rename from Emby.Common.Implementations/Configuration/ConfigurationHelper.cs
rename to Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
index 0d43a651e..ad2f45945 100644
--- a/Emby.Common.Implementations/Configuration/ConfigurationHelper.cs
+++ b/Emby.Server.Implementations/AppBase/ConfigurationHelper.cs
@@ -4,7 +4,7 @@ using System.Linq;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
-namespace Emby.Common.Implementations.Configuration
+namespace Emby.Server.Implementations.AppBase
{
///
/// Class ConfigurationHelper
diff --git a/Emby.Server.Core/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
similarity index 97%
rename from Emby.Server.Core/Configuration/ServerConfigurationManager.cs
rename to Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
index eb3d8b9f9..2241e9377 100644
--- a/Emby.Server.Core/Configuration/ServerConfigurationManager.cs
+++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using Emby.Common.Implementations.Configuration;
+using Emby.Server.Implementations.AppBase;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Controller;
@@ -17,7 +17,7 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Serialization;
-namespace Emby.Server.Core.Configuration
+namespace Emby.Server.Implementations.Configuration
{
///
/// Class ServerConfigurationManager
@@ -187,7 +187,7 @@ namespace Emby.Server.Core.Configuration
// Validate
if (!FileSystem.DirectoryExists(newPath))
{
- throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath));
+ throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
}
EnsureWriteAccess(newPath);
diff --git a/Emby.Server.Implementations/Connect/ConnectData.cs b/Emby.Server.Implementations/Connect/ConnectData.cs
deleted file mode 100644
index 41b89ce52..000000000
--- a/Emby.Server.Implementations/Connect/ConnectData.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Emby.Server.Implementations.Connect
-{
- public class ConnectData
- {
- ///
- /// Gets or sets the server identifier.
- ///
- /// The server identifier.
- public string ServerId { get; set; }
- ///
- /// Gets or sets the access key.
- ///
- /// The access key.
- public string AccessKey { get; set; }
-
- ///
- /// Gets or sets the authorizations.
- ///
- /// The authorizations.
- public List PendingAuthorizations { get; set; }
-
- ///
- /// Gets or sets the last authorizations refresh.
- ///
- /// The last authorizations refresh.
- public DateTime LastAuthorizationsRefresh { get; set; }
-
- public ConnectData()
- {
- PendingAuthorizations = new List();
- }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs b/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs
deleted file mode 100644
index b5639773b..000000000
--- a/Emby.Server.Implementations/Connect/ConnectEntryPoint.cs
+++ /dev/null
@@ -1,218 +0,0 @@
-using MediaBrowser.Common;
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Connect;
-using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using System;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Security;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Threading;
-
-namespace Emby.Server.Implementations.Connect
-{
- public class ConnectEntryPoint : IServerEntryPoint
- {
- private ITimer _timer;
- private IpAddressInfo _cachedIpAddress;
- private readonly IHttpClient _httpClient;
- private readonly IApplicationPaths _appPaths;
- private readonly ILogger _logger;
- private readonly IConnectManager _connectManager;
-
- private readonly INetworkManager _networkManager;
- private readonly IApplicationHost _appHost;
- private readonly IFileSystem _fileSystem;
- private readonly ITimerFactory _timerFactory;
- private readonly IEncryptionManager _encryption;
-
- public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager, IApplicationHost appHost, IFileSystem fileSystem, ITimerFactory timerFactory, IEncryptionManager encryption)
- {
- _httpClient = httpClient;
- _appPaths = appPaths;
- _logger = logger;
- _networkManager = networkManager;
- _connectManager = connectManager;
- _appHost = appHost;
- _fileSystem = fileSystem;
- _timerFactory = timerFactory;
- _encryption = encryption;
- }
-
- public void Run()
- {
- LoadCachedAddress();
-
- _timer = _timerFactory.Create(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(1));
- ((ConnectManager)_connectManager).Start();
- }
-
- private readonly string[] _ipLookups =
- {
- "http://bot.whatismyipaddress.com",
- "https://connect.emby.media/service/ip"
- };
-
- private async void TimerCallback(object state)
- {
- IpAddressInfo validIpAddress = null;
-
- foreach (var ipLookupUrl in _ipLookups)
- {
- try
- {
- validIpAddress = await GetIpAddress(ipLookupUrl).ConfigureAwait(false);
-
- // Try to find the ipv4 address, if present
- if (validIpAddress.AddressFamily != IpAddressFamily.InterNetworkV6)
- {
- break;
- }
- }
- catch (HttpException)
- {
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting connection info", ex);
- }
- }
-
- // If this produced an ipv6 address, try again
- if (validIpAddress != null && validIpAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
- {
- foreach (var ipLookupUrl in _ipLookups)
- {
- try
- {
- var newAddress = await GetIpAddress(ipLookupUrl, true).ConfigureAwait(false);
-
- // Try to find the ipv4 address, if present
- if (newAddress.AddressFamily != IpAddressFamily.InterNetworkV6)
- {
- validIpAddress = newAddress;
- break;
- }
- }
- catch (HttpException)
- {
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error getting connection info", ex);
- }
- }
- }
-
- if (validIpAddress != null)
- {
- ((ConnectManager)_connectManager).OnWanAddressResolved(validIpAddress);
- CacheAddress(validIpAddress);
- }
- }
-
- private async Task GetIpAddress(string lookupUrl, bool preferIpv4 = false)
- {
- // Sometimes whatismyipaddress might fail, but it won't do us any good having users raise alarms over it.
- var logErrors = false;
-
-#if DEBUG
- logErrors = true;
-#endif
- using (var stream = await _httpClient.Get(new HttpRequestOptions
- {
- Url = lookupUrl,
- UserAgent = "Emby/" + _appHost.ApplicationVersion,
- LogErrors = logErrors,
-
- // Seeing block length errors with our server
- EnableHttpCompression = false,
- PreferIpv4 = preferIpv4,
- BufferContent = false
-
- }).ConfigureAwait(false))
- {
- using (var reader = new StreamReader(stream))
- {
- var addressString = await reader.ReadToEndAsync().ConfigureAwait(false);
-
- return _networkManager.ParseIpAddress(addressString);
- }
- }
- }
-
- private string CacheFilePath
- {
- get { return Path.Combine(_appPaths.DataPath, "wan.dat"); }
- }
-
- private void CacheAddress(IpAddressInfo address)
- {
- if (_cachedIpAddress != null && _cachedIpAddress.Equals(address))
- {
- // no need to update the file if the address has not changed
- return;
- }
-
- var path = CacheFilePath;
-
- try
- {
- _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
- }
- catch (Exception ex)
- {
- }
-
- try
- {
- _fileSystem.WriteAllText(path, _encryption.EncryptString(address.ToString()), Encoding.UTF8);
- _cachedIpAddress = address;
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving data", ex);
- }
- }
-
- private void LoadCachedAddress()
- {
- var path = CacheFilePath;
-
- _logger.Info("Loading data from {0}", path);
-
- try
- {
- var endpoint = _encryption.DecryptString(_fileSystem.ReadAllText(path, Encoding.UTF8));
- IpAddressInfo ipAddress;
-
- if (_networkManager.TryParseIpAddress(endpoint, out ipAddress))
- {
- _cachedIpAddress = ipAddress;
- ((ConnectManager)_connectManager).OnWanAddressResolved(ipAddress);
- }
- }
- catch (IOException)
- {
- // File isn't there. no biggie
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error loading data", ex);
- }
- }
-
- public void Dispose()
- {
- if (_timer != null)
- {
- _timer.Dispose();
- _timer = null;
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/ConnectManager.cs b/Emby.Server.Implementations/Connect/ConnectManager.cs
deleted file mode 100644
index 8aac2a8c4..000000000
--- a/Emby.Server.Implementations/Connect/ConnectManager.cs
+++ /dev/null
@@ -1,1193 +0,0 @@
-using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Common.Security;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Connect;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Security;
-using MediaBrowser.Model.Connect;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Logging;
-using MediaBrowser.Model.Net;
-using MediaBrowser.Model.Serialization;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Common.Extensions;
-
-namespace Emby.Server.Implementations.Connect
-{
- public class ConnectManager : IConnectManager
- {
- private readonly SemaphoreSlim _operationLock = new SemaphoreSlim(1, 1);
-
- private readonly ILogger _logger;
- private readonly IApplicationPaths _appPaths;
- private readonly IJsonSerializer _json;
- private readonly IEncryptionManager _encryption;
- private readonly IHttpClient _httpClient;
- private readonly IServerApplicationHost _appHost;
- private readonly IServerConfigurationManager _config;
- private readonly IUserManager _userManager;
- private readonly IProviderManager _providerManager;
- private readonly ISecurityManager _securityManager;
- private readonly IFileSystem _fileSystem;
-
- private ConnectData _data = new ConnectData();
-
- public string ConnectServerId
- {
- get { return _data.ServerId; }
- }
- public string ConnectAccessKey
- {
- get { return _data.AccessKey; }
- }
-
- private IpAddressInfo DiscoveredWanIpAddress { get; set; }
-
- public string WanIpAddress
- {
- get
- {
- var address = _config.Configuration.WanDdns;
-
- if (!string.IsNullOrWhiteSpace(address))
- {
- Uri newUri;
-
- if (Uri.TryCreate(address, UriKind.Absolute, out newUri))
- {
- address = newUri.Host;
- }
- }
-
- if (string.IsNullOrWhiteSpace(address) && DiscoveredWanIpAddress != null)
- {
- if (DiscoveredWanIpAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
- {
- address = "[" + DiscoveredWanIpAddress + "]";
- }
- else
- {
- address = DiscoveredWanIpAddress.ToString();
- }
- }
-
- return address;
- }
- }
-
- public string WanApiAddress
- {
- get
- {
- var ip = WanIpAddress;
-
- if (!string.IsNullOrEmpty(ip))
- {
- if (!ip.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
- !ip.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
- {
- ip = (_appHost.EnableHttps ? "https://" : "http://") + ip;
- }
-
- ip += ":";
- ip += _appHost.EnableHttps ? _config.Configuration.PublicHttpsPort.ToString(CultureInfo.InvariantCulture) : _config.Configuration.PublicPort.ToString(CultureInfo.InvariantCulture);
-
- return ip;
- }
-
- return null;
- }
- }
-
- private string XApplicationValue
- {
- get { return _appHost.Name + "/" + _appHost.ApplicationVersion; }
- }
-
- public ConnectManager(ILogger logger,
- IApplicationPaths appPaths,
- IJsonSerializer json,
- IEncryptionManager encryption,
- IHttpClient httpClient,
- IServerApplicationHost appHost,
- IServerConfigurationManager config, IUserManager userManager, IProviderManager providerManager, ISecurityManager securityManager, IFileSystem fileSystem)
- {
- _logger = logger;
- _appPaths = appPaths;
- _json = json;
- _encryption = encryption;
- _httpClient = httpClient;
- _appHost = appHost;
- _config = config;
- _userManager = userManager;
- _providerManager = providerManager;
- _securityManager = securityManager;
- _fileSystem = fileSystem;
-
- LoadCachedData();
- }
-
- internal void Start()
- {
- _config.ConfigurationUpdated += _config_ConfigurationUpdated;
- }
-
- internal void OnWanAddressResolved(IpAddressInfo address)
- {
- DiscoveredWanIpAddress = address;
-
- var task = UpdateConnectInfo();
- }
-
- private async Task UpdateConnectInfo()
- {
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- await UpdateConnectInfoInternal().ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task UpdateConnectInfoInternal()
- {
- var wanApiAddress = WanApiAddress;
-
- if (string.IsNullOrWhiteSpace(wanApiAddress))
- {
- _logger.Warn("Cannot update Emby Connect information without a WanApiAddress");
- return;
- }
-
- try
- {
- var localAddress = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
-
- var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) &&
- !string.IsNullOrWhiteSpace(ConnectAccessKey);
-
- var createNewRegistration = !hasExistingRecord;
-
- if (hasExistingRecord)
- {
- try
- {
- await UpdateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false);
- }
- catch (HttpException ex)
- {
- if (!ex.StatusCode.HasValue || !new[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }.Contains(ex.StatusCode.Value))
- {
- throw;
- }
-
- createNewRegistration = true;
- }
- }
-
- if (createNewRegistration)
- {
- await CreateServerRegistration(wanApiAddress, localAddress).ConfigureAwait(false);
- }
-
- _lastReportedIdentifier = GetConnectReportingIdentifier(localAddress, wanApiAddress);
-
- await RefreshAuthorizationsInternal(true, CancellationToken.None).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error registering with Connect", ex);
- }
- }
-
- private string _lastReportedIdentifier;
- private async Task GetConnectReportingIdentifier()
- {
- var url = await _appHost.GetLocalApiUrl().ConfigureAwait(false);
- return GetConnectReportingIdentifier(url, WanApiAddress);
- }
- private string GetConnectReportingIdentifier(string localAddress, string remoteAddress)
- {
- return (remoteAddress ?? string.Empty) + (localAddress ?? string.Empty);
- }
-
- async void _config_ConfigurationUpdated(object sender, EventArgs e)
- {
- // If info hasn't changed, don't report anything
- var connectIdentifier = await GetConnectReportingIdentifier().ConfigureAwait(false);
- if (string.Equals(_lastReportedIdentifier, connectIdentifier, StringComparison.OrdinalIgnoreCase))
- {
- return;
- }
-
- await UpdateConnectInfo().ConfigureAwait(false);
- }
-
- private async Task CreateServerRegistration(string wanApiAddress, string localAddress)
- {
- if (string.IsNullOrWhiteSpace(wanApiAddress))
- {
- throw new ArgumentNullException("wanApiAddress");
- }
-
- var url = "Servers";
- url = GetConnectUrl(url);
-
- var postData = new Dictionary
- {
- {"name", _appHost.FriendlyName},
- {"url", wanApiAddress},
- {"systemId", _appHost.SystemId}
- };
-
- if (!string.IsNullOrWhiteSpace(localAddress))
- {
- postData["localAddress"] = localAddress;
- }
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- options.SetPostData(postData);
- SetApplicationHeader(options);
-
- using (var response = await _httpClient.Post(options).ConfigureAwait(false))
- {
- var data = _json.DeserializeFromStream(response.Content);
-
- _data.ServerId = data.Id;
- _data.AccessKey = data.AccessKey;
-
- CacheData();
- }
- }
-
- private async Task UpdateServerRegistration(string wanApiAddress, string localAddress)
- {
- if (string.IsNullOrWhiteSpace(wanApiAddress))
- {
- throw new ArgumentNullException("wanApiAddress");
- }
-
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var url = "Servers";
- url = GetConnectUrl(url);
- url += "?id=" + ConnectServerId;
-
- var postData = new Dictionary
- {
- {"name", _appHost.FriendlyName},
- {"url", wanApiAddress},
- {"systemId", _appHost.SystemId}
- };
-
- if (!string.IsNullOrWhiteSpace(localAddress))
- {
- postData["localAddress"] = localAddress;
- }
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- }
- }
-
- private readonly object _dataFileLock = new object();
- private string CacheFilePath
- {
- get { return Path.Combine(_appPaths.DataPath, "connect.txt"); }
- }
-
- private void CacheData()
- {
- var path = CacheFilePath;
-
- try
- {
- _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
-
- var json = _json.SerializeToString(_data);
-
- var encrypted = _encryption.EncryptString(json);
-
- lock (_dataFileLock)
- {
- _fileSystem.WriteAllText(path, encrypted, Encoding.UTF8);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error saving data", ex);
- }
- }
-
- private void LoadCachedData()
- {
- var path = CacheFilePath;
-
- _logger.Info("Loading data from {0}", path);
-
- try
- {
- lock (_dataFileLock)
- {
- var encrypted = _fileSystem.ReadAllText(path, Encoding.UTF8);
-
- var json = _encryption.DecryptString(encrypted);
-
- _data = _json.DeserializeFromString(json);
- }
- }
- catch (IOException)
- {
- // File isn't there. no biggie
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error loading data", ex);
- }
- }
-
- private User GetUser(string id)
- {
- var user = _userManager.GetUserById(id);
-
- if (user == null)
- {
- throw new ArgumentException("User not found.");
- }
-
- return user;
- }
-
- private string GetConnectUrl(string handler)
- {
- return "https://connect.emby.media/service/" + handler;
- }
-
- public async Task LinkUser(string userId, string connectUsername)
- {
- if (string.IsNullOrWhiteSpace(userId))
- {
- throw new ArgumentNullException("userId");
- }
- if (string.IsNullOrWhiteSpace(connectUsername))
- {
- throw new ArgumentNullException("connectUsername");
- }
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- await UpdateConnectInfo().ConfigureAwait(false);
- }
-
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- return await LinkUserInternal(userId, connectUsername).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task LinkUserInternal(string userId, string connectUsername)
- {
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var connectUser = await GetConnectUser(new ConnectUserQuery
- {
- NameOrEmail = connectUsername
-
- }, CancellationToken.None).ConfigureAwait(false);
-
- if (!connectUser.IsActive)
- {
- throw new ArgumentException("The Emby account has been disabled.");
- }
-
- var existingUser = _userManager.Users.FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUser.Id) && !string.IsNullOrWhiteSpace(i.ConnectAccessKey));
- if (existingUser != null)
- {
- throw new InvalidOperationException("This connect user is already linked to local user " + existingUser.Name);
- }
-
- var user = GetUser(userId);
-
- if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
- {
- await RemoveConnect(user, user.ConnectUserId).ConfigureAwait(false);
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var accessToken = Guid.NewGuid().ToString("N");
-
- var postData = new Dictionary
- {
- {"serverId", ConnectServerId},
- {"userId", connectUser.Id},
- {"userType", "Linked"},
- {"accessToken", accessToken}
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- var result = new UserLinkResult();
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- var response = _json.DeserializeFromStream(stream);
-
- result.IsPending = string.Equals(response.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase);
- }
-
- user.ConnectAccessKey = accessToken;
- user.ConnectUserName = connectUser.Name;
- user.ConnectUserId = connectUser.Id;
- user.ConnectLinkType = UserLinkType.LinkedUser;
-
- await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
-
- await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
-
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
-
- return result;
- }
-
- public async Task InviteUser(ConnectAuthorizationRequest request)
- {
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- await UpdateConnectInfo().ConfigureAwait(false);
- }
-
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- return await InviteUserInternal(request).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task InviteUserInternal(ConnectAuthorizationRequest request)
- {
- var connectUsername = request.ConnectUserName;
- var sendingUserId = request.SendingUserId;
-
- if (string.IsNullOrWhiteSpace(connectUsername))
- {
- throw new ArgumentNullException("connectUsername");
- }
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var sendingUser = GetUser(sendingUserId);
- var requesterUserName = sendingUser.ConnectUserName;
-
- if (string.IsNullOrWhiteSpace(requesterUserName))
- {
- throw new ArgumentException("A Connect account is required in order to send invitations.");
- }
-
- string connectUserId = null;
- var result = new UserLinkResult();
-
- try
- {
- var connectUser = await GetConnectUser(new ConnectUserQuery
- {
- NameOrEmail = connectUsername
-
- }, CancellationToken.None).ConfigureAwait(false);
-
- if (!connectUser.IsActive)
- {
- throw new ArgumentException("The Emby account is not active. Please ensure the account has been activated by following the instructions within the email confirmation.");
- }
-
- connectUserId = connectUser.Id;
- result.GuestDisplayName = connectUser.Name;
- }
- catch (HttpException ex)
- {
- if (!ex.StatusCode.HasValue || ex.IsTimedOut)
- {
- throw new Exception("Unable to invite guest, " + ex.Message, ex);
- }
-
- // If they entered a username, then whatever the error is just throw it, for example, user not found
- if (!Validator.EmailIsValid(connectUsername))
- {
- if (ex.StatusCode.Value == HttpStatusCode.NotFound)
- {
- throw new ResourceNotFoundException();
- }
- throw;
- }
-
- if (ex.StatusCode.Value != HttpStatusCode.NotFound)
- {
- throw;
- }
- }
-
- if (string.IsNullOrWhiteSpace(connectUserId))
- {
- return await SendNewUserInvitation(requesterUserName, connectUsername).ConfigureAwait(false);
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var accessToken = Guid.NewGuid().ToString("N");
-
- var postData = new Dictionary
- {
- {"serverId", ConnectServerId},
- {"userId", connectUserId},
- {"userType", "Guest"},
- {"accessToken", accessToken},
- {"requesterUserName", requesterUserName}
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- var response = _json.DeserializeFromStream(stream);
-
- result.IsPending = string.Equals(response.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase);
-
- _data.PendingAuthorizations.Add(new ConnectAuthorizationInternal
- {
- ConnectUserId = response.UserId,
- Id = response.Id,
- ImageUrl = response.UserImageUrl,
- UserName = response.UserName,
- EnabledLibraries = request.EnabledLibraries,
- EnabledChannels = request.EnabledChannels,
- EnableLiveTv = request.EnableLiveTv,
- AccessToken = accessToken
- });
-
- CacheData();
- }
-
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
-
- return result;
- }
-
- private async Task SendNewUserInvitation(string fromName, string email)
- {
- var url = GetConnectUrl("users/invite");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var postData = new Dictionary
- {
- {"email", email},
- {"requesterUserName", fromName}
- };
-
- options.SetPostData(postData);
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var stream = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
- {
- }
-
- return new UserLinkResult
- {
- IsNewUserInvitation = true,
- GuestDisplayName = email
- };
- }
-
- public Task RemoveConnect(string userId)
- {
- var user = GetUser(userId);
-
- return RemoveConnect(user, user.ConnectUserId);
- }
-
- private async Task RemoveConnect(User user, string connectUserId)
- {
- if (!string.IsNullOrWhiteSpace(connectUserId))
- {
- await CancelAuthorizationByConnectUserId(connectUserId).ConfigureAwait(false);
- }
-
- user.ConnectAccessKey = null;
- user.ConnectUserName = null;
- user.ConnectUserId = null;
- user.ConnectLinkType = null;
-
- await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false);
- }
-
- private async Task GetConnectUser(ConnectUserQuery query, CancellationToken cancellationToken)
- {
- var url = GetConnectUrl("user");
-
- if (!string.IsNullOrWhiteSpace(query.Id))
- {
- url = url + "?id=" + WebUtility.UrlEncode(query.Id);
- }
- else if (!string.IsNullOrWhiteSpace(query.NameOrEmail))
- {
- url = url + "?nameOrEmail=" + WebUtility.UrlEncode(query.NameOrEmail);
- }
- else if (!string.IsNullOrWhiteSpace(query.Name))
- {
- url = url + "?name=" + WebUtility.UrlEncode(query.Name);
- }
- else if (!string.IsNullOrWhiteSpace(query.Email))
- {
- url = url + "?name=" + WebUtility.UrlEncode(query.Email);
- }
- else
- {
- throw new ArgumentException("Empty ConnectUserQuery supplied");
- }
-
- var options = new HttpRequestOptions
- {
- CancellationToken = cancellationToken,
- Url = url,
- BufferContent = false
- };
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
- {
- var response = _json.DeserializeFromStream(stream);
-
- return new ConnectUser
- {
- Email = response.Email,
- Id = response.Id,
- Name = response.Name,
- IsActive = response.IsActive,
- ImageUrl = response.ImageUrl
- };
- }
- }
-
- private void SetApplicationHeader(HttpRequestOptions options)
- {
- options.RequestHeaders.Add("X-Application", XApplicationValue);
- }
-
- private void SetServerAccessToken(HttpRequestOptions options)
- {
- if (string.IsNullOrWhiteSpace(ConnectAccessKey))
- {
- throw new ArgumentNullException("ConnectAccessKey");
- }
-
- options.RequestHeaders.Add("X-Connect-Token", ConnectAccessKey);
- }
-
- public async Task RefreshAuthorizations(CancellationToken cancellationToken)
- {
- await _operationLock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
- try
- {
- await RefreshAuthorizationsInternal(true, cancellationToken).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task RefreshAuthorizationsInternal(bool refreshImages, CancellationToken cancellationToken)
- {
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- url += "?serverId=" + ConnectServerId;
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = cancellationToken,
- BufferContent = false
- };
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- try
- {
- using (var stream = (await _httpClient.SendAsync(options, "GET").ConfigureAwait(false)).Content)
- {
- var list = _json.DeserializeFromStream>(stream);
-
- await RefreshAuthorizations(list, refreshImages).ConfigureAwait(false);
- }
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing server authorizations.", ex);
- }
- }
-
- private async Task RefreshAuthorizations(List list, bool refreshImages)
- {
- var users = _userManager.Users.ToList();
-
- // Handle existing authorizations that were removed by the Connect server
- // Handle existing authorizations whose status may have been updated
- foreach (var user in users)
- {
- if (!string.IsNullOrWhiteSpace(user.ConnectUserId))
- {
- var connectEntry = list.FirstOrDefault(i => string.Equals(i.UserId, user.ConnectUserId, StringComparison.OrdinalIgnoreCase));
-
- if (connectEntry == null)
- {
- var deleteUser = user.ConnectLinkType.HasValue &&
- user.ConnectLinkType.Value == UserLinkType.Guest;
-
- user.ConnectUserId = null;
- user.ConnectAccessKey = null;
- user.ConnectUserName = null;
- user.ConnectLinkType = null;
-
- await _userManager.UpdateUser(user).ConfigureAwait(false);
-
- if (deleteUser)
- {
- _logger.Debug("Deleting guest user {0}", user.Name);
- await _userManager.DeleteUser(user).ConfigureAwait(false);
- }
- }
- else
- {
- var changed = !string.Equals(user.ConnectAccessKey, connectEntry.AccessToken, StringComparison.OrdinalIgnoreCase);
-
- if (changed)
- {
- user.ConnectUserId = connectEntry.UserId;
- user.ConnectAccessKey = connectEntry.AccessToken;
-
- await _userManager.UpdateUser(user).ConfigureAwait(false);
- }
- }
- }
- }
-
- var currentPendingList = _data.PendingAuthorizations.ToList();
- var newPendingList = new List();
-
- foreach (var connectEntry in list)
- {
- if (string.Equals(connectEntry.UserType, "guest", StringComparison.OrdinalIgnoreCase))
- {
- var currentPendingEntry = currentPendingList.FirstOrDefault(i => string.Equals(i.Id, connectEntry.Id, StringComparison.OrdinalIgnoreCase));
-
- if (string.Equals(connectEntry.AcceptStatus, "accepted", StringComparison.OrdinalIgnoreCase))
- {
- var user = _userManager.Users
- .FirstOrDefault(i => string.Equals(i.ConnectUserId, connectEntry.UserId, StringComparison.OrdinalIgnoreCase));
-
- if (user == null)
- {
- // Add user
- user = await _userManager.CreateUser(_userManager.MakeValidUsername(connectEntry.UserName)).ConfigureAwait(false);
-
- user.ConnectUserName = connectEntry.UserName;
- user.ConnectUserId = connectEntry.UserId;
- user.ConnectLinkType = UserLinkType.Guest;
- user.ConnectAccessKey = connectEntry.AccessToken;
-
- await _userManager.UpdateUser(user).ConfigureAwait(false);
-
- user.Policy.IsHidden = true;
- user.Policy.EnableLiveTvManagement = false;
- user.Policy.EnableContentDeletion = false;
- user.Policy.EnableRemoteControlOfOtherUsers = false;
- user.Policy.EnableSharedDeviceControl = false;
- user.Policy.IsAdministrator = false;
-
- if (currentPendingEntry != null)
- {
- user.Policy.EnabledFolders = currentPendingEntry.EnabledLibraries;
- user.Policy.EnableAllFolders = false;
-
- user.Policy.EnabledChannels = currentPendingEntry.EnabledChannels;
- user.Policy.EnableAllChannels = false;
-
- user.Policy.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv;
- }
-
- await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration);
- }
- }
- else if (string.Equals(connectEntry.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase))
- {
- currentPendingEntry = currentPendingEntry ?? new ConnectAuthorizationInternal();
-
- currentPendingEntry.ConnectUserId = connectEntry.UserId;
- currentPendingEntry.ImageUrl = connectEntry.UserImageUrl;
- currentPendingEntry.UserName = connectEntry.UserName;
- currentPendingEntry.Id = connectEntry.Id;
- currentPendingEntry.AccessToken = connectEntry.AccessToken;
-
- newPendingList.Add(currentPendingEntry);
- }
- }
- }
-
- _data.PendingAuthorizations = newPendingList;
-
- if (!newPendingList.Select(i => i.Id).SequenceEqual(currentPendingList.Select(i => i.Id), StringComparer.Ordinal))
- {
- CacheData();
- }
-
- await RefreshGuestNames(list, refreshImages).ConfigureAwait(false);
- }
-
- private async Task RefreshGuestNames(List list, bool refreshImages)
- {
- var users = _userManager.Users
- .Where(i => !string.IsNullOrEmpty(i.ConnectUserId) && i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest)
- .ToList();
-
- foreach (var user in users)
- {
- var authorization = list.FirstOrDefault(i => string.Equals(i.UserId, user.ConnectUserId, StringComparison.Ordinal));
-
- if (authorization == null)
- {
- _logger.Warn("Unable to find connect authorization record for user {0}", user.Name);
- continue;
- }
-
- var syncConnectName = true;
- var syncConnectImage = true;
-
- if (syncConnectName)
- {
- var changed = !string.Equals(authorization.UserName, user.Name, StringComparison.OrdinalIgnoreCase);
-
- if (changed)
- {
- await user.Rename(authorization.UserName).ConfigureAwait(false);
- }
- }
-
- if (syncConnectImage)
- {
- var imageUrl = authorization.UserImageUrl;
-
- if (!string.IsNullOrWhiteSpace(imageUrl))
- {
- var changed = false;
-
- if (!user.HasImage(ImageType.Primary))
- {
- changed = true;
- }
- else if (refreshImages)
- {
- using (var response = await _httpClient.SendAsync(new HttpRequestOptions
- {
- Url = imageUrl,
- BufferContent = false
-
- }, "HEAD").ConfigureAwait(false))
- {
- var length = response.ContentLength;
-
- if (length != _fileSystem.GetFileInfo(user.GetImageInfo(ImageType.Primary, 0).Path).Length)
- {
- changed = true;
- }
- }
- }
-
- if (changed)
- {
- await _providerManager.SaveImage(user, imageUrl, ImageType.Primary, null, CancellationToken.None).ConfigureAwait(false);
-
- await user.RefreshMetadata(new MetadataRefreshOptions(_fileSystem)
- {
- ForceSave = true,
-
- }, CancellationToken.None).ConfigureAwait(false);
- }
- }
- }
- }
- }
-
- public async Task> GetPendingGuests()
- {
- var time = DateTime.UtcNow - _data.LastAuthorizationsRefresh;
-
- if (time.TotalMinutes >= 5)
- {
- await _operationLock.WaitAsync(CancellationToken.None).ConfigureAwait(false);
-
- try
- {
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
-
- _data.LastAuthorizationsRefresh = DateTime.UtcNow;
- CacheData();
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error refreshing authorization", ex);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- return _data.PendingAuthorizations.Select(i => new ConnectAuthorization
- {
- ConnectUserId = i.ConnectUserId,
- EnableLiveTv = i.EnableLiveTv,
- EnabledChannels = i.EnabledChannels,
- EnabledLibraries = i.EnabledLibraries,
- Id = i.Id,
- ImageUrl = i.ImageUrl,
- UserName = i.UserName
-
- }).ToList();
- }
-
- public async Task CancelAuthorization(string id)
- {
- await _operationLock.WaitAsync().ConfigureAwait(false);
-
- try
- {
- await CancelAuthorizationInternal(id).ConfigureAwait(false);
- }
- finally
- {
- _operationLock.Release();
- }
- }
-
- private async Task CancelAuthorizationInternal(string id)
- {
- var connectUserId = _data.PendingAuthorizations
- .First(i => string.Equals(i.Id, id, StringComparison.Ordinal))
- .ConnectUserId;
-
- await CancelAuthorizationByConnectUserId(connectUserId).ConfigureAwait(false);
-
- await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false);
- }
-
- private async Task CancelAuthorizationByConnectUserId(string connectUserId)
- {
- if (string.IsNullOrWhiteSpace(connectUserId))
- {
- throw new ArgumentNullException("connectUserId");
- }
- if (string.IsNullOrWhiteSpace(ConnectServerId))
- {
- throw new ArgumentNullException("ConnectServerId");
- }
-
- var url = GetConnectUrl("ServerAuthorizations");
-
- var options = new HttpRequestOptions
- {
- Url = url,
- CancellationToken = CancellationToken.None,
- BufferContent = false
- };
-
- var postData = new Dictionary
- {
- {"serverId", ConnectServerId},
- {"userId", connectUserId}
- };
-
- options.SetPostData(postData);
-
- SetServerAccessToken(options);
- SetApplicationHeader(options);
-
- try
- {
- // No need to examine the response
- using (var stream = (await _httpClient.SendAsync(options, "DELETE").ConfigureAwait(false)).Content)
- {
- }
- }
- catch (HttpException ex)
- {
- // If connect says the auth doesn't exist, we can handle that gracefully since this is a remove operation
-
- if (!ex.StatusCode.HasValue || ex.StatusCode.Value != HttpStatusCode.NotFound)
- {
- throw;
- }
-
- _logger.Debug("Connect returned a 404 when removing a user auth link. Handling it.");
- }
- }
-
- public async Task Authenticate(string username, string passwordMd5)
- {
- if (string.IsNullOrWhiteSpace(username))
- {
- throw new ArgumentNullException("username");
- }
-
- if (string.IsNullOrWhiteSpace(passwordMd5))
- {
- throw new ArgumentNullException("passwordMd5");
- }
-
- var options = new HttpRequestOptions
- {
- Url = GetConnectUrl("user/authenticate"),
- BufferContent = false
- };
-
- options.SetPostData(new Dictionary
- {
- {"userName",username},
- {"password",passwordMd5}
- });
-
- SetApplicationHeader(options);
-
- // No need to examine the response
- using (var response = (await _httpClient.SendAsync(options, "POST").ConfigureAwait(false)).Content)
- {
- return _json.DeserializeFromStream(response);
- }
- }
-
- public async Task GetLocalUser(string connectUserId)
- {
- var user = _userManager.Users
- .FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUserId, StringComparison.OrdinalIgnoreCase));
-
- if (user == null)
- {
- await RefreshAuthorizations(CancellationToken.None).ConfigureAwait(false);
- }
-
- return _userManager.Users
- .FirstOrDefault(i => string.Equals(i.ConnectUserId, connectUserId, StringComparison.OrdinalIgnoreCase));
- }
-
- public User GetUserFromExchangeToken(string token)
- {
- if (string.IsNullOrWhiteSpace(token))
- {
- throw new ArgumentNullException("token");
- }
-
- return _userManager.Users.FirstOrDefault(u => string.Equals(token, u.ConnectAccessKey, StringComparison.OrdinalIgnoreCase));
- }
-
- public bool IsAuthorizationTokenValid(string token)
- {
- if (string.IsNullOrWhiteSpace(token))
- {
- throw new ArgumentNullException("token");
- }
-
- return _userManager.Users.Any(u => string.Equals(token, u.ConnectAccessKey, StringComparison.OrdinalIgnoreCase)) ||
- _data.PendingAuthorizations.Select(i => i.AccessToken).Contains(token, StringComparer.OrdinalIgnoreCase);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/Responses.cs b/Emby.Server.Implementations/Connect/Responses.cs
deleted file mode 100644
index 87cb6cdf9..000000000
--- a/Emby.Server.Implementations/Connect/Responses.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Connect;
-
-namespace Emby.Server.Implementations.Connect
-{
- public class ServerRegistrationResponse
- {
- public string Id { get; set; }
- public string Url { get; set; }
- public string Name { get; set; }
- public string AccessKey { get; set; }
- }
-
- public class UpdateServerRegistrationResponse
- {
- public string Id { get; set; }
- public string Url { get; set; }
- public string Name { get; set; }
- }
-
- public class GetConnectUserResponse
- {
- public string Id { get; set; }
- public string Name { get; set; }
- public string DisplayName { get; set; }
- public string Email { get; set; }
- public bool IsActive { get; set; }
- public string ImageUrl { get; set; }
- }
-
- public class ServerUserAuthorizationResponse
- {
- public string Id { get; set; }
- public string ServerId { get; set; }
- public string UserId { get; set; }
- public string AccessToken { get; set; }
- public string DateCreated { get; set; }
- public bool IsActive { get; set; }
- public string AcceptStatus { get; set; }
- public string UserType { get; set; }
- public string UserImageUrl { get; set; }
- public string UserName { get; set; }
- }
-
- public class ConnectUserPreferences
- {
- public string[] PreferredAudioLanguages { get; set; }
- public bool PlayDefaultAudioTrack { get; set; }
- public string[] PreferredSubtitleLanguages { get; set; }
- public SubtitlePlaybackMode SubtitleMode { get; set; }
- public bool GroupMoviesIntoBoxSets { get; set; }
-
- public ConnectUserPreferences()
- {
- PreferredAudioLanguages = new string[] { };
- PreferredSubtitleLanguages = new string[] { };
- }
-
- public static ConnectUserPreferences FromUserConfiguration(UserConfiguration config)
- {
- return new ConnectUserPreferences
- {
- PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
- SubtitleMode = config.SubtitleMode,
- PreferredAudioLanguages = string.IsNullOrWhiteSpace(config.AudioLanguagePreference) ? new string[] { } : new[] { config.AudioLanguagePreference },
- PreferredSubtitleLanguages = string.IsNullOrWhiteSpace(config.SubtitleLanguagePreference) ? new string[] { } : new[] { config.SubtitleLanguagePreference }
- };
- }
-
- public void MergeInto(UserConfiguration config)
- {
-
- }
- }
-
- public class UserPreferencesDto
- {
- public T data { get; set; }
- }
-
- public class ConnectAuthorizationInternal : ConnectAuthorization
- {
- public string AccessToken { get; set; }
- }
-}
diff --git a/Emby.Server.Implementations/Connect/Validator.cs b/Emby.Server.Implementations/Connect/Validator.cs
deleted file mode 100644
index 5c94fa71c..000000000
--- a/Emby.Server.Implementations/Connect/Validator.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System.Text.RegularExpressions;
-
-namespace Emby.Server.Implementations.Connect
-{
- public static class Validator
- {
- static readonly Regex ValidEmailRegex = CreateValidEmailRegex();
-
- ///
- /// Taken from http://haacked.com/archive/2007/08/21/i-knew-how-to-validate-an-email-address-until-i.aspx
- ///
- ///
- private static Regex CreateValidEmailRegex()
- {
- const string validEmailPattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
- + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?
+
+
+
@@ -46,11 +49,7 @@
-
-
-
-
-
+
@@ -179,6 +178,7 @@
+
@@ -213,6 +213,7 @@
+
diff --git a/Emby.Server.Core/UnhandledExceptionWriter.cs b/Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs
similarity index 60%
rename from Emby.Server.Core/UnhandledExceptionWriter.cs
rename to Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs
index 5147be9e7..5183f3a0b 100644
--- a/Emby.Server.Core/UnhandledExceptionWriter.cs
+++ b/Emby.Server.Implementations/Logging/UnhandledExceptionWriter.cs
@@ -2,20 +2,25 @@
using MediaBrowser.Model.Logging;
using System;
using System.IO;
+using MediaBrowser.Model.IO;
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations.Logging
{
public class UnhandledExceptionWriter
{
private readonly IApplicationPaths _appPaths;
private readonly ILogger _logger;
private readonly ILogManager _logManager;
+ private readonly IFileSystem _fileSystem;
+ private readonly IConsoleLogger _console;
- public UnhandledExceptionWriter(IApplicationPaths appPaths, ILogger logger, ILogManager logManager)
+ public UnhandledExceptionWriter(IApplicationPaths appPaths, ILogger logger, ILogManager logManager, IFileSystem fileSystem, IConsoleLogger console)
{
_appPaths = appPaths;
_logger = logger;
_logManager = logManager;
+ _fileSystem = fileSystem;
+ _console = console;
}
public void Log(Exception ex)
@@ -24,15 +29,15 @@ namespace Emby.Server.Core
_logManager.Flush();
var path = Path.Combine(_appPaths.LogDirectoryPath, "unhandled_" + Guid.NewGuid() + ".txt");
- Directory.CreateDirectory(Path.GetDirectoryName(path));
+ _fileSystem.CreateDirectory(Path.GetDirectoryName(path));
var builder = LogHelper.GetLogMessage(ex);
// Write to console just in case file logging fails
- Console.WriteLine("UnhandledException");
- Console.WriteLine(builder.ToString());
-
- File.WriteAllText(path, builder.ToString());
+ _console.WriteLine("UnhandledException");
+ _console.WriteLine(builder.ToString());
+
+ _fileSystem.WriteAllText(path, builder.ToString());
}
}
}
diff --git a/Emby.Server.Core/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs
similarity index 95%
rename from Emby.Server.Core/ServerApplicationPaths.cs
rename to Emby.Server.Implementations/ServerApplicationPaths.cs
index dc80b773c..b4b2bb139 100644
--- a/Emby.Server.Core/ServerApplicationPaths.cs
+++ b/Emby.Server.Implementations/ServerApplicationPaths.cs
@@ -1,8 +1,9 @@
-using System.IO;
-using Emby.Common.Implementations;
+using System;
+using System.IO;
+using Emby.Server.Implementations.AppBase;
using MediaBrowser.Controller;
-namespace Emby.Server.Core
+namespace Emby.Server.Implementations
{
///
/// Extends BaseApplicationPaths to add paths that are only applicable on the server
@@ -12,8 +13,8 @@ namespace Emby.Server.Core
///
/// Initializes a new instance of the class.
///
- public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath)
- : base(programDataPath, appFolderPath)
+ public ServerApplicationPaths(string programDataPath, string appFolderPath, string applicationResourcesPath, Action createDirectoryFn)
+ : base(programDataPath, appFolderPath, createDirectoryFn)
{
ApplicationResourcesPath = applicationResourcesPath;
}
diff --git a/MediaBrowser.Model/Logging/IConsoleLogger.cs b/MediaBrowser.Model/Logging/IConsoleLogger.cs
new file mode 100644
index 000000000..a8c282d65
--- /dev/null
+++ b/MediaBrowser.Model/Logging/IConsoleLogger.cs
@@ -0,0 +1,7 @@
+namespace MediaBrowser.Model.Logging
+{
+ public interface IConsoleLogger
+ {
+ void WriteLine(string message);
+ }
+}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index c50ee984e..b796effa1 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -135,6 +135,7 @@
+
diff --git a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
index 27001d596..7dd92b5e8 100644
--- a/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
+++ b/MediaBrowser.Server.Mono/MediaBrowser.Server.Mono.csproj
@@ -61,6 +61,9 @@
..\ThirdParty\emby\Emby.Common.Implementations.dll
+
+ ..\ThirdParty\emby\Emby.Server.Connect.dll
+
..\ThirdParty\emby\Emby.Server.Core.dll
diff --git a/MediaBrowser.Server.Mono/MonoAppHost.cs b/MediaBrowser.Server.Mono/MonoAppHost.cs
index 93ced1186..32f6b74ce 100644
--- a/MediaBrowser.Server.Mono/MonoAppHost.cs
+++ b/MediaBrowser.Server.Mono/MonoAppHost.cs
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using Emby.Server.Connect;
using Emby.Server.Core;
using Emby.Server.Implementations;
-using Emby.Server.Implementations.FFMpeg;
+using MediaBrowser.Controller.Connect;
using MediaBrowser.IsoMounter;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
@@ -26,6 +27,11 @@ namespace MediaBrowser.Server.Mono
}
}
+ protected override IConnectManager CreateConnectManager()
+ {
+ return new ConnectManager();
+ }
+
protected override void RestartInternal()
{
MainClass.Restart(StartupOptions);
@@ -46,6 +52,7 @@ namespace MediaBrowser.Server.Mono
var list = new List();
list.Add(typeof(LinuxIsoManager).Assembly);
+ list.Add(typeof(ConnectManager).Assembly);
return list;
}
diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs
index 4790378a9..649283410 100644
--- a/MediaBrowser.Server.Mono/Program.cs
+++ b/MediaBrowser.Server.Mono/Program.cs
@@ -16,8 +16,11 @@ using Emby.Common.Implementations.Logging;
using Emby.Common.Implementations.Networking;
using Emby.Common.Implementations.Security;
using Emby.Server.Core;
+using Emby.Server.Core.Logging;
using Emby.Server.Implementations;
using Emby.Server.Implementations.IO;
+using Emby.Server.Implementations.Logging;
+using MediaBrowser.Model.IO;
using MediaBrowser.Model.System;
using MediaBrowser.Server.Startup.Common.IO;
using Mono.Unix.Native;
@@ -32,6 +35,7 @@ namespace MediaBrowser.Server.Mono
private static ApplicationHost _appHost;
private static ILogger _logger;
+ private static IFileSystem FileSystem;
public static void Main(string[] args)
{
@@ -98,7 +102,9 @@ namespace MediaBrowser.Server.Mono
var appFolderPath = Path.GetDirectoryName(applicationPath);
- return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath));
+ Action createDirectoryFn = s => Directory.CreateDirectory(s);
+
+ return new ServerApplicationPaths(programDataPath, appFolderPath, Path.GetDirectoryName(applicationPath), createDirectoryFn);
}
private static readonly TaskCompletionSource ApplicationTaskCompletionSource = new TaskCompletionSource();
@@ -111,6 +117,8 @@ namespace MediaBrowser.Server.Mono
var fileSystem = new MonoFileSystem(logManager.GetLogger("FileSystem"), false, false, appPaths.TempDirectory);
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
+ FileSystem = fileSystem;
+
var environmentInfo = GetEnvironmentInfo();
var imageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => _appHost.HttpClient, appPaths);
@@ -247,7 +255,7 @@ namespace MediaBrowser.Server.Mono
{
var exception = (Exception)e.ExceptionObject;
- new UnhandledExceptionWriter(_appHost.ServerConfigurationManager.ApplicationPaths, _logger, _appHost.LogManager).Log(exception);
+ new UnhandledExceptionWriter(_appHost.ServerConfigurationManager.ApplicationPaths, _logger, _appHost.LogManager, FileSystem, new ConsoleLogger()).Log(exception);
if (!Debugger.IsAttached)
{
diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs
index c42cd0396..b41e7607c 100644
--- a/MediaBrowser.ServerApplication/MainStartup.cs
+++ b/MediaBrowser.ServerApplication/MainStartup.cs
@@ -23,11 +23,14 @@ using Emby.Common.Implementations.Logging;
using Emby.Common.Implementations.Networking;
using Emby.Common.Implementations.Security;
using Emby.Server.Core;
+using Emby.Server.Core.Logging;
using Emby.Server.Implementations;
using Emby.Server.Implementations.Browser;
using Emby.Server.Implementations.IO;
+using Emby.Server.Implementations.Logging;
using ImageMagickSharp;
using MediaBrowser.Common.Net;
+using MediaBrowser.Model.IO;
using MediaBrowser.Server.Startup.Common.IO;
namespace MediaBrowser.ServerApplication
@@ -47,6 +50,8 @@ namespace MediaBrowser.ServerApplication
public static string ApplicationPath;
+ private static IFileSystem FileSystem;
+
public static bool TryGetLocalFromUncDirectory(string local, out string unc)
{
if ((local == null) || (local == ""))
@@ -259,16 +264,18 @@ namespace MediaBrowser.ServerApplication
var resourcesPath = Path.GetDirectoryName(applicationPath);
+ Action createDirectoryFn = s => Directory.CreateDirectory(s);
+
if (runAsService)
{
var systemPath = Path.GetDirectoryName(applicationPath);
var programDataPath = Path.GetDirectoryName(systemPath);
- return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath);
+ return new ServerApplicationPaths(programDataPath, appFolderPath, resourcesPath, createDirectoryFn);
}
- return new ServerApplicationPaths(ApplicationPathHelper.GetProgramDataPath(applicationPath), appFolderPath, resourcesPath);
+ return new ServerApplicationPaths(ApplicationPathHelper.GetProgramDataPath(applicationPath), appFolderPath, resourcesPath, createDirectoryFn);
}
///
@@ -330,6 +337,8 @@ namespace MediaBrowser.ServerApplication
var imageEncoder = ImageEncoderHelper.GetImageEncoder(_logger, logManager, fileSystem, options, () => _appHost.HttpClient, appPaths);
+ FileSystem = fileSystem;
+
_appHost = new WindowsAppHost(appPaths,
logManager,
options,
@@ -580,7 +589,7 @@ namespace MediaBrowser.ServerApplication
{
var exception = (Exception)e.ExceptionObject;
- new UnhandledExceptionWriter(_appHost.ServerConfigurationManager.ApplicationPaths, _logger, _appHost.LogManager).Log(exception);
+ new UnhandledExceptionWriter(_appHost.ServerConfigurationManager.ApplicationPaths, _logger, _appHost.LogManager, FileSystem, new ConsoleLogger()).Log(exception);
if (!IsRunningAsService)
{
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index 8a75bf67a..656b295c2 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -67,6 +67,9 @@
..\ThirdParty\emby\Emby.Common.Implementations.dll
+
+ ..\ThirdParty\emby\Emby.Server.Connect.dll
+
..\ThirdParty\emby\Emby.Server.Core.dll
diff --git a/MediaBrowser.ServerApplication/WindowsAppHost.cs b/MediaBrowser.ServerApplication/WindowsAppHost.cs
index 9d19525b4..d4753f57a 100644
--- a/MediaBrowser.ServerApplication/WindowsAppHost.cs
+++ b/MediaBrowser.ServerApplication/WindowsAppHost.cs
@@ -4,10 +4,12 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices.ComTypes;
+using Emby.Server.Connect;
using Emby.Server.Core;
using Emby.Server.Implementations;
using Emby.Server.Implementations.EntryPoints;
using Emby.Server.Implementations.FFMpeg;
+using MediaBrowser.Controller.Connect;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.System;
@@ -27,6 +29,11 @@ namespace MediaBrowser.ServerApplication
get { return MainStartup.IsRunningAsService; }
}
+ protected override IConnectManager CreateConnectManager()
+ {
+ return new ConnectManager();
+ }
+
protected override void RestartInternal()
{
MainStartup.Restart();
@@ -41,6 +48,7 @@ namespace MediaBrowser.ServerApplication
//list.Add(typeof(PismoIsoManager).Assembly);
}
+ list.Add(typeof(ConnectManager).Assembly);
list.Add(GetType().Assembly);
return list;
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 292c80a7c..fdc2b9f7d 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Common.Internal
- 3.0.680
+ 3.0.681
Emby.Common.Internal
Luke
ebr,Luke,scottisafool
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 4bb58cd73..95cee8be1 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Common
- 3.0.694
+ 3.0.695
Emby.Common
Emby Team
ebr,Luke,scottisafool
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index c475a4c91..f703690a9 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -2,7 +2,7 @@
MediaBrowser.Server.Core
- 3.0.694
+ 3.0.695
Emby.Server.Core
Emby Team
ebr,Luke,scottisafool
@@ -12,7 +12,7 @@
Contains core components required to build plugins for Emby Server.
Copyright © Emby 2013
-
+
diff --git a/SharedVersion.cs b/SharedVersion.cs
index 7d9fa0d70..740e72b1a 100644
--- a/SharedVersion.cs
+++ b/SharedVersion.cs
@@ -1,3 +1,3 @@
using System.Reflection;
-[assembly: AssemblyVersion("3.2.1.111")]
+[assembly: AssemblyVersion("3.2.1.112")]