< Summary

Class:DCLServices.PlacesAPIService.PlacesAPIService
Assembly:PlacesAPIService
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLServices/PlacesAPIService/PlacesAPIService.cs
Covered lines:18
Uncovered lines:114
Coverable lines:132
Total lines:316
Line coverage:13.6% (18 of 132)
Covered branches:0
Total branches:0
Covered methods:4
Total methods:21
Method coverage:19% (4 of 21)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
PlacesAPIService(...)0%110100%
Initialize()0%110100%
SearchPlaces()0%12300%
GetMostActivePlaces()0%72800%
GetPlace()0%30500%
GetPlace()0%30500%
GetPlacesByCoordsList()0%1321100%
>c__DisplayClass19_0/<<GetFavorites()0%90900%
GetFavorites()0%1821300%
SetPlaceFavorite()0%12300%
SetPlaceVote()0%12300%
SetPlaceFavorite()0%30500%
IsFavoritePlace()0%56700%
IsFavoritePlace()0%56700%
IsFavoritePlace()0%56700%
CachePlace(...)0%6200%
CreateRequest()0%12300%
GetPointsOfInterestCoords()0%550100%
ReportPlace()0%12300%
GetPlaceCategories()0%30500%
Dispose()0%110100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLServices/PlacesAPIService/PlacesAPIService.cs

