using StackExchange.Redis; using SWAD.API.Consts.Enums; using SWAD.API.Controllers.DTOs; using SWAD.API.Exceptions; using SWAD.API.Services.MusicAPI.Api; namespace SWAD.API.Services.Links; /// /// Service for manipulating with links (LinkController) /// public class LinksService { private readonly Dictionary _services; private readonly IDatabase _redis; private readonly ILogger _logger; public LinksService(IEnumerable services, IDatabase redis, ILogger logger) { _services = services.ToList() .ConvertAll(x => new KeyValuePair(x.ServiceType, x)).ToDictionary(); _redis = redis; _logger = logger; } /// /// Get link by query /// /// Search query /// Success, Failure, BadRequest, NoResponse public async Task<(string? link, ServiceResult result)> GetLinkByQuery(TrackDto query) { //Mapping service var service = _services.GetValueOrDefault(query.Service); //Throw result try { var output = await service!.GetLinkByQuery(query); return (output, output != null ? ServiceResult.Success : ServiceResult.Failure); } catch (HttpRequestException) { return (null, ServiceResult.BadRequest); } catch (TimeoutException) { return (null, ServiceResult.NoResponse); } } /// /// Get MusicService by url /// /// /// Success, Failure public async Task<(MusicService? service, ServiceResult result)> GetServiceByLink(string link) { var cacheKey = $"GET_SERVICE_{link}"; var cache = await _redis.StringGetAsync(cacheKey); if (cache.HasValue) { var result = (MusicService?)Enum.Parse(typeof(MusicService), cache.ToString()); return (result, ServiceResult.Success); } _logger.LogInformation($"Getting service for {link}..."); foreach (var service in _services.Values) if (service.Config.Endpoints.MusicLink.Any(link.StartsWith)) { await _redis.StringSetAsync(cacheKey, service.ServiceType.ToString(), TimeSpan.FromDays(30)); return (service.ServiceType, ServiceResult.Success); } _logger.LogInformation($"FAIL"); return (null, ServiceResult.Failure); } /// /// Get Link from other service /// /// link from first service /// link from another service, Success, Failure, BadRequest, NoResponse public async Task<(string? link, ServiceResult result)> MapLinks(TrackLinkDto trackLink) { var service = await GetServiceByLink(trackLink.Link); if (service.result != ServiceResult.Success) return (null, service.result); var cacheKey = $"{service.service}_{trackLink.Link}_{Enum.GetName(trackLink.Service)}"; var cache = await _redis.StringGetAsync(cacheKey); if (cache.HasValue) { return (cache.ToString(), ServiceResult.Success); } _logger.LogInformation($"Getting {trackLink.Link} for {Enum.GetName(trackLink.Service)}..."); try { var apiService = _services[service.service!.Value]; var query = await apiService.GetQueryObject(trackLink.Link); var linkApiService = _services[trackLink.Service]; var link = await linkApiService.GetLinkByQuery(query); if (link == null) return (null, ServiceResult.Failure); await _redis.StringSetAsync(cacheKey, link, TimeSpan.FromDays(30)); return (link, ServiceResult.Success); } catch (TrackNotFoundException) { return (null, ServiceResult.NotFound); } catch (HttpRequestException) { return (null, ServiceResult.BadRequest); } catch (TimeoutException) { return (null, ServiceResult.NoResponse); } catch (TooManyRequestsException) { return (null, ServiceResult.TooManyRequests); } } }