< Summary

Class:Catalyst
Assembly:Catalyst
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/ServiceProviders/Catalyst/Catalyst.cs
Covered lines:37
Uncovered lines:92
Coverable lines:129
Total lines:279
Line coverage:28.6% (37 of 129)
Covered branches:0
Total branches:0
Covered methods:11
Total methods:21
Method coverage:52.3% (11 of 21)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
Catalyst()0%5.345076.19%
GetLambdaUrl(...)0%6200%
NormalizeUrls()0%110100%
TrySetCompletionSource(...)0%220100%
GetNormalizedUrl(...)0%330100%
Dispose()0%110100%
GetContent()0%12300%
GetDeployedScenes(...)0%2100%
GetDeployedScenes(...)0%20400%
GetEntities(...)0%1101000%
Get(...)0%2100%
PlayerRealmOnChange(...)0%2100%
PlayerRealmAboutLambdasOnChange(...)0%2100%
PlayerRealmAboutContentOnChange(...)0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/ServiceProviders/Catalyst/Catalyst.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using Cysharp.Threading.Tasks;
 5using DCL;
 6using DCL.Helpers;
 7using Decentraland.Bff;
 8using System.Threading;
 9using UnityEngine;
 10using Variables.RealmsInfo;
 11
 12public class Catalyst : ICatalyst
 13{
 14    private const float DEFAULT_CACHE_TIME = 5 * 60;
 15    private const int MAX_POINTERS_PER_REQUEST = 90;
 16
 017    public string contentUrl => realmContentServerUrl;
 39218    public string lambdasUrl { get; private set; }
 19
 13020    private UniTaskCompletionSource<string> lambdasUrlCs = new UniTaskCompletionSource<string>();
 13021    private string realmDomain = "https://peer.decentraland.org";
 13022    private string realmContentServerUrl = "https://peer.decentraland.org/content/";
 23
 13024    private readonly IDataCache<CatalystSceneEntityPayload[]> deployedScenesCache = new DataCache<CatalystSceneEntityPay
 25
 39226    private CurrentRealmVariable playerRealm => DataStore.i.realm.playerRealm;
 26027    private BaseVariable<AboutResponse.Types.LambdasInfo> aboutLambdas => DataStore.i.realm.playerRealmAboutLambdas;
 26028    private BaseVariable<AboutResponse.Types.ContentInfo> aboutContent => DataStore.i.realm.playerRealmAboutContent;
 12929    private BaseVariable<AboutResponse.Types.AboutConfiguration> aboutConfiguration => DataStore.i.realm.playerRealmAbou
 30
 31
 13032    public Catalyst()
 33    {
 13034        if (playerRealm.Get() != null)
 35        {
 136            realmDomain = playerRealm.Get().domain;
 137            lambdasUrl = $"{realmDomain}/lambdas";
 138            TrySetCompletionSource(lambdasUrl);
 139            realmContentServerUrl = playerRealm.Get().contentServerUrl;
 40        }
 12941        else if (aboutConfiguration.Get() != null)
 42        {
 43            //TODO: This checks are going to dissapear when we inject the urls in kernel. Currently they are null,
 44            //and we dont want to override the ones that have been set up in playerRealm
 045            if (!string.IsNullOrEmpty(aboutLambdas.Get().PublicUrl))
 46            {
 047                lambdasUrl = aboutLambdas.Get().PublicUrl;
 048                TrySetCompletionSource(lambdasUrl);
 49            }
 50
 051            if (!string.IsNullOrEmpty(aboutContent.Get().PublicUrl))
 052                realmContentServerUrl = aboutContent.Get().PublicUrl;
 53        }
 54
 13055        NormalizeUrls();
 56
 13057        playerRealm.OnChange += PlayerRealmOnChange;
 13058        aboutContent.OnChange += PlayerRealmAboutContentOnChange;
 13059        aboutLambdas.OnChange += PlayerRealmAboutLambdasOnChange;
 13060    }
 61
 62    public UniTask<string> GetLambdaUrl(CancellationToken ct)
 63    {
 064        if (!string.IsNullOrEmpty(lambdasUrl))
 065            return new UniTask<string>(lambdasUrl);
 66
 067        return lambdasUrlCs.Task.AttachExternalCancellation(ct);
 68    }
 69
 70    private void NormalizeUrls()
 71    {
 13072        lambdasUrl = GetNormalizedUrl(lambdasUrl);
 13073        TrySetCompletionSource(lambdasUrl);
 13074        realmContentServerUrl = GetNormalizedUrl(realmContentServerUrl);
 13075    }
 76
 77    private void TrySetCompletionSource(string url)
 78    {
 26079        if (string.IsNullOrEmpty(url)) return;
 80
 281        lambdasUrlCs.TrySetResult(url);
 282    }
 83
 84    private string GetNormalizedUrl(string url)
 85    {
 39086        if (string.IsNullOrEmpty(url)) return url;
 13087        if (!url.EndsWith('/'))
 188            url += "/";
 89
 13090        return url;
 91    }
 92
 93    public void Dispose()
 94    {
 13095        playerRealm.OnChange -= PlayerRealmOnChange;
 13096        aboutContent.OnChange -= PlayerRealmAboutContentOnChange;
 13097        aboutLambdas.OnChange -= PlayerRealmAboutLambdasOnChange;
 13098        deployedScenesCache.Dispose();
 13099    }
 100
 101    public async UniTask<string> GetContent(string hash)
 102    {
 0103        string callResult = "";
 0104        string url = $"{realmContentServerUrl}/contents/" + hash;
 105
 0106        var callPromise = Get(url);
 0107        callPromise.Then(result => { callResult = result; });
 108
 0109        callPromise.Catch(error => { callResult = error; });
 0110        await callPromise;
 0111        return callResult;
 0112    }
 113
 114    public Promise<CatalystSceneEntityPayload[]> GetDeployedScenes(string[] parcels)
 115    {
 0116        return GetDeployedScenes(parcels, DEFAULT_CACHE_TIME);
 117    }
 118
 119    public Promise<CatalystSceneEntityPayload[]> GetDeployedScenes(string[] parcels, float cacheMaxAgeSeconds)
 120    {
 0121        var promise = new Promise<CatalystSceneEntityPayload[]>();
 122
 0123        string cacheKey = string.Join(";", parcels);
 124
 0125        if (cacheMaxAgeSeconds >= 0)
 126        {
 0127            if (deployedScenesCache.TryGet(cacheKey, out CatalystSceneEntityPayload[] cacheValue, out float lastUpdate))
 128            {
 0129                if (Time.unscaledTime - lastUpdate <= cacheMaxAgeSeconds)
 130                {
 0131                    promise.Resolve(cacheValue);
 0132                    return promise;
 133                }
 134            }
 135        }
 136
 0137        GetEntities(CatalystEntitiesType.SCENE, parcels)
 138           .Then(json =>
 139            {
 0140                CatalystSceneEntityPayload[] scenes = null;
 0141                bool hasException = false;
 142
 143                try
 144                {
 0145                    CatalystSceneEntityPayload[] parsedValue = Utils.ParseJsonArray<CatalystSceneEntityPayload[]>(json);
 146
 147                    // remove duplicated
 0148                    List<CatalystSceneEntityPayload> noDuplicates = new List<CatalystSceneEntityPayload>();
 149
 0150                    for (int i = 0; i < parsedValue.Length; i++)
 151                    {
 0152                        var sceneToCheck = parsedValue[i];
 153
 0154                        if (noDuplicates.Any(scene => scene.id == sceneToCheck.id))
 155                            continue;
 156
 0157                        noDuplicates.Add(sceneToCheck);
 158                    }
 159
 0160                    scenes = noDuplicates.ToArray();
 0161                }
 0162                catch (Exception e)
 163                {
 0164                    promise.Reject(e.Message);
 0165                    hasException = true;
 0166                }
 167                finally
 168                {
 0169                    if (!hasException)
 170                    {
 0171                        deployedScenesCache.Add(cacheKey, scenes, DEFAULT_CACHE_TIME);
 0172                        promise.Resolve(scenes);
 173                    }
 0174                }
 0175            })
 0176           .Catch(error => promise.Reject(error));
 177
 0178        return promise;
 179    }
 180
 181    public Promise<string> GetEntities(string entityType, string[] pointers)
 182    {
 0183        Promise<string> promise = new Promise<string>();
 184
 185        string[][] pointersGroupsToFetch;
 186
 0187        if (pointers.Length <= MAX_POINTERS_PER_REQUEST) { pointersGroupsToFetch = new[] { pointers }; }
 188        else
 189        {
 190            // split pointers array in length of MAX_POINTERS_PER_REQUEST
 0191            int i = 0;
 192
 0193            var query = from s in pointers
 0194                let num = i++
 0195                group s by num / MAX_POINTERS_PER_REQUEST
 196                into g
 0197                select g.ToArray();
 198
 0199            pointersGroupsToFetch = query.ToArray();
 200        }
 201
 0202        if (pointersGroupsToFetch.Length == 0)
 203        {
 0204            promise.Reject("error: no pointers to fetch");
 0205            return promise;
 206        }
 207
 0208        Promise<string>[] splittedPromises = new Promise<string>[pointersGroupsToFetch.Length];
 209
 0210        for (int i = 0; i < pointersGroupsToFetch.Length; i++)
 211        {
 0212            string urlParams = "";
 0213            urlParams = pointersGroupsToFetch[i].Aggregate(urlParams, (current, pointer) => current + $"&pointer={pointe
 0214            string url = $"{realmContentServerUrl}/entities/{entityType}?{urlParams}";
 215
 0216            splittedPromises[i] = Get(url);
 217
 0218            splittedPromises[i]
 219               .Then(value =>
 220                {
 221                    // check if all other promises have been resolved
 0222                    for (int j = 0; j < splittedPromises.Length; j++)
 223                    {
 0224                        if (splittedPromises[j] == null || splittedPromises[j].keepWaiting || !string.IsNullOrEmpty(spli
 225                    }
 226
 227                    // make sure not to continue if promise was already resolved
 0228                    if (!promise.keepWaiting)
 0229                        return;
 230
 231                    // build json with all promises result
 0232                    string json = splittedPromises[0].value.Substring(1, splittedPromises[0].value.Length - 2);
 233
 0234                    for (int j = 1; j < splittedPromises.Length; j++)
 235                    {
 0236                        string jsonContent = splittedPromises[j].value.Substring(1, splittedPromises[j].value.Length - 2
 237
 0238                        if (!string.IsNullOrEmpty(jsonContent))
 0239                            json += $",{jsonContent}";
 240                    }
 241
 0242                    promise.Resolve($"[{json}]");
 0243                });
 244
 0245            splittedPromises[i].Catch(error => promise.Reject(error));
 246        }
 247
 0248        return promise;
 249    }
 250
 251    public Promise<string> Get(string url)
 252    {
 0253        Promise<string> promise = new Promise<string>();
 254
 0255        DCL.Environment.i.platform.webRequest.Get(url, null, request => { promise.Resolve(request.webRequest.downloadHan
 256
 0257        return promise;
 258    }
 259
 260    private void PlayerRealmOnChange(CurrentRealmModel current, CurrentRealmModel previous)
 261    {
 0262        realmDomain = current.domain;
 0263        lambdasUrl = $"{realmDomain}/lambdas";
 0264        realmContentServerUrl = current.contentServerUrl;
 0265        NormalizeUrls();
 0266    }
 267
 268    private void PlayerRealmAboutLambdasOnChange(AboutResponse.Types.LambdasInfo current, AboutResponse.Types.LambdasInf
 269    {
 0270        lambdasUrl = current.PublicUrl;
 0271        NormalizeUrls();
 0272    }
 273
 274    private void PlayerRealmAboutContentOnChange(AboutResponse.Types.ContentInfo current, AboutResponse.Types.ContentInf
 275    {
 0276        realmContentServerUrl = current.PublicUrl;
 0277        NormalizeUrls();
 0278    }
 279}