#LineLine coverage
 1using Cysharp.Threading.Tasks;
 2using DCL;
 3using DCL.Tasks;
 4using DCLServices.Lambdas;
 5using MainScripts.DCL.Controllers.HotScenes;
 6using System;
 7using System.Collections.Generic;
 8using System.Threading;
 9using UnityEngine;
 10
 11namespace DCLServices.PlacesAPIService
 12{
 13    public interface IPlacesAPIService: IService
 14    {
 15        UniTask<(IReadOnlyList<IHotScenesController.PlaceInfo> places, int total)> SearchPlaces(string searchText, int p
 16
 17        UniTask<(IReadOnlyList<IHotScenesController.PlaceInfo> places, int total)> GetMostActivePlaces(int pageNumber, i
 18
 19        UniTask<IHotScenesController.PlaceInfo> GetPlace(Vector2Int coords, CancellationToken ct, bool renewCache = fals
 20
 21        UniTask<IHotScenesController.PlaceInfo> GetPlace(string placeUUID, CancellationToken ct, bool renewCache = false
 22
 23        UniTask<IReadOnlyList<IHotScenesController.PlaceInfo>> GetFavorites(int pageNumber, int pageSize, CancellationTo
 24
 25        UniTask<List<IHotScenesController.PlaceInfo>> GetPlacesByCoordsList(IEnumerable<Vector2Int> coordsList, Cancella
 26
 27        UniTask SetPlaceFavorite(string placeUUID, bool isFavorite, CancellationToken ct);
 28        UniTask SetPlaceVote(bool? isUpvote, string placeUUID, CancellationToken ct);
 29        UniTask SetPlaceFavorite(Vector2Int coords, bool isFavorite, CancellationToken ct);
 30
 31        UniTask<bool> IsFavoritePlace(IHotScenesController.PlaceInfo placeInfo, CancellationToken ct, bool renewCache = 
 32        UniTask<bool> IsFavoritePlace(Vector2Int coords, CancellationToken ct, bool renewCache = false);
 33        UniTask<bool> IsFavoritePlace(string placeUUID, CancellationToken ct, bool renewCache = false);
 34
 35        UniTask<IReadOnlyList<string>> GetPointsOfInterestCoords(CancellationToken ct, bool renewCache = false);
 36
 37        UniTask ReportPlace(PlaceContentReportPayload placeContentReportPayload, CancellationToken ct);
 38        UniTask<List<PlaceCategoryInfo>> GetPlaceCategories(CancellationToken ct, bool renewCache = false);
 39    }
 40
 41    public class PlacesAPIService : IPlacesAPIService, ILambdaServiceConsumer<IHotScenesController.PlacesAPIResponse>
 42    {
 43        private readonly IPlacesAPIClient client;
 44
 42545        internal readonly Dictionary<string, LambdaResponsePagePointer<IHotScenesController.PlacesAPIResponse>> activePl
 42546        internal readonly Dictionary<string, IHotScenesController.PlaceInfo> placesById = new ();
 42547        internal readonly Dictionary<Vector2Int, IHotScenesController.PlaceInfo> placesByCoords = new ();
 48        private List<string> pointsOfInterestCoords;
 49        private List<PlaceCategoryInfo> placeCategories;
 50
 51        //Favorites
 42552        internal bool composedFavoritesDirty = true;
 42553        internal readonly List<IHotScenesController.PlaceInfo> composedFavorites = new ();
 54        internal UniTaskCompletionSource<List<IHotScenesController.PlaceInfo>> serverFavoritesCompletionSource = null;
 42555        private DateTime serverFavoritesLastRetrieval = DateTime.MinValue;
 42556        internal readonly Dictionary<string, bool> localFavorites = new ();
 57
 42558        private readonly CancellationTokenSource disposeCts = new ();
 59
 42560        public PlacesAPIService(IPlacesAPIClient client)
 61        {
 42562            this.client = client;
 42563        }
 42564        public void Initialize() { }
 65
 66        public async UniTask<(IReadOnlyList<IHotScenesController.PlaceInfo> places, int total)> SearchPlaces(string sear
 67        {
 068            IHotScenesController.PlacesAPIResponse placesAPIResponse = await client.SearchPlaces(searchText, pageNumber,
 069            return (placesAPIResponse.data, placesAPIResponse.total);
 070        }
 71
 72        public async UniTask<(IReadOnlyList<IHotScenesController.PlaceInfo> places, int total)> GetMostActivePlaces(int 
 73        {
 074            var createNewPointer = false;
 75
 076            if (!activePlacesPagePointers.TryGetValue($"{pageSize}_{filter}_{sort}", out var pagePointer)) { createNewPo
 077            else if (renewCache)
 78            {
 079                pagePointer.Dispose();
 080                activePlacesPagePointers.Remove($"{pageSize}_{filter}_{sort}");
 081                createNewPointer = true;
 82            }
 83
 084            if (createNewPointer)
 85            {
 086                activePlacesPagePointers[$"{pageSize}_{filter}_{sort}"] = pagePointer = new LambdaResponsePagePointer<IH
 87                    $"", // not needed, the consumer will compose the URL
 88                    pageSize, disposeCts.Token, this, TimeSpan.FromSeconds(30));
 89            }
 90
 091            (IHotScenesController.PlacesAPIResponse response, bool _) = await pagePointer.GetPageAsync(pageNumber, ct, n
 92
 093            foreach (IHotScenesController.PlaceInfo place in response.data)
 94            {
 095                CachePlace(place);
 96            }
 97
 098            return (response.data, response.total);
 099        }
 100
 101        public async UniTask<IHotScenesController.PlaceInfo> GetPlace(Vector2Int coords, CancellationToken ct, bool rene
 102        {
 0103            if (renewCache)
 0104                placesByCoords.Remove(coords);
 0105            else if (placesByCoords.TryGetValue(coords, out var placeInfo))
 0106                return placeInfo;
 107
 0108            var place = await client.GetPlace(coords, ct);
 0109            CachePlace(place);
 0110            return place;
 0111        }
 112
 113        public async UniTask<IHotScenesController.PlaceInfo> GetPlace(string placeUUID, CancellationToken ct, bool renew
 114        {
 0115            if (renewCache)
 0116                placesById.Remove(placeUUID);
 0117            else if (placesById.TryGetValue(placeUUID, out var placeInfo))
 0118                return placeInfo;
 119
 0120            var place = await client.GetPlace(placeUUID, ct);
 0121            CachePlace(place);
 0122            return place;
 0123        }
 124
 125        public async UniTask<List<IHotScenesController.PlaceInfo>> GetPlacesByCoordsList(IEnumerable<Vector2Int> coordsL
 126        {
 0127            List<IHotScenesController.PlaceInfo> alreadyCachedPlaces = new ();
 0128            List<Vector2Int> coordsToRequest = new ();
 129
 0130            foreach (Vector2Int coords in coordsList)
 131            {
 0132                if (renewCache)
 133                {
 0134                    placesByCoords.Remove(coords);
 0135                    coordsToRequest.Add(coords);
 136                }
 137                else
 138                {
 0139                    if (placesByCoords.TryGetValue(coords, out var placeInfo))
 0140                        alreadyCachedPlaces.Add(placeInfo);
 141                    else
 0142                        coordsToRequest.Add(coords);
 143                }
 144            }
 145
 0146            var places = new List<IHotScenesController.PlaceInfo>();
 0147            if (coordsToRequest.Count > 0)
 148            {
 0149                places = await client.GetPlacesByCoordsList(coordsToRequest, ct);
 0150                foreach (var place in places)
 0151                    CachePlace(place);
 152            }
 153
 0154            places.AddRange(alreadyCachedPlaces);
 155
 0156            return places;
 0157        }
 158
 159        public async UniTask<IReadOnlyList<IHotScenesController.PlaceInfo>> GetFavorites(int pageNumber, int pageSize, C
 160        {
 161            const int CACHE_EXPIRATION = 30; // Seconds
 162
 163            // We need to pass the source to avoid conflicts with parallel calls forcing renewCache
 164            async UniTask RetrieveFavorites(UniTaskCompletionSource<List<IHotScenesController.PlaceInfo>> source)
 165            {
 166                List<IHotScenesController.PlaceInfo> favorites;
 167                // We dont use the ct param, otherwise the whole flow would be cancel if the first call is cancelled
 0168                if (pageNumber == -1 && pageSize == -1)
 169                {
 0170                    favorites = await client.GetAllFavorites(ct);
 171                }
 172                else
 173                {
 0174                    favorites = await client.GetFavorites(pageNumber, pageSize, disposeCts.Token);
 175                }
 0176                foreach (IHotScenesController.PlaceInfo place in favorites)
 177                {
 0178                    CachePlace(place);
 179                }
 0180                composedFavoritesDirty = true;
 0181                source.TrySetResult(favorites);
 0182            }
 183
 0184            if (serverFavoritesCompletionSource == null || renewCache || (DateTime.Now - serverFavoritesLastRetrieval) >
 185            {
 0186                localFavorites.Clear();
 0187                serverFavoritesLastRetrieval = DateTime.Now;
 0188                serverFavoritesCompletionSource = new UniTaskCompletionSource<List<IHotScenesController.PlaceInfo>>();
 0189                RetrieveFavorites(serverFavoritesCompletionSource).Forget();
 190            }
 191
 0192            List<IHotScenesController.PlaceInfo> serverFavorites = await serverFavoritesCompletionSource.Task.AttachExte
 193
 0194            if (!composedFavoritesDirty)
 0195                return composedFavorites;
 196
 0197            composedFavorites.Clear();
 0198            foreach (IHotScenesController.PlaceInfo serverFavorite in serverFavorites)
 199            {
 200                //skip if it's already in the local favorites cache, it will be added (or not) later
 0201                if(localFavorites.ContainsKey(serverFavorite.id))
 202                    continue;
 0203                composedFavorites.Add(serverFavorite);
 204            }
 205
 0206            foreach ((string placeUUID, bool isFavorite) in localFavorites)
 207            {
 0208                if (!isFavorite)
 209                    continue;
 210
 0211                if(placesById.TryGetValue(placeUUID, out var place))
 0212                    composedFavorites.Add(place);
 213            }
 0214            composedFavoritesDirty = false;
 215
 0216            return composedFavorites;
 0217        }
 218
 219        public async UniTask SetPlaceFavorite(string placeUUID, bool isFavorite, CancellationToken ct)
 220        {
 0221            localFavorites[placeUUID] = isFavorite;
 0222            composedFavoritesDirty = true;
 0223            await client.SetPlaceFavorite(placeUUID, isFavorite, ct);
 0224        }
 225
 226        public async UniTask SetPlaceVote(bool? isUpvote, string placeUUID, CancellationToken ct)
 227        {
 0228            await client.SetPlaceVote(isUpvote, placeUUID, ct);
 0229        }
 230
 231        public async UniTask SetPlaceFavorite(Vector2Int coords, bool isFavorite, CancellationToken ct)
 232        {
 0233            var place = await GetPlace(coords, ct);
 0234            await SetPlaceFavorite(place.id, isFavorite, ct);
 0235        }
 236
 237        public async UniTask<bool> IsFavoritePlace(IHotScenesController.PlaceInfo placeInfo, CancellationToken ct, bool 
 238        {
 0239            var favorites = await GetFavorites(-1,-1, ct, renewCache);
 240
 0241            foreach (IHotScenesController.PlaceInfo favorite in favorites)
 242            {
 0243                if (favorite.id == placeInfo.id)
 0244                    return true;
 245            }
 246
 0247            return false;
 0248        }
 249
 250        public async UniTask<bool> IsFavoritePlace(Vector2Int coords, CancellationToken ct, bool renewCache = false)
 251        {
 252            // We could call IsFavoritePlace with the placeInfo and avoid code repetition, but this way we can have the 
 0253            (IHotScenesController.PlaceInfo placeInfo, IReadOnlyList<IHotScenesController.PlaceInfo> favorites) = await 
 254
 0255            foreach (IHotScenesController.PlaceInfo favorite in favorites)
 256            {
 0257                if (favorite.id == placeInfo.id)
 0258                    return true;
 259            }
 260
 0261            return false;
 0262        }
 263
 264        public async UniTask<bool> IsFavoritePlace(string placeUUID, CancellationToken ct, bool renewCache = false)
 265        {
 266            // We could call IsFavoritePlace with the placeInfo and avoid code repetition, but this way we can have the 
 0267            (IHotScenesController.PlaceInfo placeInfo, IReadOnlyList<IHotScenesController.PlaceInfo> favorites) = await 
 268
 0269            foreach (IHotScenesController.PlaceInfo favorite in favorites)
 270            {
 0271                if (favorite.id == placeInfo.id)
 0272                    return true;
 273            }
 274
 0275            return false;
 0276        }
 277
 278        internal void CachePlace(IHotScenesController.PlaceInfo placeInfo)
 279        {
 0280            placesById[placeInfo.id] = placeInfo;
 281
 0282            foreach (Vector2Int placeInfoPosition in placeInfo.Positions) { placesByCoords[placeInfoPosition] = placeInf
 0283        }
 284
 285        public async UniTask<(IHotScenesController.PlacesAPIResponse response, bool success)> CreateRequest(string endPo
 286        {
 0287            var response = await client.GetMostActivePlaces(pageNumber, pageSize,additionalData["filter"],additionalData
 288            // Client will handle most of the error handling and throw if needed
 0289            return (response, true);
 0290        }
 291
 292        public async UniTask<IReadOnlyList<string>> GetPointsOfInterestCoords(CancellationToken ct, bool renewCache = fa
 293        {
 1294            if (renewCache || pointsOfInterestCoords == null)
 3295                pointsOfInterestCoords = await client.GetPointsOfInterestCoords(ct);
 296
 1297            return pointsOfInterestCoords;
 1298        }
 299
 300        public async UniTask ReportPlace(PlaceContentReportPayload placeContentReportPayload, CancellationToken ct) =>
 0301            await client.ReportPlace(placeContentReportPayload, ct);
 302
 303        public async UniTask<List<PlaceCategoryInfo>> GetPlaceCategories(CancellationToken ct, bool renewCache = false)
 304        {
 0305            if (renewCache || placeCategories == null)
 0306                placeCategories = await client.GetPlaceCategories(ct);
 307
 0308            return placeCategories;
 0309        }
 310
 311        public void Dispose()
 312        {
 425313            disposeCts.SafeCancelAndDispose();
 425314        }
 315    }
 316}