diff options
| author | Michalis Adamidis <gsnerf@gsnerf.de> | 2014-08-30 02:05:33 +0200 |
|---|---|---|
| committer | Michalis Adamidis <gsnerf@gsnerf.de> | 2014-08-30 02:05:33 +0200 |
| commit | 7c5613fc51738cb3af1ce3e7ada9eb19a54b3aed (patch) | |
| tree | dfd23a717d87e1da776a74f9952a5fae8f215b4a /MediaBrowser.Server.Implementations/Connect | |
| parent | 5740a4c22d676d0050e875b0bd5455f5a303f5bd (diff) | |
| parent | 6a9dbf6ae85b4e7abcf06f7f29ef9d8b0b890876 (diff) | |
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
Diffstat (limited to 'MediaBrowser.Server.Implementations/Connect')
4 files changed, 364 insertions, 0 deletions
diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectData.cs b/MediaBrowser.Server.Implementations/Connect/ConnectData.cs new file mode 100644 index 000000000..1816b103e --- /dev/null +++ b/MediaBrowser.Server.Implementations/Connect/ConnectData.cs @@ -0,0 +1,17 @@ + +namespace MediaBrowser.Server.Implementations.Connect +{ + public class ConnectData + { + /// <summary> + /// Gets or sets the server identifier. + /// </summary> + /// <value>The server identifier.</value> + public string ServerId { get; set; } + /// <summary> + /// Gets or sets the access key. + /// </summary> + /// <value>The access key.</value> + public string AccessKey { get; set; } + } +} diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs new file mode 100644 index 000000000..2ee78ba01 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs @@ -0,0 +1,125 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Connect; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Model.Logging; +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; + +namespace MediaBrowser.Server.Implementations.Connect +{ + public class ConnectEntryPoint : IServerEntryPoint + { + private Timer _timer; + private readonly IHttpClient _httpClient; + private readonly IApplicationPaths _appPaths; + private readonly ILogger _logger; + private readonly IConnectManager _connectManager; + + private readonly INetworkManager _networkManager; + + public ConnectEntryPoint(IHttpClient httpClient, IApplicationPaths appPaths, ILogger logger, INetworkManager networkManager, IConnectManager connectManager) + { + _httpClient = httpClient; + _appPaths = appPaths; + _logger = logger; + _networkManager = networkManager; + _connectManager = connectManager; + } + + public void Run() + { + LoadCachedAddress(); + + _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(30), TimeSpan.FromHours(24)); + } + + private async void TimerCallback(object state) + { + try + { + using (var stream = await _httpClient.Get(new HttpRequestOptions + { + Url = "http://bot.whatismyipaddress.com/" + + }).ConfigureAwait(false)) + { + using (var reader = new StreamReader(stream)) + { + var address = await reader.ReadToEndAsync().ConfigureAwait(false); + + if (IsValid(address)) + { + ((ConnectManager) _connectManager).OnWanAddressResolved(address); + CacheAddress(address); + } + } + } + } + catch + { + } + } + + private string CacheFilePath + { + get { return Path.Combine(_appPaths.DataPath, "wan.txt"); } + } + + private void CacheAddress(string address) + { + var path = CacheFilePath; + + try + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.WriteAllText(path, address, Encoding.UTF8); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving data", ex); + } + } + + private void LoadCachedAddress() + { + var path = CacheFilePath; + + try + { + var endpoint = File.ReadAllText(path, Encoding.UTF8); + + if (IsValid(endpoint)) + { + ((ConnectManager)_connectManager).OnWanAddressResolved(endpoint); + } + } + catch (IOException) + { + // File isn't there. no biggie + } + catch (Exception ex) + { + _logger.ErrorException("Error loading data", ex); + } + } + + private bool IsValid(string address) + { + IPAddress ipAddress; + return IPAddress.TryParse(address, out ipAddress); + } + + public void Dispose() + { + if (_timer != null) + { + _timer.Dispose(); + _timer = null; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs new file mode 100644 index 000000000..504814fe0 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -0,0 +1,204 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Connect; +using MediaBrowser.Controller.Security; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Serialization; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Connect +{ + public class ConnectManager : IConnectManager + { + 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; + + public string ConnectServerId { get; set; } + public string ConnectAccessKey { get; set; } + + public string WanIpAddress { get; private set; } + + public string WanApiAddress + { + get + { + var ip = WanIpAddress; + + if (!string.IsNullOrEmpty(ip)) + { + if (!ip.StartsWith("http://", StringComparison.OrdinalIgnoreCase) && + !ip.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) + { + ip = "http://" + ip; + } + + return ip + ":" + _config.Configuration.HttpServerPortNumber.ToString(CultureInfo.InvariantCulture); + } + + return null; + } + } + + public ConnectManager(ILogger logger, + IApplicationPaths appPaths, + IJsonSerializer json, + IEncryptionManager encryption, + IHttpClient httpClient, + IServerApplicationHost appHost, + IServerConfigurationManager config) + { + _logger = logger; + _appPaths = appPaths; + _json = json; + _encryption = encryption; + _httpClient = httpClient; + _appHost = appHost; + _config = config; + + LoadCachedData(); + } + + internal void OnWanAddressResolved(string address) + { + WanIpAddress = address; + + UpdateConnectInfo(); + } + + private async void UpdateConnectInfo() + { + var wanApiAddress = WanApiAddress; + + if (string.IsNullOrWhiteSpace(wanApiAddress)) + { + _logger.Warn("Cannot update Media Browser Connect information without a WanApiAddress"); + return; + } + + try + { + var hasExistingRecord = !string.IsNullOrWhiteSpace(ConnectServerId) && + !string.IsNullOrWhiteSpace(ConnectAccessKey); + + if (hasExistingRecord) + { + //await UpdateServerRegistration(wanApiAddress).ConfigureAwait(false); + } + else + { + //await CreateServerRegistration(wanApiAddress).ConfigureAwait(false); + } + } + catch (Exception ex) + { + _logger.ErrorException("Error registering with Connect", ex); + } + } + + private async Task CreateServerRegistration(string wanApiAddress) + { + var url = "Servers"; + url = GetConnectUrl(url); + url += "?Name=" + WebUtility.UrlEncode(_appHost.FriendlyName); + url += "&Url=" + WebUtility.UrlEncode(wanApiAddress); + + using (var stream = await _httpClient.Post(url, new Dictionary<string, string>(), CancellationToken.None).ConfigureAwait(false)) + { + var data = _json.DeserializeFromStream<ServerRegistrationResponse>(stream); + + ConnectServerId = data.Id; + ConnectAccessKey = data.AccessKey; + + CacheData(); + } + } + + private async Task UpdateServerRegistration(string wanApiAddress) + { + var url = "Servers/" + ConnectServerId; + url = GetConnectUrl(url); + url += "?Name=" + WebUtility.UrlEncode(_appHost.FriendlyName); + url += "&Url=" + WebUtility.UrlEncode(wanApiAddress); + + // TODO: Add AccessKey http request header + + // No need to examine the response + using (var stream = await _httpClient.Post(url, new Dictionary<string, string>(), CancellationToken.None).ConfigureAwait(false)) + { + } + } + + private string CacheFilePath + { + get { return Path.Combine(_appPaths.DataPath, "connect.txt"); } + } + + private void CacheData() + { + var path = CacheFilePath; + + try + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + var json = _json.SerializeToString(new ConnectData + { + AccessKey = ConnectAccessKey, + ServerId = ConnectServerId + }); + + var encrypted = _encryption.EncryptString(json); + + File.WriteAllText(path, encrypted, Encoding.UTF8); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving data", ex); + } + } + + private void LoadCachedData() + { + var path = CacheFilePath; + + try + { + var encrypted = File.ReadAllText(path, Encoding.UTF8); + + var json = _encryption.DecryptString(encrypted); + + var data = _json.DeserializeFromString<ConnectData>(json); + + ConnectAccessKey = data.AccessKey; + ConnectServerId = data.ServerId; + } + catch (IOException) + { + // File isn't there. no biggie + } + catch (Exception ex) + { + _logger.ErrorException("Error loading data", ex); + } + } + + private string GetConnectUrl(string handler) + { + return "http://mb3admin.com/admin/connect/" + handler; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Connect/ServerRegistrationResponse.cs b/MediaBrowser.Server.Implementations/Connect/ServerRegistrationResponse.cs new file mode 100644 index 000000000..75c55e26e --- /dev/null +++ b/MediaBrowser.Server.Implementations/Connect/ServerRegistrationResponse.cs @@ -0,0 +1,18 @@ + +namespace MediaBrowser.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; } + } +} |
