|
|
|
@ -3,9 +3,11 @@ using System.Collections.Generic; |
|
|
|
using System.Linq; |
|
|
|
using System.Threading.Tasks; |
|
|
|
using Microsoft.Extensions.Caching.Distributed; |
|
|
|
using Microsoft.Extensions.Configuration; |
|
|
|
using Microsoft.Extensions.Hosting; |
|
|
|
using Microsoft.Extensions.Logging; |
|
|
|
using Microsoft.Extensions.Options; |
|
|
|
using Nest; |
|
|
|
using Newtonsoft.Json; |
|
|
|
using Volo.Abp; |
|
|
|
using Volo.Abp.Caching; |
|
|
|
@ -26,6 +28,10 @@ namespace Volo.Docs.Documents |
|
|
|
protected IHostEnvironment HostEnvironment { get; } |
|
|
|
private readonly IDocumentFullSearch _documentFullSearch; |
|
|
|
private readonly DocsElasticSearchOptions _docsElasticSearchOptions; |
|
|
|
private readonly IConfiguration _configuration; |
|
|
|
private readonly TimeSpan _cacheTimeout; |
|
|
|
private readonly TimeSpan _documentResourceAbsoluteExpiration; |
|
|
|
private readonly TimeSpan _documentResourceSlidingExpiration; |
|
|
|
|
|
|
|
public DocumentAppService( |
|
|
|
IProjectRepository projectRepository, |
|
|
|
@ -36,7 +42,8 @@ namespace Volo.Docs.Documents |
|
|
|
IDistributedCache<DocumentUpdateInfo> documentUpdateCache, |
|
|
|
IHostEnvironment hostEnvironment, |
|
|
|
IDocumentFullSearch documentFullSearch, |
|
|
|
IOptions<DocsElasticSearchOptions> docsElasticSearchOptions) |
|
|
|
IOptions<DocsElasticSearchOptions> docsElasticSearchOptions, |
|
|
|
IConfiguration configuration) |
|
|
|
{ |
|
|
|
_projectRepository = projectRepository; |
|
|
|
_documentRepository = documentRepository; |
|
|
|
@ -46,7 +53,11 @@ namespace Volo.Docs.Documents |
|
|
|
DocumentUpdateCache = documentUpdateCache; |
|
|
|
HostEnvironment = hostEnvironment; |
|
|
|
_documentFullSearch = documentFullSearch; |
|
|
|
_configuration = configuration; |
|
|
|
_docsElasticSearchOptions = docsElasticSearchOptions.Value; |
|
|
|
_cacheTimeout = GetCacheTimeout(); |
|
|
|
_documentResourceAbsoluteExpiration = GetDocumentResourceAbsoluteExpirationTimeout(); |
|
|
|
_documentResourceSlidingExpiration = GetDocumentResourceSlidingExpirationTimeout(); |
|
|
|
} |
|
|
|
|
|
|
|
public virtual async Task<DocumentWithDetailsDto> GetAsync(GetDocumentInput input) |
|
|
|
@ -132,9 +143,8 @@ namespace Volo.Docs.Documents |
|
|
|
GetResourceAsync, |
|
|
|
() => new DistributedCacheEntryOptions |
|
|
|
{ |
|
|
|
//TODO: Configurable?
|
|
|
|
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(6), |
|
|
|
SlidingExpiration = TimeSpan.FromMinutes(30) |
|
|
|
AbsoluteExpirationRelativeToNow = _documentResourceAbsoluteExpiration, |
|
|
|
SlidingExpiration = _documentResourceSlidingExpiration |
|
|
|
} |
|
|
|
); |
|
|
|
} |
|
|
|
@ -200,48 +210,23 @@ namespace Volo.Docs.Documents |
|
|
|
{ |
|
|
|
version = string.IsNullOrWhiteSpace(version) ? project.LatestVersionBranchName : version; |
|
|
|
|
|
|
|
async Task<DocumentWithDetailsDto> GetDocumentAsync(Document oldDocument = null) |
|
|
|
{ |
|
|
|
Logger.LogInformation($"Not found in the cache. Requesting {documentName} from the source..."); |
|
|
|
|
|
|
|
var source = _documentStoreFactory.Create(project.DocumentStoreType); |
|
|
|
var sourceDocument = await source.GetDocumentAsync(project, documentName, languageCode, version, oldDocument?.LastSignificantUpdateTime); |
|
|
|
|
|
|
|
await _documentRepository.DeleteAsync(project.Id, sourceDocument.Name, sourceDocument.LanguageCode, sourceDocument.Version); |
|
|
|
await _documentRepository.InsertAsync(sourceDocument, true); |
|
|
|
|
|
|
|
Logger.LogInformation($"Document retrieved: {documentName}"); |
|
|
|
|
|
|
|
var cacheKey = $"DocumentUpdateInfo{sourceDocument.ProjectId}#{sourceDocument.Name}#{sourceDocument.LanguageCode}#{sourceDocument.Version}"; |
|
|
|
await DocumentUpdateCache.SetAsync(cacheKey, new DocumentUpdateInfo |
|
|
|
{ |
|
|
|
Name = sourceDocument.Name, |
|
|
|
CreationTime = sourceDocument.CreationTime, |
|
|
|
LastUpdatedTime = sourceDocument.LastUpdatedTime, |
|
|
|
LastSignificantUpdateTime = sourceDocument.LastSignificantUpdateTime |
|
|
|
}); |
|
|
|
|
|
|
|
return CreateDocumentWithDetailsDto(project, sourceDocument); |
|
|
|
} |
|
|
|
|
|
|
|
if (HostEnvironment.IsDevelopment()) |
|
|
|
{ |
|
|
|
return await GetDocumentAsync(); |
|
|
|
return await GetDocumentAsync(documentName, project, languageCode, version); |
|
|
|
} |
|
|
|
|
|
|
|
var document = await _documentRepository.FindAsync(project.Id, documentName, languageCode, version); |
|
|
|
if (document == null) |
|
|
|
{ |
|
|
|
return await GetDocumentAsync(); |
|
|
|
return await GetDocumentAsync(documentName, project, languageCode, version); |
|
|
|
} |
|
|
|
|
|
|
|
//Only the latest version (dev) of the document needs to update the cache.
|
|
|
|
if (!project.LatestVersionBranchName.IsNullOrWhiteSpace() && |
|
|
|
document.Version == project.LatestVersionBranchName && |
|
|
|
//TODO: Configurable cache time?
|
|
|
|
document.LastCachedTime + TimeSpan.FromHours(2) < DateTime.Now) |
|
|
|
document.LastCachedTime + _cacheTimeout < DateTime.Now) |
|
|
|
{ |
|
|
|
return await GetDocumentAsync(document); |
|
|
|
return await GetDocumentAsync(documentName, project, languageCode, version, document); |
|
|
|
} |
|
|
|
|
|
|
|
var cacheKey = $"DocumentUpdateInfo{document.ProjectId}#{document.Name}#{document.LanguageCode}#{document.Version}"; |
|
|
|
@ -263,5 +248,62 @@ namespace Volo.Docs.Documents |
|
|
|
documentDto.Contributors = ObjectMapper.Map<List<DocumentContributor>, List<DocumentContributorDto>>(document.Contributors); |
|
|
|
return documentDto; |
|
|
|
} |
|
|
|
|
|
|
|
private async Task<DocumentWithDetailsDto> GetDocumentAsync(string documentName, Project project, string languageCode, string version, Document oldDocument = null) |
|
|
|
{ |
|
|
|
Logger.LogInformation($"Not found in the cache. Requesting {documentName} from the source..."); |
|
|
|
|
|
|
|
var source = _documentStoreFactory.Create(project.DocumentStoreType); |
|
|
|
var sourceDocument = await source.GetDocumentAsync(project, documentName, languageCode, version, oldDocument?.LastSignificantUpdateTime); |
|
|
|
|
|
|
|
await _documentRepository.DeleteAsync(project.Id, sourceDocument.Name, sourceDocument.LanguageCode, sourceDocument.Version); |
|
|
|
await _documentRepository.InsertAsync(sourceDocument, true); |
|
|
|
|
|
|
|
Logger.LogInformation($"Document retrieved: {documentName}"); |
|
|
|
|
|
|
|
var cacheKey = $"DocumentUpdateInfo{sourceDocument.ProjectId}#{sourceDocument.Name}#{sourceDocument.LanguageCode}#{sourceDocument.Version}"; |
|
|
|
await DocumentUpdateCache.SetAsync(cacheKey, new DocumentUpdateInfo |
|
|
|
{ |
|
|
|
Name = sourceDocument.Name, |
|
|
|
CreationTime = sourceDocument.CreationTime, |
|
|
|
LastUpdatedTime = sourceDocument.LastUpdatedTime, |
|
|
|
LastSignificantUpdateTime = sourceDocument.LastSignificantUpdateTime |
|
|
|
}); |
|
|
|
|
|
|
|
return CreateDocumentWithDetailsDto(project, sourceDocument); |
|
|
|
} |
|
|
|
|
|
|
|
private TimeSpan GetCacheTimeout() |
|
|
|
{ |
|
|
|
var value = _configuration["Volo.Docs:DocumentCacheTimeoutInterval"]; |
|
|
|
if (value.IsNullOrEmpty()) |
|
|
|
{ |
|
|
|
return TimeSpan.FromHours(6); |
|
|
|
} |
|
|
|
|
|
|
|
return TimeSpan.Parse(value); |
|
|
|
} |
|
|
|
|
|
|
|
private TimeSpan GetDocumentResourceAbsoluteExpirationTimeout() |
|
|
|
{ |
|
|
|
var value = _configuration["Volo.Docs:DocumentResource.AbsoluteExpirationRelativeToNow"]; |
|
|
|
if (value.IsNullOrEmpty()) |
|
|
|
{ |
|
|
|
return TimeSpan.FromHours(6); |
|
|
|
} |
|
|
|
|
|
|
|
return TimeSpan.Parse(value); |
|
|
|
} |
|
|
|
|
|
|
|
private TimeSpan GetDocumentResourceSlidingExpirationTimeout() |
|
|
|
{ |
|
|
|
var value = _configuration["Volo.Docs:DocumentResource.SlidingExpiration"]; |
|
|
|
if (value.IsNullOrEmpty()) |
|
|
|
{ |
|
|
|
return TimeSpan.FromMinutes(30); |
|
|
|
} |
|
|
|
|
|
|
|
return TimeSpan.Parse(value); |
|
|
|
} |
|
|
|
} |
|
|
|
} |