| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889 |
- using System;
- using System.Threading;
- using Microsoft.AspNetCore.Mvc.ApiExplorer;
- using Microsoft.Extensions.Caching.Memory;
- using Microsoft.Extensions.Options;
- using Microsoft.OpenApi.Models;
- using Swashbuckle.AspNetCore.Swagger;
- using Swashbuckle.AspNetCore.SwaggerGen;
- namespace Jellyfin.Server.Filters;
- /// <summary>
- /// OpenApi provider with caching.
- /// </summary>
- internal sealed class CachingOpenApiProvider : ISwaggerProvider
- {
- private const string CacheKey = "openapi.json";
- private static readonly MemoryCacheEntryOptions _cacheOptions = new() { SlidingExpiration = TimeSpan.FromMinutes(5) };
- private static readonly SemaphoreSlim _lock = new(1, 1);
- private static readonly TimeSpan _lockTimeout = TimeSpan.FromSeconds(1);
- private readonly IMemoryCache _memoryCache;
- private readonly SwaggerGenerator _swaggerGenerator;
- private readonly SwaggerGeneratorOptions _swaggerGeneratorOptions;
- /// <summary>
- /// Initializes a new instance of the <see cref="CachingOpenApiProvider"/> class.
- /// </summary>
- /// <param name="optionsAccessor">The options accessor.</param>
- /// <param name="apiDescriptionsProvider">The api descriptions provider.</param>
- /// <param name="schemaGenerator">The schema generator.</param>
- /// <param name="memoryCache">The memory cache.</param>
- public CachingOpenApiProvider(
- IOptions<SwaggerGeneratorOptions> optionsAccessor,
- IApiDescriptionGroupCollectionProvider apiDescriptionsProvider,
- ISchemaGenerator schemaGenerator,
- IMemoryCache memoryCache)
- {
- _swaggerGeneratorOptions = optionsAccessor.Value;
- _swaggerGenerator = new SwaggerGenerator(_swaggerGeneratorOptions, apiDescriptionsProvider, schemaGenerator);
- _memoryCache = memoryCache;
- }
- /// <inheritdoc />
- public OpenApiDocument GetSwagger(string documentName, string? host = null, string? basePath = null)
- {
- if (_memoryCache.TryGetValue(CacheKey, out OpenApiDocument? openApiDocument) && openApiDocument is not null)
- {
- return AdjustDocument(openApiDocument, host, basePath);
- }
- var acquired = _lock.Wait(_lockTimeout);
- try
- {
- if (_memoryCache.TryGetValue(CacheKey, out openApiDocument) && openApiDocument is not null)
- {
- return AdjustDocument(openApiDocument, host, basePath);
- }
- if (!acquired)
- {
- throw new InvalidOperationException("OpenApi document is generating");
- }
- openApiDocument = _swaggerGenerator.GetSwagger(documentName);
- _memoryCache.Set(CacheKey, openApiDocument, _cacheOptions);
- return AdjustDocument(openApiDocument, host, basePath);
- }
- finally
- {
- if (acquired)
- {
- _lock.Release();
- }
- }
- }
- private OpenApiDocument AdjustDocument(OpenApiDocument document, string? host, string? basePath)
- {
- document.Servers = _swaggerGeneratorOptions.Servers.Count != 0
- ? _swaggerGeneratorOptions.Servers
- : string.IsNullOrEmpty(host) && string.IsNullOrEmpty(basePath)
- ? []
- : [new OpenApiServer { Url = $"{host}{basePath}" }];
- return document;
- }
- }
|