migrate to IHttpClientFactory in SchedulesDirect

This commit is contained in:
crobibero 2020-08-31 11:57:11 -06:00
parent 50a1e35765
commit 652e688cc1

View File

@ -8,6 +8,8 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common; using MediaBrowser.Common;
@ -26,7 +28,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{ {
private readonly ILogger<SchedulesDirect> _logger; private readonly ILogger<SchedulesDirect> _logger;
private readonly IJsonSerializer _jsonSerializer; private readonly IJsonSerializer _jsonSerializer;
private readonly IHttpClient _httpClient; private readonly IHttpClientFactory _httpClientFactory;
private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _tokenSemaphore = new SemaphoreSlim(1, 1);
private readonly IApplicationHost _appHost; private readonly IApplicationHost _appHost;
@ -35,12 +37,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public SchedulesDirect( public SchedulesDirect(
ILogger<SchedulesDirect> logger, ILogger<SchedulesDirect> logger,
IJsonSerializer jsonSerializer, IJsonSerializer jsonSerializer,
IHttpClient httpClient, IHttpClientFactory httpClientFactory,
IApplicationHost appHost) IApplicationHost appHost)
{ {
_logger = logger; _logger = logger;
_jsonSerializer = jsonSerializer; _jsonSerializer = jsonSerializer;
_httpClient = httpClient; _httpClientFactory = httpClientFactory;
_appHost = appHost; _appHost = appHost;
} }
@ -102,38 +104,23 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var requestString = _jsonSerializer.SerializeToString(requestList); var requestString = _jsonSerializer.SerializeToString(requestList);
_logger.LogDebug("Request string for schedules is: {RequestString}", requestString); _logger.LogDebug("Request string for schedules is: {RequestString}", requestString);
var httpOptions = new HttpRequestOptions() using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/schedules");
{ options.Content = new StringContent(requestString, Encoding.UTF8, MediaTypeNames.Application.Json);
Url = ApiUrl + "/schedules", options.Headers.TryAddWithoutValidation("token", token);
UserAgent = UserAgent, using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
CancellationToken = cancellationToken, await using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
LogErrorResponseBody = true, var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(responseStream).ConfigureAwait(false);
RequestContent = requestString
};
httpOptions.RequestHeaders["token"] = token;
using (var response = await Post(httpOptions, true, info).ConfigureAwait(false))
{
var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Day>>(response.Content).ConfigureAwait(false);
_logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
httpOptions = new HttpRequestOptions() using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs");
{ programRequestOptions.Headers.TryAddWithoutValidation("token", token);
Url = ApiUrl + "/programs",
UserAgent = UserAgent,
CancellationToken = cancellationToken,
LogErrorResponseBody = true
};
httpOptions.RequestHeaders["token"] = token;
var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct(); var programsID = dailySchedules.SelectMany(d => d.programs.Select(s => s.programID)).Distinct();
httpOptions.RequestContent = "[\"" + string.Join("\", \"", programsID) + "\"]"; programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json);
using (var innerResponse = await Post(httpOptions, true, info).ConfigureAwait(false)) using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
{ await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponse.Content).ConfigureAwait(false); var programDetails = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ProgramDetails>>(innerResponseStream).ConfigureAwait(false);
var programDict = programDetails.ToDictionary(p => p.programID, y => y); var programDict = programDetails.ToDictionary(p => p.programID, y => y);
var programIdsWithImages = var programIdsWithImages =
@ -190,8 +177,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return programsInfo; return programsInfo;
} }
}
}
private static int GetSizeOrder(ScheduleDirect.ImageData image) private static int GetSizeOrder(ScheduleDirect.ImageData image)
{ {
@ -482,22 +467,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings
imageIdString = imageIdString.TrimEnd(',') + "]"; imageIdString = imageIdString.TrimEnd(',') + "]";
var httpOptions = new HttpRequestOptions() using var message = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/metadata/programs");
{ message.Content = new StringContent(imageIdString, Encoding.UTF8, MediaTypeNames.Application.Json);
Url = ApiUrl + "/metadata/programs",
UserAgent = UserAgent,
CancellationToken = cancellationToken,
RequestContent = imageIdString,
LogErrorResponseBody = true,
};
try try
{ {
using (var innerResponse2 = await Post(httpOptions, true, info).ConfigureAwait(false)) using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false);
{ await using var response = await innerResponse2.Content.ReadAsStreamAsync();
return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>( return await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.ShowImages>>(
innerResponse2.Content).ConfigureAwait(false); response).ConfigureAwait(false);
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -518,22 +496,15 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return lineups; return lineups;
} }
var options = new HttpRequestOptions() using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/headends?country=" + country + "&postalcode=" + location);
{ options.Headers.TryAddWithoutValidation("token", token);
Url = ApiUrl + "/headends?country=" + country + "&postalcode=" + location,
UserAgent = UserAgent,
CancellationToken = cancellationToken,
LogErrorResponseBody = true
};
options.RequestHeaders["token"] = token;
try try
{ {
using (var httpResponse = await Get(options, false, info).ConfigureAwait(false)) using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false);
using (Stream responce = httpResponse.Content) await using var response = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
{
var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(responce).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync<List<ScheduleDirect.Headends>>(response).ConfigureAwait(false);
if (root != null) if (root != null)
{ {
@ -554,7 +525,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("No lineups available"); _logger.LogInformation("No lineups available");
} }
} }
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error getting headends"); _logger.LogError(ex, "Error getting headends");
@ -633,83 +603,46 @@ namespace Emby.Server.Implementations.LiveTv.Listings
} }
} }
private async Task<HttpResponseInfo> Post(HttpRequestOptions options, private async Task<HttpResponseMessage> Send(
HttpRequestMessage options,
bool enableRetry, bool enableRetry,
ListingsProviderInfo providerInfo) ListingsProviderInfo providerInfo,
{
// Schedules direct requires that the client support compression and will return a 400 response without it
options.DecompressionMethod = CompressionMethods.Deflate;
try
{
return await _httpClient.Post(options).ConfigureAwait(false);
}
catch (HttpException ex)
{
_tokens.Clear();
if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
{
enableRetry = false;
}
if (!enableRetry)
{
throw;
}
}
options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
return await Post(options, false, providerInfo).ConfigureAwait(false);
}
private async Task<HttpResponseInfo> Get(HttpRequestOptions options,
bool enableRetry,
ListingsProviderInfo providerInfo)
{
// Schedules direct requires that the client support compression and will return a 400 response without it
options.DecompressionMethod = CompressionMethods.Deflate;
try
{
return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false);
}
catch (HttpException ex)
{
_tokens.Clear();
if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
{
enableRetry = false;
}
if (!enableRetry)
{
throw;
}
}
options.RequestHeaders["token"] = await GetToken(providerInfo, options.CancellationToken).ConfigureAwait(false);
return await Get(options, false, providerInfo).ConfigureAwait(false);
}
private async Task<string> GetTokenInternal(string username, string password,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
var httpOptions = new HttpRequestOptions() try
{ {
Url = ApiUrl + "/token", return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, cancellationToken).ConfigureAwait(false);
UserAgent = UserAgent, }
RequestContent = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", catch (HttpException ex)
CancellationToken = cancellationToken, {
LogErrorResponseBody = true _tokens.Clear();
};
// _logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent);
using (var response = await Post(httpOptions, false, null).ConfigureAwait(false)) if (!ex.StatusCode.HasValue || (int)ex.StatusCode.Value >= 500)
{ {
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(response.Content).ConfigureAwait(false); enableRetry = false;
}
if (!enableRetry)
{
throw;
}
}
options.Headers.TryAddWithoutValidation("token", await GetToken(providerInfo, cancellationToken).ConfigureAwait(false));
return await Send(options, false, providerInfo, cancellationToken).ConfigureAwait(false);
}
private async Task<string> GetTokenInternal(
string username,
string password,
CancellationToken cancellationToken)
{
using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token");
options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json);
using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Token>(stream).ConfigureAwait(false);
if (root.message == "OK") if (root.message == "OK")
{ {
_logger.LogInformation("Authenticated with Schedules Direct token: " + root.token); _logger.LogInformation("Authenticated with Schedules Direct token: " + root.token);
@ -718,7 +651,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message); throw new Exception("Could not authenticate with Schedules Direct Error: " + root.message);
} }
}
private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken) private async Task AddLineupToAccount(ListingsProviderInfo info, CancellationToken cancellationToken)
{ {
@ -736,20 +668,9 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("Adding new LineUp "); _logger.LogInformation("Adding new LineUp ");
var httpOptions = new HttpRequestOptions() using var options = new HttpRequestMessage(HttpMethod.Put, ApiUrl + "/lineups/" + info.ListingsId);
{ options.Headers.TryAddWithoutValidation("token", token);
Url = ApiUrl + "/lineups/" + info.ListingsId, using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, cancellationToken).ConfigureAwait(false);
UserAgent = UserAgent,
CancellationToken = cancellationToken,
LogErrorResponseBody = true,
BufferContent = false
};
httpOptions.RequestHeaders["token"] = token;
using (await _httpClient.SendAsync(httpOptions, HttpMethod.Put).ConfigureAwait(false))
{
}
} }
private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken) private async Task<bool> HasLineup(ListingsProviderInfo info, CancellationToken cancellationToken)
@ -768,26 +689,18 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_logger.LogInformation("Headends on account "); _logger.LogInformation("Headends on account ");
var options = new HttpRequestOptions() using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups");
{ options.Headers.TryAddWithoutValidation("token", token);
Url = ApiUrl + "/lineups",
UserAgent = UserAgent,
CancellationToken = cancellationToken,
LogErrorResponseBody = true
};
options.RequestHeaders["token"] = token;
try try
{ {
using (var httpResponse = await Get(options, false, null).ConfigureAwait(false)) using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false);
using (var response = httpResponse.Content) await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
{ using var response = httpResponse.Content;
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(response).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Lineups>(stream).ConfigureAwait(false);
return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase));
} }
}
catch (HttpException ex) catch (HttpException ex)
{ {
// Apparently we're supposed to swallow this // Apparently we're supposed to swallow this
@ -851,22 +764,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
throw new Exception("token required"); throw new Exception("token required");
} }
var httpOptions = new HttpRequestOptions() using var options = new HttpRequestMessage(HttpMethod.Get, ApiUrl + "/lineups/" + listingsId);
{ options.Headers.TryAddWithoutValidation("token", token);
Url = ApiUrl + "/lineups/" + listingsId,
UserAgent = UserAgent,
CancellationToken = cancellationToken,
LogErrorResponseBody = true,
};
httpOptions.RequestHeaders["token"] = token;
var list = new List<ChannelInfo>(); var list = new List<ChannelInfo>();
using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false)) using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
using (var response = httpResponse.Content) await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
{ var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(stream).ConfigureAwait(false);
var root = await _jsonSerializer.DeserializeFromStreamAsync<ScheduleDirect.Channel>(response).ConfigureAwait(false);
_logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count); _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
_logger.LogInformation("Mapping Stations to Channel"); _logger.LogInformation("Mapping Stations to Channel");
@ -879,19 +784,10 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase)); var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
if (station == null) if (station == null)
{ {
station = new ScheduleDirect.Station station = new ScheduleDirect.Station {stationID = map.stationID};
{
stationID = map.stationID
};
} }
var channelInfo = new ChannelInfo var channelInfo = new ChannelInfo {Id = station.stationID, CallSign = station.callsign, Number = channelNumber, Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name};
{
Id = station.stationID,
CallSign = station.callsign,
Number = channelNumber,
Name = string.IsNullOrWhiteSpace(station.name) ? channelNumber : station.name
};
if (station.logo != null) if (station.logo != null)
{ {
@ -900,7 +796,6 @@ namespace Emby.Server.Implementations.LiveTv.Listings
list.Add(channelInfo); list.Add(channelInfo);
} }
}
return list; return list;
} }