improve httpclient resource disposal

This commit is contained in:
Luke Pulverenti
2017-10-20 12:16:56 -04:00
parent 86226ff97c
commit 060215143f
36 changed files with 664 additions and 601 deletions

View File

@@ -279,39 +279,9 @@ namespace Emby.Server.Implementations.HttpClientManager
public async Task<Stream> Get(HttpRequestOptions options)
{
var response = await GetResponse(options).ConfigureAwait(false);
return response.Content;
}
/// <summary>
/// Performs a GET request and returns the resulting stream
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="resourcePool">The resource pool.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns>
public Task<Stream> Get(string url, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
return Get(new HttpRequestOptions
{
Url = url,
ResourcePool = resourcePool,
CancellationToken = cancellationToken,
BufferContent = resourcePool != null
});
}
/// <summary>
/// Gets the specified URL.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns>
public Task<Stream> Get(string url, CancellationToken cancellationToken)
{
return Get(url, null, cancellationToken);
}
/// <summary>
/// send as an asynchronous operation.
/// </summary>
@@ -589,26 +559,6 @@ namespace Emby.Server.Implementations.HttpClientManager
return response.Content;
}
/// <summary>
/// Performs a POST request
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="postData">Params to add to the POST data.</param>
/// <param name="resourcePool">The resource pool.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>stream on success, null on failure</returns>
public Task<Stream> Post(string url, Dictionary<string, string> postData, SemaphoreSlim resourcePool, CancellationToken cancellationToken)
{
return Post(new HttpRequestOptions
{
Url = url,
ResourcePool = resourcePool,
CancellationToken = cancellationToken,
BufferContent = resourcePool != null
}, postData);
}
/// <summary>
/// Downloads the contents of a given url into a temporary location
/// </summary>
@@ -891,18 +841,6 @@ namespace Emby.Server.Implementations.HttpClientManager
}
}
/// <summary>
/// Posts the specified URL.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="postData">The post data.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{Stream}.</returns>
public Task<Stream> Post(string url, Dictionary<string, string> postData, CancellationToken cancellationToken)
{
return Post(url, postData, null, cancellationToken);
}
private Task<WebResponse> GetResponseAsync(WebRequest request, TimeSpan timeout)
{
var taskCompletion = new TaskCompletionSource<WebResponse>();

View File

@@ -55,10 +55,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
if (season.IndexNumber.HasValue)
{
var seasonNumber = season.IndexNumber.Value;
season.Name = seasonNumber == 0 ?
args.LibraryOptions.SeasonZeroDisplayName :
string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture));
string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture), args.GetLibraryOptions().PreferredMetadataLanguage);
}
return season;

View File

@@ -1463,6 +1463,9 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_timerProvider.AddOrUpdate(timer, false);
await SaveRecordingMetadata(timer, recordPath, seriesPath).ConfigureAwait(false);
CreateRecordingFolders();
TriggerRefresh(recordPath);
EnforceKeepUpTo(timer, seriesPath);
};

View File

