/* * Copyright (c) 2024 Proton AG * * This file is part of ProtonVPN. * * ProtonVPN is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ProtonVPN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ProtonVPN. If not, see . */ using System.Text.RegularExpressions; using ProtonVPN.Client.Localization.Contracts; using ProtonVPN.Client.Localization.Extensions; using ProtonVPN.Client.Logic.Searches.Contracts; using ProtonVPN.Client.Logic.Servers.Contracts; using ProtonVPN.Client.Logic.Servers.Contracts.Enums; using ProtonVPN.Client.Logic.Servers.Contracts.Models; namespace ProtonVPN.Client.Logic.Searches; public partial class GlobalSearch : IGlobalSearch { [GeneratedRegex(@"^.{2,}(#\d*|\d+)$")] private static partial Regex GenerateCompileTimeRegex(); private readonly Regex _serverSearchTriggerRegex = GenerateCompileTimeRegex(); private readonly IServersLoader _serversLoader; //private readonly IProfilesManager _profilesManager; private readonly ILocalizationProvider _localizer; public GlobalSearch(IServersLoader serversLoader, //IProfilesManager profilesManager, ILocalizationProvider localizer) { _serversLoader = serversLoader; //_profilesManager = profilesManager; _localizer = localizer; } public async Task> SearchAsync( string? input, ServerFeatures? serverFeatures = null, SearchCategory categories = SearchCategory.All) { input = input.NormalizeInput(); if (string.IsNullOrWhiteSpace(input)) { return []; } Task> serversTask = categories.HasFlag(SearchCategory.Servers) && _serverSearchTriggerRegex.IsMatch(input) ? Task.Run(() => SearchServers(input, serverFeatures)) : Task.FromResult>([]); Task> countriesTask = categories.HasFlag(SearchCategory.Countries) ? Task.Run(() => SearchCountries(input, serverFeatures)) : Task.FromResult>([]); Task> statesTask = categories.HasFlag(SearchCategory.States) ? Task.Run(() => SearchStates(input, serverFeatures)) : Task.FromResult>([]); Task> citiesTask = categories.HasFlag(SearchCategory.Cities) ? Task.Run(() => SearchCities(input, serverFeatures)) : Task.FromResult>([]); //Task> gatewaysTask = Task.Run(() => SearchGateways(input)); //Task> profilesTask = Task.Run(() => SearchProfiles(input)); Task.WaitAll(serversTask, citiesTask, statesTask, countriesTask/*, gatewaysTask, profilesTask*/); IEnumerable servers = await serversTask; IEnumerable cities = await citiesTask; IEnumerable states = await statesTask; IEnumerable countries = await countriesTask; //IEnumerable gateways = await gatewaysTask; //IEnumerable profiles = await profilesTask; //return profiles.Concat(gateways).Concat(countries).Concat(states).Concat(cities).Concat(servers).ToList(); return countries .Concat(states) .Concat(cities) .Concat(servers) .ToList(); } private IEnumerable SearchServers(string input, ServerFeatures? serverFeatures) { IEnumerable servers = serverFeatures is null ? _serversLoader.GetServers() : _serversLoader.GetServersByFeatures(serverFeatures.Value); return servers.Where(s => SearchMatcher.MatchesServer(s, input)); } private IEnumerable SearchCities(string input, ServerFeatures? serverFeatures) { IEnumerable cities = serverFeatures is null ? _serversLoader.GetCities() : _serversLoader.GetCitiesByFeatures(serverFeatures.Value); List localizedCities = cities.Select(city => new LocalizedLocation() { Location = city, LocalizedName = _localizer.GetCityName(city.Name, city.CountryCode) }).ToList(); return localizedCities .Where(c => SearchMatcher.MatchesCity(c.LocalizedName, input)) .Select(c => c.Location); } private IEnumerable SearchStates(string input, ServerFeatures? serverFeatures) { IEnumerable states = serverFeatures is null ? _serversLoader.GetStates() : _serversLoader.GetStatesByFeatures(serverFeatures.Value); List localizedStates = states.Select(state => new LocalizedLocation() { Location = state, LocalizedName = _localizer.GetStateName(state.Name, state.CountryCode) }).ToList(); return localizedStates .Where(s => SearchMatcher.MatchesState(s.LocalizedName, input)) .Select(s => s.Location); } private IEnumerable SearchCountries(string input, ServerFeatures? serverFeatures) { IEnumerable countries = serverFeatures is null ? _serversLoader.GetCountries() : _serversLoader.GetCountriesByFeatures(serverFeatures.Value); List localizedCountries = countries.Select(c => new LocalizedCountry() { Country = c, LocalizedName = _localizer.GetCountryName(c.Code) }).ToList(); return localizedCountries .Where(c => SearchMatcher.MatchesCountry(c.Country, c.LocalizedName, input)) .Select(c => c.Country); } //private IEnumerable SearchGateways(string input) //{ // IEnumerable gateways = _serversLoader.GetGateways(); // return gateways.Where(g => IsAMatch(g, input)) // .Select(g => new ConnectionIntent(new GatewayLocationIntent(g))); //} //private IEnumerable SearchProfiles(string input) //{ // IOrderedEnumerable profiles = _profilesManager.GetAll(); // return profiles.Where(p => IsAMatch(p.Name, input)); //} }