// This NNNCore pattern allows arg checking to happen synchronously, before starting the async operation. private async Task <IHtmlString> GetContentItemCore(string name, string[] extensions, TimeSpan expiresIn) { using (Trace.Activity("GetContentItem " + name)) { ContentItem cachedItem = null; if (ContentCache.TryGetValue(name, out cachedItem) && DateTime.UtcNow < cachedItem.ExpiryUtc) { Trace.Verbose("Cache Valid. Expires at: " + cachedItem.ExpiryUtc.ToString()); return(cachedItem.Content); } Trace.Verbose("Cache Expired."); // Get the file from the content service var filenames = extensions.Select(extension => name + extension).ToArray(); foreach (var filename in filenames) { ContentItem item = await RefreshContentFromFile(filename, cachedItem, expiresIn); if (item != null) { // Cache and return the result Debug.Assert(item.Content != null); ContentCache.AddOrSet(name, item); return(item.Content); } } return(new HtmlString(String.Empty)); } }
// This NNNCore pattern allows arg checking to happen synchronously, before starting the async operation. private async Task <IHtmlString> GetContentItemCore(string name, TimeSpan expiresIn) { using (Trace.Activity("GetContentItem " + name)) { ContentItem cachedItem = null; if (ContentCache.TryGetValue(name, out cachedItem) && DateTime.UtcNow < cachedItem.ExpiryUtc) { Trace.Verbose("Cache Valid. Expires at: " + cachedItem.ExpiryUtc.ToString()); return(cachedItem.Content); } Trace.Verbose("Cache Expired."); // Get the file from the content service string htmlFileName = name + HtmlContentFileExtension; string markdownFileName = name + MarkdownContentFileExtension; foreach (var filename in new[] { htmlFileName, markdownFileName }) { ContentItem item = await RefreshContentFromFile(filename, cachedItem, expiresIn); if (item != null) { // Cache and return the result Debug.Assert(item.Content != null); ContentCache.AddOrSet(name, item); return(item.Content); } } return(new HtmlString(String.Empty)); } }
public void UpdatePackage(Package package) { var packageRegistrationKey = package.PackageRegistrationKey; var updateTerm = new Term("PackageRegistrationKey", packageRegistrationKey.ToString(CultureInfo.InvariantCulture)); if (!package.IsLatest || !package.IsLatestStable) { // Someone passed us in a version which was e.g. just unlisted? Or just not the latest version which is what we want to index. Doesn't really matter. We'll find one to index. package = _packageRepository.GetAll() .Where(p => (p.IsLatest || p.IsLatestStable) && p.PackageRegistrationKey == packageRegistrationKey) .Include(p => p.PackageRegistration) .Include(p => p.PackageRegistration.Owners) .Include(p => p.SupportedFrameworks) .FirstOrDefault(); } // Just update the provided package using (Trace.Activity(String.Format(CultureInfo.CurrentCulture, "Updating Document: {0}", updateTerm.ToString()))) { EnsureIndexWriter(creatingIndex: false); if (package != null) { var indexEntity = new PackageIndexEntity(package); Trace.Information(String.Format(CultureInfo.CurrentCulture, "Updating Lucene Index for: {0} {1} [PackageKey:{2}]", package.PackageRegistration.Id, package.Version, package.Key)); _indexWriter.UpdateDocument(updateTerm, indexEntity.ToDocument()); } else { Trace.Information(String.Format(CultureInfo.CurrentCulture, "Deleting Document: {0}", updateTerm.ToString())); _indexWriter.DeleteDocuments(updateTerm); } _indexWriter.Commit(); } }
public void UpdatePackage(Package package) { var packageRegistrationKey = package.PackageRegistrationKey; // We can't just update that one document. Someone might have unlisted, and therefore changed the IsLatest(Stable) // flags. Update the whole registration, and all curated feeds var packagesForIndexing = GetPackages(lastIndexTime: null, package: package); packagesForIndexing.AddRange(GetCuratedPackages(lastIndexTime: null, package: package)); // Just update the provided package var updateTerm = new Term("PackageRegistrationKey", packageRegistrationKey.ToString(CultureInfo.InvariantCulture)); using (Trace.Activity(String.Format(CultureInfo.CurrentCulture, "Updating Document: {0}", updateTerm.ToString()))) { EnsureIndexWriter(creatingIndex: false); // This will delete existing documents AddPackages(packagesForIndexing, false); _indexWriter.Commit(); } }
private async Task <ContentItem> RefreshContentFromFile(string fileName, ContentItem cachedItem, TimeSpan expiresIn) { using (Trace.Activity("Downloading Content Item: " + fileName)) { IFileReference reference = await FileStorage.GetFileReferenceAsync( Constants.ContentFolderName, fileName, ifNoneMatch : cachedItem?.ContentId); if (reference == null) { Trace.Error("Requested Content File Not Found: " + fileName); return(null); } // Check the content ID to see if it's different if (cachedItem != null && String.Equals(cachedItem.ContentId, reference.ContentId, StringComparison.Ordinal)) { Trace.Verbose("No change to content item. Using Cache"); // Update the expiry time cachedItem.ExpiryUtc = DateTime.UtcNow + expiresIn; Trace.Verbose($"Updating Cache: {fileName} expires at {cachedItem.ExpiryUtc}"); return(cachedItem); } // Retrieve the content Trace.Verbose("Content Item changed. Trying to update..."); try { using (var stream = reference.OpenRead()) { if (stream == null) { Trace.Error("Requested Content File Not Found: " + fileName); return(null); } else { using (Trace.Activity("Reading Content File: " + fileName)) { using (var reader = new StreamReader(stream)) { string text = await reader.ReadToEndAsync(); string content; if (fileName.EndsWith(".md")) { content = new Markdown().Transform(text); } else { content = text; } IHtmlString html = new HtmlString(content.Trim()); // Prep the new item for the cache var expiryTime = DateTime.UtcNow + expiresIn; return(new ContentItem(html, expiryTime, reference.ContentId, DateTime.UtcNow)); } } } } } catch (Exception) { Debug.Assert(false, "owchy oochy - reading content failed"); Trace.Error("Reading updated content failed. Returning cached content instead."); return(cachedItem); } } }
// This NNNCore pattern allows arg checking to happen synchronously, before starting the async operation. private async Task <HtmlString> GetContentItemCore(string name, TimeSpan expiresIn) { using (Trace.Activity("GetContentItem " + name)) { ContentItem item = null; if (ContentCache.TryGetValue(name, out item) && DateTime.UtcNow < item.ExpiryUtc) { Trace.Information("Cache Valid. Expires at: " + item.ExpiryUtc.ToString()); return(item.Content); } Trace.Information("Cache Expired."); // Get the file from the content service string fileName = name + ContentFileExtension; IFileReference reference; using (Trace.Activity("Downloading Content Item: " + fileName)) { reference = await FileStorage.GetFileReferenceAsync( Constants.ContentFolderName, fileName, ifNoneMatch : item == null?null : item.ContentId); } HtmlString result = new HtmlString(String.Empty); if (reference == null) { Trace.Error("Requested Content File Not Found: " + fileName); } else { // Check the content ID to see if it's different if (item != null && String.Equals(item.ContentId, reference.ContentId, StringComparison.Ordinal)) { Trace.Information("No change to content item. Using Cache"); // No change, just use the cache. result = item.Content; } else { // Process the file Trace.Information("Content Item changed. Updating..."); using (var stream = reference.OpenRead()) { if (stream == null) { Trace.Error("Requested Content File Not Found: " + fileName); reference = null; } else { using (Trace.Activity("Reading Content File: " + fileName)) using (var reader = new StreamReader(stream)) { result = new HtmlString(MarkdownProcessor.Transform(await reader.ReadToEndAsync()).Trim()); } } } } } // Prep the new item for the cache item = new ContentItem(result, DateTime.UtcNow + expiresIn, reference == null ? null : reference.ContentId, DateTime.UtcNow); Trace.Information(String.Format("Updating Cache: {0} expires at {1}", name, item.ExpiryUtc)); ContentCache.AddOrSet(name, item); // Return the result return(result); } }