@@ -541,27 +541,30 @@ namespace Emby.Server.Implementations.LiveTv.Listings
try
{
using (Stream responce = await Get(options, false, info).ConfigureAwait(false))
using (var httpResponse = await Get(options, false, info).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.Headends>>(responce);
if (root != null)
using (Stream responce = httpResponse.Content)
{
foreach (ScheduleDirect.Headends headend in root)
var root = _jsonSerializer.DeserializeFromStream<List<ScheduleDirect.Headends>>(responce);
if (root != null)
{
foreach (ScheduleDirect.Lineup lineup in headend.lineups)
foreach (ScheduleDirect.Headends headend in root)
{
lineups.Add(new NameIdPair
foreach (ScheduleDirect.Lineup lineup in headend.lineups)
{
Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
Id = lineup.uri.Substring(18)
});
lineups.Add(new NameIdPair
{
Name = string.IsNullOrWhiteSpace(lineup.name) ? lineup.lineup : lineup.name,
Id = lineup.uri.Substring(18)
});
}
}
}
}
else
{
_logger.Info("No lineups available");
else
{
_logger.Info("No lineups available");
}
}
}
}
@@ -671,13 +674,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return await Post(options, false, providerInfo).ConfigureAwait(false);
}
private async Task<Stream> Get(HttpRequestOptions options,
private async Task<HttpResponseInfo> Get(HttpRequestOptions options,
bool enableRetry,
ListingsProviderInfo providerInfo)
{
try
{
return await _httpClient.Get(options).ConfigureAwait(false);
return await _httpClient.SendAsync(options, "GET").ConfigureAwait(false);
}
catch (HttpException ex)
{
@@ -797,11 +800,14 @@ namespace Emby.Server.Implementations.LiveTv.Listings
try
{
using (var response = await Get(options, false, null).ConfigureAwait(false))
using (var httpResponse = await Get(options, false, null).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Lineups>(response);
using (var response = httpResponse.Content)
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Lineups>(response);
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)
@@ -879,53 +885,56 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var list = new List<ChannelInfo>();
using (var response = await Get(httpOptions, true, info).ConfigureAwait(false))
using (var httpResponse = await Get(httpOptions, true, info).ConfigureAwait(false))
{
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
_logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
_logger.Info("Mapping Stations to Channel");
var allStations = root.stations ?? new List<ScheduleDirect.Station>();
foreach (ScheduleDirect.Map map in root.map)
using (var response = httpResponse.Content)
{
var channelNumber = GetChannelNumber(map);
var root = _jsonSerializer.DeserializeFromStream<ScheduleDirect.Channel>(response);
_logger.Info("Found " + root.map.Count + " channels on the lineup on ScheduleDirect");
_logger.Info("Mapping Stations to Channel");
var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
if (station == null)
var allStations = root.stations ?? new List<ScheduleDirect.Station>();
foreach (ScheduleDirect.Map map in root.map)
{
station = new ScheduleDirect.Station
var channelNumber = GetChannelNumber(map);
var station = allStations.FirstOrDefault(item => string.Equals(item.stationID, map.stationID, StringComparison.OrdinalIgnoreCase));
if (station == null)
{
stationID = map.stationID
station = new ScheduleDirect.Station
{
stationID = map.stationID
};
}
var name = channelNumber;
var channelInfo = new ChannelInfo
{
Number = channelNumber,
Name = name
};
}
var name = channelNumber;
var channelInfo = new ChannelInfo
{
Number = channelNumber,
Name = name
};
if (station != null)
{
if (!string.IsNullOrWhiteSpace(station.name))
if (station != null)
{
channelInfo.Name = station.name;
if (!string.IsNullOrWhiteSpace(station.name))
{
channelInfo.Name = station.name;
}
channelInfo.Id = station.stationID;
channelInfo.CallSign = station.callsign;
if (station.logo != null)
{
channelInfo.ImageUrl = station.logo.URL;
channelInfo.HasImage = true;
}
}
channelInfo.Id = station.stationID;
channelInfo.CallSign = station.callsign;
if (station.logo != null)
{
channelInfo.ImageUrl = station.logo.URL;
channelInfo.HasImage = true;
}
list.Add(channelInfo);
}
list.Add(channelInfo);
}
}

View File

@@ -86,16 +86,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
CancellationToken = cancellationToken,
BufferContent = false
};
using (var stream = await _httpClient.Get(options).ConfigureAwait(false))
using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
{
var lineup = JsonSerializer.DeserializeFromStream<List<Channels>>(stream) ?? new List<Channels>();
if (info.ImportFavoritesOnly)
using (var stream = response.Content)
{
lineup = lineup.Where(i => i.Favorite).ToList();
}
var lineup = JsonSerializer.DeserializeFromStream<List<Channels>>(stream) ?? new List<Channels>();
return lineup.Where(i => !i.DRM).ToList();
if (info.ImportFavoritesOnly)
{
lineup = lineup.Where(i => i.Favorite).ToList();
}
return lineup.Where(i => !i.DRM).ToList();
}
}
}
@@ -143,26 +146,29 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
try
{
using (var stream = await _httpClient.Get(new HttpRequestOptions()
using (var response = await _httpClient.SendAsync(new HttpRequestOptions()
{
Url = string.Format("{0}/discover.json", GetApiUrl(info, false)),
CancellationToken = cancellationToken,
TimeoutMs = Convert.ToInt32(TimeSpan.FromSeconds(5).TotalMilliseconds),
BufferContent = false
}).ConfigureAwait(false))
}, "GET").ConfigureAwait(false))
{
var response = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
if (!string.IsNullOrWhiteSpace(info.Id))
using (var stream = response.Content)
{
lock (_modelCache)
{
_modelCache[info.Id] = response;
}
}
var discoverResponse = JsonSerializer.DeserializeFromStream<DiscoverResponse>(stream);
return response;
if (!string.IsNullOrWhiteSpace(info.Id))
{
lock (_modelCache)
{
_modelCache[info.Id] = discoverResponse;
}
}
return discoverResponse;
}
}
}
catch (HttpException ex)

