better caching of remote data

This commit is contained in:
Luke Pulverenti
2016-01-02 16:54:37 -05:00
parent 4bf13f7754
commit 821e824687
13 changed files with 79 additions and 294 deletions

View File

@@ -153,66 +153,6 @@ namespace MediaBrowser.Common.Implementations.Security
}
}
public async Task<SupporterInfo> GetSupporterInfo()
{
var key = SupporterKey;
if (string.IsNullOrWhiteSpace(key))
{
return new SupporterInfo();
}
var data = new Dictionary<string, string>
{
{ "key", key },
};
var url = MbAdmin.HttpsUrl + "/service/supporter/retrieve";
using (var stream = await _httpClient.Post(url, data, CancellationToken.None).ConfigureAwait(false))
{
var response = _jsonSerializer.DeserializeFromStream<SuppporterInfoResponse>(stream);
var info = new SupporterInfo
{
Email = response.email,
PlanType = response.planType,
SupporterKey = response.supporterKey,
IsActiveSupporter = IsMBSupporter
};
if (!string.IsNullOrWhiteSpace(response.expDate))
{
DateTime parsedDate;
if (DateTime.TryParse(response.expDate, out parsedDate))
{
info.ExpirationDate = parsedDate;
}
else
{
_logger.Error("Failed to parse expDate: {0}", response.expDate);
}
}
if (!string.IsNullOrWhiteSpace(response.regDate))
{
DateTime parsedDate;
if (DateTime.TryParse(response.regDate, out parsedDate))
{
info.RegistrationDate = parsedDate;
}
else
{
_logger.Error("Failed to parse regDate: {0}", response.regDate);
}
}
info.IsExpiredSupporter = info.ExpirationDate.HasValue && info.ExpirationDate < DateTime.UtcNow && !string.IsNullOrWhiteSpace(info.SupporterKey);
return info;
}
}
/// <summary>
/// Register an app store sale with our back-end. It will validate the transaction with the store
/// and then register the proper feature and then fill in the supporter key on success.

View File

@@ -185,7 +185,7 @@ namespace MediaBrowser.Common.Implementations.Updates
}
}
private Tuple<List<PackageInfo>, DateTime> _lastPackageListResult;
private DateTime _lastPackageUpdateTime;
/// <summary>
/// Gets all available packages.
@@ -194,40 +194,89 @@ namespace MediaBrowser.Common.Implementations.Updates
/// <returns>Task{List{PackageInfo}}.</returns>
public async Task<IEnumerable<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken)
{
if (_lastPackageListResult != null)
using (var stream = await GetCachedPackages(cancellationToken).ConfigureAwait(false))
{
TimeSpan cacheLength;
var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(stream).ToList();
switch (_config.CommonConfiguration.SystemUpdateLevel)
if ((DateTime.UtcNow - _lastPackageUpdateTime) > GetCacheLength())
{
case PackageVersionClass.Beta:
cacheLength = TimeSpan.FromMinutes(30);
break;
case PackageVersionClass.Dev:
cacheLength = TimeSpan.FromMinutes(3);
break;
default:
cacheLength = TimeSpan.FromHours(24);
break;
UpdateCachedPackages(CancellationToken.None, false);
}
if ((DateTime.UtcNow - _lastPackageListResult.Item2) < cacheLength)
{
return _lastPackageListResult.Item1;
}
return packages;
}
}
private string PackageCachePath
{
get { return Path.Combine(_appPaths.CachePath, "serverpackages.json"); }
}
private async Task<Stream> GetCachedPackages(CancellationToken cancellationToken)
{
try
{
return _fileSystem.OpenRead(PackageCachePath);
}
catch (Exception)
{
}
using (var json = await _httpClient.Get(MbAdmin.HttpUrl + "service/MB3Packages.json", cancellationToken).ConfigureAwait(false))
await UpdateCachedPackages(cancellationToken, true).ConfigureAwait(false);
return _fileSystem.OpenRead(PackageCachePath);
}
private readonly SemaphoreSlim _updateSemaphore = new SemaphoreSlim(1, 1);
private async Task UpdateCachedPackages(CancellationToken cancellationToken, bool throwErrors)
{
await _updateSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
cancellationToken.ThrowIfCancellationRequested();
if ((DateTime.UtcNow - _lastPackageUpdateTime) < GetCacheLength())
{
return;
}
var packages = _jsonSerializer.DeserializeFromStream<List<PackageInfo>>(json).ToList();
var tempFile = await _httpClient.GetTempFile(new HttpRequestOptions
{
Url = MbAdmin.HttpUrl + "service/MB3Packages.json",
CancellationToken = cancellationToken,
Progress = new Progress<Double>()
packages = FilterPackages(packages).ToList();
}).ConfigureAwait(false);
_lastPackageListResult = new Tuple<List<PackageInfo>, DateTime>(packages, DateTime.UtcNow);
_fileSystem.CreateDirectory(Path.GetDirectoryName(PackageCachePath));
return _lastPackageListResult.Item1;
_fileSystem.CopyFile(tempFile, PackageCachePath, true);
_lastPackageUpdateTime = DateTime.UtcNow;
}
catch (Exception ex)
{
_logger.ErrorException("Error updating package cache", ex);
if (throwErrors)
{
throw;
}
}
finally
{
_updateSemaphore.Release();
}
}
private TimeSpan GetCacheLength()
{
switch (_config.CommonConfiguration.SystemUpdateLevel)
{
case PackageVersionClass.Beta:
return TimeSpan.FromMinutes(30);
case PackageVersionClass.Dev:
return TimeSpan.FromMinutes(3);
default:
return TimeSpan.FromHours(24);
}
}
@@ -554,7 +603,7 @@ namespace MediaBrowser.Common.Implementations.Updates
if (packageChecksum != Guid.Empty) // support for legacy uploads for now
{
using (var crypto = new MD5CryptoServiceProvider())
using (var stream = new BufferedStream(_fileSystem.OpenRead(tempFile), 100000))
using (var stream = new BufferedStream(_fileSystem.OpenRead(tempFile), 100000))
{
var check = Guid.Parse(BitConverter.ToString(crypto.ComputeHash(stream)).Replace("-", String.Empty));
if (check != packageChecksum)
@@ -569,12 +618,12 @@ namespace MediaBrowser.Common.Implementations.Updates
// Success - move it to the real target
try
{
_fileSystem.CreateDirectory(Path.GetDirectoryName(target));
_fileSystem.CopyFile(tempFile, target, true);
_fileSystem.CreateDirectory(Path.GetDirectoryName(target));
_fileSystem.CopyFile(tempFile, target, true);
//If it is an archive - write out a version file so we know what it is
if (isArchive)
{
File.WriteAllText(target + ".ver", package.versionStr);
File.WriteAllText(target + ".ver", package.versionStr);
}
}
catch (IOException e)