From 076a75b82f4cbfa74f02ff29d7098c325a9b9017 Mon Sep 17 00:00:00 2001 From: tidusjar Date: Thu, 21 Apr 2016 12:10:36 +0100 Subject: [PATCH] Stop the Cachers from bombing out when the response from the 3rd party api returns an exception or invalid response. #171 --- PlexRequests.Api/ApiRequest.cs | 23 ++++++---- PlexRequests.Api/CouchPotatoApi.cs | 18 ++++++-- PlexRequests.Api/PlexApi.cs | 32 ++++++++++---- PlexRequests.Api/SickrageApi.cs | 17 +++++++- PlexRequests.Api/SonarrApi.cs | 12 +++++- PlexRequests.Api/TheMovieDbApi.cs | 4 +- PlexRequests.Api/TheTvDbApi.cs | 3 ++ .../Exceptions/ApiRequestException.cs | 42 +++++++++++++++++++ .../PlexRequests.Helpers.csproj | 1 + PlexRequests.UI.Tests/AdminModuleTests.cs | 9 +++- PlexRequests.UI.Tests/UserLoginModuleTests.cs | 3 ++ PlexRequests.UI/Modules/SearchModule.cs | 3 -- 12 files changed, 138 insertions(+), 29 deletions(-) create mode 100644 PlexRequests.Helpers/Exceptions/ApiRequestException.cs diff --git a/PlexRequests.Api/ApiRequest.cs b/PlexRequests.Api/ApiRequest.cs index d3c26066c..b5ffa8c76 100644 --- a/PlexRequests.Api/ApiRequest.cs +++ b/PlexRequests.Api/ApiRequest.cs @@ -25,7 +25,6 @@ // ************************************************************************/ #endregion using System; -using System.Collections.Generic; using System.IO; using System.Xml.Serialization; @@ -34,14 +33,15 @@ using Newtonsoft.Json; using NLog; using PlexRequests.Api.Interfaces; -using PlexRequests.Helpers; +using PlexRequests.Helpers.Exceptions; + using RestSharp; namespace PlexRequests.Api { public class ApiRequest : IApiRequest { - private JsonSerializerSettings Settings = new JsonSerializerSettings + private readonly JsonSerializerSettings _settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore @@ -66,7 +66,8 @@ namespace PlexRequests.Api if (response.ErrorException != null) { var message = "Error retrieving response. Check inner details for more info."; - throw new ApplicationException(message, response.ErrorException); + Log.Error(response.ErrorException); + throw new ApiRequestException(message, response.ErrorException); } return response.Data; @@ -80,8 +81,9 @@ namespace PlexRequests.Api if (response.ErrorException != null) { + Log.Error(response.ErrorException); var message = "Error retrieving response. Check inner details for more info."; - throw new ApplicationException(message, response.ErrorException); + throw new ApiRequestException(message, response.ErrorException); } return response; @@ -95,8 +97,9 @@ namespace PlexRequests.Api if (response.ErrorException != null) { + Log.Error(response.ErrorException); var message = "Error retrieving response. Check inner details for more info."; - throw new ApplicationException(message, response.ErrorException); + throw new ApiRequestException(message, response.ErrorException); } var result = DeserializeXml(response.Content); @@ -112,12 +115,13 @@ namespace PlexRequests.Api Log.Trace(response.Content); if (response.ErrorException != null) { + Log.Error(response.ErrorException); var message = "Error retrieving response. Check inner details for more info."; - throw new ApplicationException(message, response.ErrorException); + throw new ApiRequestException(message, response.ErrorException); } Log.Trace("Deserialzing Object"); - var json = JsonConvert.DeserializeObject(response.Content, Settings); + var json = JsonConvert.DeserializeObject(response.Content, _settings); Log.Trace("Finished Deserialzing Object"); return json; @@ -133,8 +137,9 @@ namespace PlexRequests.Api using (var sr = new StringReader(input)) return (T)ser.Deserialize(sr); } - catch (InvalidOperationException) + catch (InvalidOperationException e) { + Log.Error(e); return null; } } diff --git a/PlexRequests.Api/CouchPotatoApi.cs b/PlexRequests.Api/CouchPotatoApi.cs index 88cc07075..9db43a409 100644 --- a/PlexRequests.Api/CouchPotatoApi.cs +++ b/PlexRequests.Api/CouchPotatoApi.cs @@ -31,6 +31,7 @@ using Newtonsoft.Json.Linq; using NLog; using PlexRequests.Api.Interfaces; using PlexRequests.Api.Models.Movie; +using PlexRequests.Helpers.Exceptions; using RestSharp; @@ -118,13 +119,22 @@ namespace PlexRequests.Api public CouchPotatoMovies GetMovies(Uri baseUrl, string apiKey, string[] status) { - RestRequest request; - request = new RestRequest { Resource = "/api/{apikey}/movie.list?status={status}" }; + var request = new RestRequest + { + Resource = "/api/{apikey}/movie.list?status={status}" + }; request.AddUrlSegment("apikey", apiKey); request.AddUrlSegment("status", string.Join(",", status)); - - return Api.Execute(request, baseUrl); + try + { + return Api.Execute(request, baseUrl); + } + catch (ApiRequestException) // Request error is already logged in the ApiRequest class + { + Log.Error("Error when attempting to GetMovies."); + return new CouchPotatoMovies(); + } } } } \ No newline at end of file diff --git a/PlexRequests.Api/PlexApi.cs b/PlexRequests.Api/PlexApi.cs index a91355c63..cbe06e3a6 100644 --- a/PlexRequests.Api/PlexApi.cs +++ b/PlexRequests.Api/PlexApi.cs @@ -26,14 +26,14 @@ #endregion using System; +using NLog; + using PlexRequests.Api.Interfaces; -using PlexRequests.Api.Models; using PlexRequests.Api.Models.Plex; using PlexRequests.Helpers; +using PlexRequests.Helpers.Exceptions; using RestSharp; -using System.Xml; -using System.Collections.Generic; namespace PlexRequests.Api { @@ -43,6 +43,8 @@ namespace PlexRequests.Api { Version = AssemblyHelper.GetAssemblyVersion(); } + + private static Logger Log = LogManager.GetCurrentClassLogger(); private static string Version { get; } public PlexAuthentication SignIn(string username, string password) @@ -148,9 +150,16 @@ namespace PlexRequests.Api AddHeaders(ref request, authToken); var api = new ApiRequest(); - var sections = api.ExecuteXml(request, plexFullHost); + try + { - return sections; + return api.ExecuteXml(request, plexFullHost); + } + catch (ApiRequestException) + { + Log.Error("There has been a API Exception when attempting to get the Plex Libraries"); + return new PlexLibraries(); + } } public PlexSearch GetLibrary(string authToken, Uri plexFullHost, string libraryId) @@ -161,13 +170,20 @@ namespace PlexRequests.Api Resource = "library/sections/{libraryId}/all" }; - request.AddUrlSegment("libraryId", libraryId.ToString()); + request.AddUrlSegment("libraryId", libraryId); AddHeaders(ref request, authToken); var api = new ApiRequest(); - var search = api.ExecuteXml(request, plexFullHost); + try + { - return search; + return api.ExecuteXml(request, plexFullHost); + } + catch (ApiRequestException) + { + Log.Error("There has been a API Exception when attempting to get the Plex Library"); + return new PlexSearch(); + } } private void AddHeaders(ref RestRequest request, string authToken) diff --git a/PlexRequests.Api/SickrageApi.cs b/PlexRequests.Api/SickrageApi.cs index 7d5aca913..e600d5aec 100644 --- a/PlexRequests.Api/SickrageApi.cs +++ b/PlexRequests.Api/SickrageApi.cs @@ -41,6 +41,8 @@ using PlexRequests.Helpers; using RestSharp; using Newtonsoft.Json.Linq; +using PlexRequests.Helpers.Exceptions; + namespace PlexRequests.Api { public class SickrageApi : ISickRageApi @@ -218,7 +220,20 @@ namespace PlexRequests.Api }; request.AddUrlSegment("apiKey", apiKey); - return await Task.Run(() => Api.Execute(request, baseUrl)).ConfigureAwait(false); + return await Task.Run( + () => + { + try + { + return Api.Execute(request, baseUrl); + } + catch (ApiRequestException) + { + Log.Error("There has been a API exception when Getting the Sickrage shows"); + return null; + } + + }).ConfigureAwait(false); } } } \ No newline at end of file diff --git a/PlexRequests.Api/SonarrApi.cs b/PlexRequests.Api/SonarrApi.cs index e9e1e96ad..3d160187a 100644 --- a/PlexRequests.Api/SonarrApi.cs +++ b/PlexRequests.Api/SonarrApi.cs @@ -38,6 +38,8 @@ using PlexRequests.Helpers; using RestSharp; using Newtonsoft.Json.Linq; +using PlexRequests.Helpers.Exceptions; + namespace PlexRequests.Api { public class SonarrApi : ISonarrApi @@ -128,8 +130,16 @@ namespace PlexRequests.Api { var request = new RestRequest { Resource = "/api/series", Method = Method.GET }; request.AddHeader("X-Api-Key", apiKey); + try + { - return Api.Execute>(request, baseUrl); + return Api.Execute>(request, baseUrl); + } + catch (ApiRequestException) + { + Log.Error("There has been an API exception when getting the Sonarr Series"); + return null; + } } } } \ No newline at end of file diff --git a/PlexRequests.Api/TheMovieDbApi.cs b/PlexRequests.Api/TheMovieDbApi.cs index 6d8fa31ef..ce0d3772c 100644 --- a/PlexRequests.Api/TheMovieDbApi.cs +++ b/PlexRequests.Api/TheMovieDbApi.cs @@ -50,7 +50,7 @@ namespace PlexRequests.Api return results.Results; } - [Obsolete("Should use TheTvDbApi for TV")] + [Obsolete("Should use TvMaze for TV")] public async Task> SearchTv(string searchTerm) { var results = await Client.SearchTvShow(searchTerm); @@ -74,7 +74,7 @@ namespace PlexRequests.Api return movies; } - [Obsolete("Should use TheTvDbApi for TV")] + [Obsolete("Should use TvMaze for TV")] public async Task GetTvShowInformation(int tmdbId) { var show = await Client.GetTvShow(tmdbId); diff --git a/PlexRequests.Api/TheTvDbApi.cs b/PlexRequests.Api/TheTvDbApi.cs index 50c94e7d9..2ac7734f7 100644 --- a/PlexRequests.Api/TheTvDbApi.cs +++ b/PlexRequests.Api/TheTvDbApi.cs @@ -24,12 +24,15 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // ************************************************************************/ #endregion +using System; + using PlexRequests.Api.Models.Tv; using RestSharp; namespace PlexRequests.Api { + [Obsolete("Use TVMazeAPP")] public class TheTvDbApi : TvBase { public TheTvDbApi() diff --git a/PlexRequests.Helpers/Exceptions/ApiRequestException.cs b/PlexRequests.Helpers/Exceptions/ApiRequestException.cs new file mode 100644 index 000000000..e44a8fdec --- /dev/null +++ b/PlexRequests.Helpers/Exceptions/ApiRequestException.cs @@ -0,0 +1,42 @@ +#region Copyright +// /************************************************************************ +// Copyright (c) 2016 Jamie Rees +// File: ApplicationSettingsException.cs +// Created By: Jamie Rees +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// ************************************************************************/ +#endregion +using System; + +namespace PlexRequests.Helpers.Exceptions +{ + public class ApiRequestException : Exception + { + public ApiRequestException(string message) : base(message) + { + + } + public ApiRequestException(string message, Exception innerException) : base(message, innerException) + { + + } + } +} \ No newline at end of file diff --git a/PlexRequests.Helpers/PlexRequests.Helpers.csproj b/PlexRequests.Helpers/PlexRequests.Helpers.csproj index b15baabc3..c8c08a6ec 100644 --- a/PlexRequests.Helpers/PlexRequests.Helpers.csproj +++ b/PlexRequests.Helpers/PlexRequests.Helpers.csproj @@ -53,6 +53,7 @@ + diff --git a/PlexRequests.UI.Tests/AdminModuleTests.cs b/PlexRequests.UI.Tests/AdminModuleTests.cs index e8ae7f04c..77d316deb 100644 --- a/PlexRequests.UI.Tests/AdminModuleTests.cs +++ b/PlexRequests.UI.Tests/AdminModuleTests.cs @@ -45,6 +45,7 @@ using PlexRequests.Store.Repository; using PlexRequests.UI.Models; using PlexRequests.UI.Modules; using PlexRequests.Helpers; +using PlexRequests.UI.Helpers; namespace PlexRequests.UI.Tests { @@ -121,7 +122,13 @@ namespace PlexRequests.UI.Tests with.Dependency(PushoverApi.Object); with.Dependency(NotificationService.Object); with.Dependency(HeadphonesSettings.Object); - with.Dependencies(Cache.Object); + with.Dependency(Cache.Object); + with.ApplicationStartup( + (container, pipelines) => + { + var loc = ServiceLocator.Instance; + loc.SetContainer(container); + }); with.RootPathProvider(); with.RequestStartup((container, pipelines, context) => { diff --git a/PlexRequests.UI.Tests/UserLoginModuleTests.cs b/PlexRequests.UI.Tests/UserLoginModuleTests.cs index eb71e8cd1..d8e5b3e3a 100644 --- a/PlexRequests.UI.Tests/UserLoginModuleTests.cs +++ b/PlexRequests.UI.Tests/UserLoginModuleTests.cs @@ -77,6 +77,9 @@ namespace PlexRequests.UI.Tests with.RootPathProvider(); }); + var loc = ServiceLocator.Instance; + loc.SetContainer(TinyIoCContainer.Current); + bootstrapper.WithSession(new Dictionary()); var browser = new Browser(bootstrapper); diff --git a/PlexRequests.UI/Modules/SearchModule.cs b/PlexRequests.UI/Modules/SearchModule.cs index e6e47cc6e..3001b8511 100644 --- a/PlexRequests.UI/Modules/SearchModule.cs +++ b/PlexRequests.UI/Modules/SearchModule.cs @@ -49,7 +49,6 @@ using PlexRequests.Store; using PlexRequests.UI.Helpers; using PlexRequests.UI.Models; using System.Threading.Tasks; -using TMDbLib.Objects.Search; using PlexRequests.Api.Models.Tv; using TMDbLib.Objects.General; @@ -71,7 +70,6 @@ namespace PlexRequests.UI.Modules CpService = cpSettings; PrService = prSettings; MovieApi = new TheMovieDbApi(); - TvApi = new TheTvDbApi(); Cache = cache; Checker = checker; CpCacher = cpCacher; @@ -108,7 +106,6 @@ namespace PlexRequests.UI.Modules private INotificationService NotificationService { get; } private ICouchPotatoApi CouchPotatoApi { get; } private ISonarrApi SonarrApi { get; } - private TheTvDbApi TvApi { get; } private ISickRageApi SickrageApi { get; } private IRequestService RequestService { get; } private ICacheProvider Cache { get; }