View File

@@ -92,14 +92,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}, "GET").ConfigureAwait(false))
{
Logger.Info("Opened HDHR stream from {0}", url);
Logger.Info("Beginning multicastStream.CopyUntilCancelled");
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath));
using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None))
using (var stream = response.Content)
{
StreamHelper.CopyTo(response.Content, fileStream, 81920, () => Resolve(openTaskCompletionSource), cancellationToken);
Logger.Info("Opened HDHR stream from {0}", url);
Logger.Info("Beginning multicastStream.CopyUntilCancelled");
FileSystem.CreateDirectory(FileSystem.GetDirectoryName(TempFilePath));
using (var fileStream = FileSystem.GetFileStream(TempFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, FileOpenOptions.None))
{
StreamHelper.CopyTo(stream, fileStream, 81920, () => Resolve(openTaskCompletionSource), cancellationToken);
}
}
}
}

View File

@@ -315,6 +315,11 @@ namespace Emby.Server.Implementations.Localization
public string GetLocalizedString(string phrase, string culture)
{
if (string.IsNullOrWhiteSpace(culture))
{
culture = _configurationManager.Configuration.UICulture;
}
var dictionary = GetLocalizationDictionary(culture);
string value;

View File

@@ -88,15 +88,18 @@ namespace Emby.Server.Implementations.News
BufferContent = false
};
using (var stream = await _httpClient.Get(requestOptions).ConfigureAwait(false))
using (var response = await _httpClient.SendAsync(requestOptions, "GET").ConfigureAwait(false))
{
using (var reader = XmlReader.Create(stream))
using (var stream = response.Content)
{
var news = ParseRssItems(reader).ToList();
using (var reader = XmlReader.Create(stream))
{
var news = ParseRssItems(reader).ToList();
_json.SerializeToFile(news, path);
_json.SerializeToFile(news, path);
await CreateNotifications(news, lastUpdate, CancellationToken.None).ConfigureAwait(false);
await CreateNotifications(news, lastUpdate, CancellationToken.None).ConfigureAwait(false);
}
}
}
}

View File

@@ -293,10 +293,13 @@ namespace Emby.Server.Implementations.Security
options.SetPostData(data);
using (var json = (await _httpClient.Post(options).ConfigureAwait(false)).Content)
using (var response = (await _httpClient.Post(options).ConfigureAwait(false)))
{
reg = _jsonSerializer.DeserializeFromStream<RegRecord>(json);
success = true;
using (var json = response.Content)
{
reg = _jsonSerializer.DeserializeFromStream<RegRecord>(json);
success = true;
}
}
if (reg.registered)

View File

@@ -66,19 +66,22 @@ namespace Emby.Server.Implementations.Session
return SendMessage(name, new Dictionary<string, string>(), cancellationToken);
}
private Task SendMessage(string name,
private async Task SendMessage(string name,
Dictionary<string, string> args,
CancellationToken cancellationToken)
{
var url = PostUrl + "/" + name + ToQueryString(args);
return _httpClient.Post(new HttpRequestOptions
using ((await _httpClient.Post(new HttpRequestOptions
{
Url = url,
CancellationToken = cancellationToken,
BufferContent = false
});
}).ConfigureAwait(false)))
{
}
}
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)

View File

@@ -175,13 +175,24 @@ namespace Emby.Server.Implementations.Updates
{ "systemid", _applicationHost.SystemId }
};
using (var json = await _httpClient.Post("https://www.mb3admin.com/admin/service/package/retrieveall?includeAllRuntimes=true", data, cancellationToken).ConfigureAwait(false))
var options = new HttpRequestOptions
{
cancellationToken.ThrowIfCancellationRequested();
Url = "https://www.mb3admin.com/admin/service/package/retrieveall?includeAllRuntimes=true",
CancellationToken = cancellationToken
};
var packages = _jsonSerializer.DeserializeFromStream<PackageInfo[]>(json);
options.SetPostData(data);
return FilterPackages(packages, packageType, applicationVersion);
using (var response = await _httpClient.SendAsync(options, "POST").ConfigureAwait(false))
{
using (var json = response.Content)
{
cancellationToken.ThrowIfCancellationRequested();
var packages = _jsonSerializer.DeserializeFromStream<PackageInfo[]>(json);
return FilterPackages(packages, packageType, applicationVersion);
}
}
}
else