public async Task <bool> IsTileKnownToBeMissing(string tileDetail) { var cacheKey = GetCacheKey(tileDetail); using (await MemCacheLock.LockAsync(cacheKey)) return(!string.IsNullOrEmpty(_dataCache.Get <string>(cacheKey))); }
/// <summary> /// Get user preferences /// </summary> private async Task <UserPreferenceData> GetShortCachedUserPreferences() { using (await _lock.LockAsync(((TilePrincipal)User).UserEmail)) { var userPreferences = await prefProxy.GetShortCachedUserPreferences(((TilePrincipal)User).UserEmail, TimeSpan.FromSeconds(10), CustomHeaders); if (userPreferences == null) { throw new ServiceException(HttpStatusCode.BadRequest, new ContractExecutionResult(ContractExecutionStatesEnum.FailedToGetResults, "Failed to retrieve preferences for current user")); } return(userPreferences); } }
private async Task <ResponseContent> ProcessCheckpoint(string clientId, Uri sellerId, string uuidString, string orderQuoteJson, FlowStage flowStage, OrderType orderType) { OrderQuote orderQuote = OpenActiveSerializer.Deserialize <OrderQuote>(orderQuoteJson); if (orderQuote == null || orderQuote.GetType() != typeof(OrderQuote)) { throw new OpenBookingException(new UnexpectedOrderTypeError(), "OrderQuote is required for C1 and C2"); } var(orderId, sellerIdComponents, seller) = await ConstructIdsFromRequest(clientId, sellerId, uuidString, orderType); using (await asyncDuplicateLock.LockAsync(GetParallelLockKey(orderId))) { var orderResponse = await ProcessFlowRequest(ValidateFlowRequest <OrderQuote>(orderId, sellerIdComponents, seller, flowStage, orderQuote), orderQuote); // Return a 409 status code if any OrderItem level errors exist return(ResponseContent.OpenBookingResponse(OpenActiveSerializer.Serialize(orderResponse), orderResponse.OrderedItem.Exists(x => x.Error?.Count > 0) ? HttpStatusCode.Conflict : HttpStatusCode.OK)); } }
public Task <IDisposable> LockAsync() => _asyncLock.LockAsync(_id);
/// <summary> /// Processes the JavaScript request using cruncher and returns the result. /// </summary> /// <param name="context"> /// The current context. /// </param> /// <param name="minify"> /// Whether to minify the output. /// </param> /// <param name="paths"> /// The paths to the resources to crunch. /// </param> /// <returns> /// The <see cref="string"/> representing the processed result. /// </returns> public async Task <string> ProcessJavascriptCrunchAsync(HttpContext context, bool minify, params string[] paths) { string combinedJavaScript = string.Empty; if (paths != null) { string key = string.Join(string.Empty, paths).ToMd5Fingerprint(); using (await Locker.LockAsync(key)) { combinedJavaScript = (string)CacheManager.GetItem(key); if (string.IsNullOrWhiteSpace(combinedJavaScript)) { StringBuilder stringBuilder = new StringBuilder(); CruncherOptions cruncherOptions = new CruncherOptions { MinifyCacheKey = key, Minify = minify, CacheFiles = true, AllowRemoteFiles = CruncherConfiguration.Instance.AllowRemoteDownloads, RemoteFileMaxBytes = CruncherConfiguration.Instance.MaxBytes, RemoteFileTimeout = CruncherConfiguration.Instance.Timeout }; JavaScriptCruncher javaScriptCruncher = new JavaScriptCruncher(cruncherOptions, context); // Loop through and process each file. foreach (string path in paths) { // Local files. if (PreprocessorManager.Instance.AllowedExtensionsRegex.IsMatch(path)) { List <string> files = new List <string>(); // Try to get the file using absolute/relative path if (!ResourceHelper.IsResourceFilenameOnly(path)) { string javaScriptFilePath = ResourceHelper.GetFilePath( path, cruncherOptions.RootFolder, context); if (File.Exists(javaScriptFilePath)) { files.Add(javaScriptFilePath); } } else { // Get the path from the server. // Loop through each possible directory. foreach (string javaScriptFolder in CruncherConfiguration.Instance.JavaScriptPaths) { if (!string.IsNullOrWhiteSpace(javaScriptFolder) && javaScriptFolder.Trim().StartsWith("~/")) { DirectoryInfo directoryInfo = new DirectoryInfo(context.Server.MapPath(javaScriptFolder)); if (directoryInfo.Exists) { files.AddRange( Directory.GetFiles( directoryInfo.FullName, path, SearchOption.AllDirectories)); } } } } if (files.Any()) { // We only want the first file. string first = files.FirstOrDefault(); cruncherOptions.RootFolder = Path.GetDirectoryName(first); stringBuilder.Append(await javaScriptCruncher.CrunchAsync(first)); } } else { // Remote files. string remoteFile = this.GetUrlFromToken(path).ToString(); stringBuilder.Append(await javaScriptCruncher.CrunchAsync(remoteFile)); } } combinedJavaScript = stringBuilder.ToString(); if (minify) { // Minify. combinedJavaScript = javaScriptCruncher.Minify(combinedJavaScript); } this.AddItemToCache(key, combinedJavaScript, javaScriptCruncher.FileMonitors); } } } return(combinedJavaScript); }
/// <summary> /// Processes the image. /// </summary> /// <param name="context"> /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides /// references to the intrinsic server objects /// </param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task"/>. /// </returns> private async Task ProcessImageAsync(HttpContext context) { HttpRequest request = context.Request; string rawUrl = this.GetRequestUrl(request); // Should we ignore this request? if (string.IsNullOrWhiteSpace(rawUrl) || rawUrl.ToUpperInvariant().Contains("IPIGNORE=TRUE")) { return; } // Sometimes the request is url encoded // See https://github.com/JimBobSquarePants/ImageProcessor/issues/478 // This causes a bit of a nightmare as the incoming request is corrupted and cannot be used for splitting // out each url part. This becomes a manual job. string url = rawUrl; string applicationPath = request.ApplicationPath; IImageService currentService = this.GetImageServiceForRequest(url, applicationPath); if (currentService != null) { // Parse url string requestPath, queryString; UrlParser.ParseUrl(url, currentService.Prefix, out requestPath, out queryString); string originalQueryString = queryString; // Replace any presets in the querystring with the actual value. queryString = this.ReplacePresetsInQueryString(queryString); HttpContextWrapper httpContextBase = new HttpContextWrapper(context); // Execute the handler which can change the querystring // LEGACY: #pragma warning disable 618 queryString = this.CheckQuerystringHandler(context, queryString, rawUrl); #pragma warning restore 618 // NEW WAY: ValidatingRequestEventArgs validatingArgs = new ValidatingRequestEventArgs(httpContextBase, queryString); this.OnValidatingRequest(validatingArgs); // If the validation has failed based on events, return if (validatingArgs.Cancel) { ImageProcessorBootstrapper.Instance.Logger.Log <ImageProcessingModule>("Image processing has been cancelled by an event"); return; } // Re-assign based on event handlers queryString = validatingArgs.QueryString; url = Regex.Replace(url, originalQueryString, queryString, RegexOptions.IgnoreCase); // Map the request path if file local. bool isFileLocal = currentService.IsFileLocalService; if (currentService.IsFileLocalService) { requestPath = HostingEnvironment.MapPath(requestPath); } if (string.IsNullOrWhiteSpace(requestPath)) { return; } // Parse any protocol values from settings if no protocol is present. if (currentService.Settings.ContainsKey("Protocol") && (ProtocolRegex.Matches(requestPath).Count == 0 || ProtocolRegex.Matches(requestPath)[0].Index > 0)) { // ReSharper disable once PossibleNullReferenceException requestPath = currentService.Settings["Protocol"] + "://" + requestPath.TrimStart('/'); } // Break out if we don't meet critera. // First check that the request path is valid and whether we are intercepting all requests or the querystring is valid. bool interceptAll = interceptAllRequests != null && interceptAllRequests.Value; if (string.IsNullOrWhiteSpace(requestPath) || (!interceptAll && string.IsNullOrWhiteSpace(queryString))) { return; } // Check whether the path is valid for other requests. // We've already checked the unprefixed requests in GetImageServiceForRequest(). if (!string.IsNullOrWhiteSpace(currentService.Prefix) && !currentService.IsValidRequest(requestPath)) { return; } using (await Locker.LockAsync(rawUrl)) { // Parse the url to see whether we should be doing any work. // If we're not intercepting all requests and we don't have valid instructions we shoul break here. IWebGraphicsProcessor[] processors = null; AnimationProcessMode mode = AnimationProcessMode.First; bool processing = false; if (!string.IsNullOrWhiteSpace(queryString)) { // Attempt to match querystring and processors. processors = ImageFactoryExtensions.GetMatchingProcessors(queryString); // Animation is not a processor but can be a specific request so we should allow it. bool processAnimation; mode = this.ParseAnimationMode(queryString, out processAnimation); // Are we processing or cache busting? processing = processors != null && (processors.Any() || processAnimation); bool cacheBusting = this.ParseCacheBuster(queryString); if (!processing && !cacheBusting) { // No? Someone is either attacking the server or hasn't read the instructions. string message = $"The request {request.Unvalidated.RawUrl} could not be understood by the server due to malformed syntax."; ImageProcessorBootstrapper.Instance.Logger.Log <ImageProcessingModule>(message); return; } } // Create a new cache to help process and cache the request. this.imageCache = (IImageCache)ImageProcessorConfiguration.Instance .ImageCache.GetInstance(requestPath, url, queryString); // Is the file new or updated? bool isNewOrUpdated = await this.imageCache.IsNewOrUpdatedAsync(); string cachedPath = this.imageCache.CachedPath; // Only process if the file has been updated. if (isNewOrUpdated) { // Ok let's get the image byte[] imageBuffer = null; string mimeType; try { imageBuffer = await currentService.GetImage(requestPath); } catch (HttpException ex) { // We want 404's to be handled by IIS so that other handlers/modules can still run. if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound) { ImageProcessorBootstrapper.Instance.Logger.Log <ImageProcessingModule>(ex.Message); return; } } if (imageBuffer == null) { return; } // Using recyclable streams here should dramatically reduce the overhead required using (MemoryStream inStream = MemoryStreamPool.Shared.GetStream("inStream", imageBuffer, 0, imageBuffer.Length)) { // Process the Image. Use a recyclable stream here to reduce the allocations MemoryStream outStream = MemoryStreamPool.Shared.GetStream(); if (!string.IsNullOrWhiteSpace(queryString)) { if (processing) { // Process the image. bool exif = preserveExifMetaData != null && preserveExifMetaData.Value; bool gamma = fixGamma != null && fixGamma.Value; using (ImageFactory imageFactory = new ImageFactory(exif, gamma) { AnimationProcessMode = mode }) { imageFactory.Load(inStream).AutoProcess(processors).Save(outStream); mimeType = imageFactory.CurrentImageFormat.MimeType; } } else { // We're cachebusting. Allow the value to be cached await inStream.CopyToAsync(outStream); mimeType = FormatUtilities.GetFormat(outStream).MimeType; } } else { // We're capturing all requests. await inStream.CopyToAsync(outStream); mimeType = FormatUtilities.GetFormat(outStream).MimeType; } // Fire the post processing event. EventHandler <PostProcessingEventArgs> handler = OnPostProcessing; if (handler != null) { string extension = Path.GetExtension(cachedPath); PostProcessingEventArgs args = new PostProcessingEventArgs { Context = context, ImageStream = outStream, ImageExtension = extension }; handler(this, args); outStream = args.ImageStream; } // Add to the cache. await this.imageCache.AddImageToCacheAsync(outStream, mimeType); // Cleanup outStream.Dispose(); } // Store the response type and cache dependency in the context for later retrieval. context.Items[CachedResponseTypeKey] = mimeType; bool isFileCached = new Uri(cachedPath).IsFile; if (isFileLocal) { if (isFileCached) { // Some services might only provide filename so we can't monitor for the browser. context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath ? new[] { cachedPath } : new[] { requestPath, cachedPath }; } else { context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath ? null : new[] { requestPath }; } } else if (isFileCached) { context.Items[CachedResponseFileDependency] = new[] { cachedPath }; } } // The cached file is valid so just rewrite the path. this.imageCache.RewritePath(context); // Redirect if not a locally store file. if (!new Uri(cachedPath).IsFile) { context.ApplicationInstance.CompleteRequest(); } if (isNewOrUpdated) { // Trim the cache. await this.imageCache.TrimCacheAsync(); } } } }
/// <summary> /// Processes the image. /// </summary> /// <param name="context"> /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides /// references to the intrinsic server objects /// </param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task"/>. /// </returns> private async Task ProcessImageAsync(HttpContext context) { HttpRequest request = context.Request; // Should we ignore this request? if (request.Unvalidated.RawUrl.ToUpperInvariant().Contains("IPIGNORE=TRUE")) { return; } IImageService currentService = this.GetImageServiceForRequest(request); if (currentService != null) { bool isFileLocal = currentService.IsFileLocalService; string url = request.Url.ToString(); bool isLegacy = ProtocolRegex.Matches(url).Count > 1; bool hasMultiParams = url.Count(f => f == '?') > 1; string requestPath; string queryString = string.Empty; string urlParameters = string.Empty; // Legacy support. I'd like to remove this asap. if (isLegacy && hasMultiParams) { // We need to split the querystring to get the actual values we want. string[] paths = url.Split('?'); requestPath = paths[1]; // Handle extension-less urls. if (paths.Length > 3) { queryString = paths[3]; urlParameters = paths[2]; } else if (paths.Length > 1) { queryString = paths[2]; } } else { if (string.IsNullOrWhiteSpace(currentService.Prefix)) { requestPath = currentService.IsFileLocalService ? HostingEnvironment.MapPath(request.Path) : request.Path; queryString = request.QueryString.ToString(); } else { // Parse any protocol values from settings. string protocol = currentService.Settings.ContainsKey("Protocol") ? currentService.Settings["Protocol"] + "://" : currentService.GetType() == typeof(RemoteImageService) ? request.Url.Scheme + "://" : string.Empty; // Handle requests that require parameters. if (hasMultiParams) { string[] paths = url.Split('?'); requestPath = protocol + request.Path.TrimStart('/').Remove(0, currentService.Prefix.Length).TrimStart('/') + "?" + paths[1]; queryString = paths[2]; } else { requestPath = protocol + request.Path.TrimStart('/').Remove(0, currentService.Prefix.Length).TrimStart('/'); queryString = request.QueryString.ToString(); } } } // Replace any presets in the querystring with the actual value. queryString = this.ReplacePresetsInQueryString(queryString); // Execute the handler which can change the querystring queryString = this.CheckQuerystringHandler(context, queryString, request.Unvalidated.RawUrl); // Break out if we don't meet critera. bool interceptAll = interceptAllRequests != null && interceptAllRequests.Value; if (string.IsNullOrWhiteSpace(requestPath) || (!interceptAll && string.IsNullOrWhiteSpace(queryString))) { return; } string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty; string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString); object resourcePath; // More legacy support code. if (hasMultiParams) { resourcePath = string.IsNullOrWhiteSpace(urlParameters) ? new Uri(requestPath, UriKind.RelativeOrAbsolute) : new Uri(requestPath + "?" + urlParameters, UriKind.RelativeOrAbsolute); } else { resourcePath = requestPath; } // Check whether the path is valid for other requests. if (!currentService.IsValidRequest(resourcePath.ToString())) { return; } string combined = requestPath + fullPath + queryString; using (await Locker.LockAsync(combined)) { // Create a new cache to help process and cache the request. this.imageCache = (IImageCache)ImageProcessorConfiguration.Instance .ImageCache.GetInstance(requestPath, fullPath, queryString); // Is the file new or updated? bool isNewOrUpdated = await this.imageCache.IsNewOrUpdatedAsync(); string cachedPath = this.imageCache.CachedPath; // Only process if the file has been updated. if (isNewOrUpdated) { // Process the image. bool exif = preserveExifMetaData != null && preserveExifMetaData.Value; bool gamma = fixGamma != null && fixGamma.Value; AnimationProcessMode mode = this.ParseAnimationMode(queryString); using (ImageFactory imageFactory = new ImageFactory(exif, gamma) { AnimationProcessMode = mode }) { byte[] imageBuffer = null; string mimeType; try { imageBuffer = await currentService.GetImage(resourcePath); } catch (HttpException ex) { // We want 404's to be handled by IIS so that other handlers/modules can still run. if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound) { return; } } if (imageBuffer == null) { return; } using (MemoryStream inStream = new MemoryStream(imageBuffer)) { // Process the Image MemoryStream outStream = new MemoryStream(); if (!string.IsNullOrWhiteSpace(queryString)) { imageFactory.Load(inStream).AutoProcess(queryString).Save(outStream); mimeType = imageFactory.CurrentImageFormat.MimeType; } else { await inStream.CopyToAsync(outStream); mimeType = FormatUtilities.GetFormat(outStream).MimeType; } // Fire the post processing event. EventHandler <PostProcessingEventArgs> handler = OnPostProcessing; if (handler != null) { string extension = Path.GetExtension(cachedPath); PostProcessingEventArgs args = new PostProcessingEventArgs { Context = context, ImageStream = outStream, ImageExtension = extension }; handler(this, args); outStream = args.ImageStream; } // Add to the cache. await this.imageCache.AddImageToCacheAsync(outStream, mimeType); // Cleanup outStream.Dispose(); } // Store the response type and cache dependency in the context for later retrieval. context.Items[CachedResponseTypeKey] = mimeType; bool isFileCached = new Uri(cachedPath).IsFile; if (isFileLocal) { if (isFileCached) { // Some services might only provide filename so we can't monitor for the browser. context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath ? new List <string> { cachedPath } : new List <string> { requestPath, cachedPath }; } else { context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath ? null : new List <string> { requestPath }; } } else if (isFileCached) { context.Items[CachedResponseFileDependency] = new List <string> { cachedPath }; } } } // The cached file is valid so just rewrite the path. this.imageCache.RewritePath(context); // Redirect if not a locally store file. if (!new Uri(cachedPath).IsFile) { context.ApplicationInstance.CompleteRequest(); } } } }
/// <summary> /// Gets the elevation statistics for the given filter from Raptor /// </summary> /// <param name="projectId">Legacy project ID</param> /// <param name="filter">Compaction filter</param> /// <param name="projectSettings">Project settings</param> /// <returns>Elevation statistics</returns> public async Task <ElevationStatisticsResult> GetElevationRange(long projectId, Guid projectUid, FilterResult filter, CompactionProjectSettings projectSettings, IHeaderDictionary customHeaders, string userId) { const double NO_ELEVATION = 10000000000.0; var cacheKey = ElevationCacheKey(projectUid, filter); var strFilter = filter != null?JsonConvert.SerializeObject(filter) : ""; var opts = new MemoryCacheEntryOptions().GetCacheOptions(elevationExtentsCacheLifeKey, configStore, log); // User Story: 88271 - when the UI makes calls requiring elevation, we can bombard Raptor with duplicate calls to retrieve elevation // This can cause raptor to take longer than expected to query the same data over and over again. // This only ever happens when there is no cached item here, as once the item is cached for a given filter the cached item is returned. // To fix this, we will lock per cache key here, so only one call can be made to raptor, blocking all other calls requesting the same info until the cache item is ready // Overall the call time should not change for any request, however the number of calls will be reduced to 1 for each unique projectid / filter. ElevationStatisticsResult resultElevationStatisticsResult = null; using (await memCacheLock.LockAsync(cacheKey)) { resultElevationStatisticsResult = await elevationExtentsCache.GetOrCreate(cacheKey, async entry => { ElevationStatisticsResult result; entry.SetOptions(opts); var projectStatisticsResult = await ProjectStatisticsHelper.GetProjectStatisticsWithProjectSsExclusions(projectUid, projectId, userId, customHeaders); if (projectStatisticsResult?.extents != null) { var extents = projectStatisticsResult.extents; result = new ElevationStatisticsResult ( new BoundingBox3DGrid(extents.MinX, extents.MinY, extents.MinZ, extents.MaxX, extents.MaxY, extents.MaxZ), extents.MinZ, extents.MaxZ, 0.0 ); } else { result = new ElevationStatisticsResult(null, 0.0, 0.0, 0.0); } //Check for 'No elevation range' result if (Math.Abs(result.MinElevation - NO_ELEVATION) < 0.001 && Math.Abs(result.MaxElevation + NO_ELEVATION) < 0.001) { result = null; } // We need to tag the result as this filter and project for cache invalidation var identifiers = new List <string> { projectUid.ToString() }; if (filter?.Uid != null) { identifiers.Add(filter.Uid.Value.ToString()); } log.LogDebug($"Done elevation request"); return(new CacheItem <ElevationStatisticsResult>(result, identifiers)); }); } return(resultElevationStatisticsResult); }
/// <summary> /// Processes the image. /// </summary> /// <param name="context"> /// the <see cref="T:System.Web.HttpContext">HttpContext</see> object that provides /// references to the intrinsic server objects /// </param> /// <returns> /// The <see cref="T:System.Threading.Tasks.Task"/>. /// </returns> private async Task ProcessImageAsync(HttpContext context) { HttpRequest request = context.Request; // Should we ignore this request? if (request.Unvalidated.RawUrl.ToUpperInvariant().Contains("IPIGNORE=TRUE")) { return; } IImageService currentService = this.GetImageServiceForRequest(request); if (currentService != null) { bool isFileLocal = currentService.IsFileLocalService; string url = request.Url.ToString(); bool isLegacy = ProtocolRegex.Matches(url).Count > 1; bool hasMultiParams = url.Count(f => f == '?') > 1; string requestPath; string queryString = string.Empty; string urlParameters = string.Empty; // Legacy support. I'd like to remove this asap. if (isLegacy && hasMultiParams) { // We need to split the querystring to get the actual values we want. string[] paths = url.Split('?'); requestPath = paths[1]; // Handle extension-less urls. if (paths.Length > 3) { queryString = paths[3]; urlParameters = paths[2]; } else if (paths.Length > 1) { queryString = paths[2]; } } else { if (string.IsNullOrWhiteSpace(currentService.Prefix)) { requestPath = currentService.IsFileLocalService ? HostingEnvironment.MapPath(request.Path) : request.Path; queryString = request.QueryString.ToString(); } else { // Parse any protocol values from settings. string protocol = currentService.Settings.ContainsKey("Protocol") ? currentService.Settings["Protocol"] + "://" : string.Empty; // Handle requests that require parameters. if (hasMultiParams) { string[] paths = url.Split('?'); requestPath = protocol + request.Path.Replace(currentService.Prefix, string.Empty).TrimStart('/') + "?" + paths[1]; queryString = paths[2]; } else { requestPath = protocol + request.Path.Replace(currentService.Prefix, string.Empty).TrimStart('/'); queryString = request.QueryString.ToString(); } } } // Replace any presets in the querystring with the actual value. queryString = this.ReplacePresetsInQueryString(queryString); // Execute the handler which can change the querystring queryString = this.CheckQuerystringHandler(queryString, request.Unvalidated.RawUrl); // If the current service doesn't require a prefix, don't fetch it. // Let the static file handler take over. if (string.IsNullOrWhiteSpace(currentService.Prefix) && string.IsNullOrWhiteSpace(queryString)) { return; } if (string.IsNullOrWhiteSpace(requestPath)) { return; } string parts = !string.IsNullOrWhiteSpace(urlParameters) ? "?" + urlParameters : string.Empty; string fullPath = string.Format("{0}{1}?{2}", requestPath, parts, queryString); object resourcePath; // More legacy support code. if (hasMultiParams) { resourcePath = string.IsNullOrWhiteSpace(urlParameters) ? new Uri(requestPath, UriKind.RelativeOrAbsolute) : new Uri(requestPath + "?" + urlParameters, UriKind.RelativeOrAbsolute); } else { resourcePath = requestPath; } // Check whether the path is valid for other requests. if (!currentService.IsValidRequest(resourcePath.ToString())) { return; } string combined = requestPath + fullPath + queryString; using (await Locker.LockAsync(combined)) { // Create a new cache to help process and cache the request. this.imageCache = (IImageCache)ImageProcessorConfiguration.Instance .ImageCache.GetInstance(requestPath, fullPath, queryString); // Is the file new or updated? bool isNewOrUpdated = await this.imageCache.IsNewOrUpdatedAsync(); string cachedPath = this.imageCache.CachedPath; // Only process if the file has been updated. if (isNewOrUpdated) { // Process the image. using (ImageFactory imageFactory = new ImageFactory(preserveExifMetaData != null && preserveExifMetaData.Value)) { byte[] imageBuffer = await currentService.GetImage(resourcePath); using (MemoryStream inStream = new MemoryStream(imageBuffer)) { // Process the Image using (MemoryStream outStream = new MemoryStream()) { imageFactory.Load(inStream).AutoProcess(queryString).Save(outStream); // Add to the cache. await this.imageCache.AddImageToCacheAsync(outStream, imageFactory.CurrentImageFormat.MimeType); } } // Store the cached path, response type, and cache dependency in the context for later retrieval. context.Items[CachedPathKey] = cachedPath; context.Items[CachedResponseTypeKey] = imageFactory.CurrentImageFormat.MimeType; bool isFileCached = new Uri(cachedPath).IsFile; if (isFileLocal) { if (isFileCached) { // Some services might only provide filename so we can't monitor for the browser. context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath ? new List <string> { cachedPath } : new List <string> { requestPath, cachedPath }; } else { context.Items[CachedResponseFileDependency] = Path.GetFileName(requestPath) == requestPath ? null : new List <string> { requestPath }; } } else if (isFileCached) { context.Items[CachedResponseFileDependency] = new List <string> { cachedPath }; } } } // The cached file is valid so just rewrite the path. this.imageCache.RewritePath(context); // Redirect if not a locally store file. if (!new Uri(cachedPath).IsFile) { context.ApplicationInstance.CompleteRequest(); } } } }
public async Task HandleReactionAddAsync(Cacheable <IUserMessage, ulong> cachedMessage, Cacheable <IMessageChannel, ulong> cachedChannel, SocketReaction reaction) { var channel = await cachedChannel.GetOrDownloadAsync(); if (!IsStarReaction(channel, reaction, out var starboard, out var starboardChannel) || reaction.User.IsSpecified && reaction.User.Value.IsBot) { return; } var guildId = channel.Cast <IGuildChannel>().Guild.Id; var messageId = cachedMessage.Id; var starrerId = reaction.UserId; var message = await cachedMessage.GetOrDownloadAsync(); if (_db.TryGetStargazers(guildId, messageId, out var entry)) { using (await _starboardReadWriteLock.LockAsync(entry.StarredMessageId)) { // Add the star to the database if (entry.Stargazers.TryAdd(starrerId, channel == starboardChannel ? StarTarget.StarboardMessage : StarTarget.OriginalMessage)) { // Update message star count await UpdateOrPostToStarboardAsync(starboard, message, entry); _db.UpdateStargazers(entry); } else if (starboard.DeleteInvalidStars) { // Invalid star! Either the starboard post or the actual message already has a reaction by this user. await message.RemoveReactionAsync(_starEmoji, reaction.UserId, DiscordHelper.CreateRequestOptions(x => x.AuditLogReason = "Star reaction is invalid: User has already starred!")); } } } else if (channel != starboardChannel) // Can't make a new starboard message for a post in the starboard channel! { using (await _starboardReadWriteLock.LockAsync(messageId)) { if (message.Reactions.FirstOrDefault(e => e.Key.Name == _starEmoji.Name).Value.ReactionCount >= starboard.StarsRequiredToPost) { // Create new star message! entry = new StarboardEntry { GuildId = guildId, StarredMessageId = messageId, StarboardMessageId = 0, // is set in UpdateOrPostToStarboardAsync Stargazers = { [starrerId] = StarTarget.OriginalMessage } }; await UpdateOrPostToStarboardAsync(starboard, message, entry); } _db.UpdateStargazers(entry); } } }