< Summary

Class:CatalogController
Assembly:CatalogController
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/CatalogController/CatalogController.cs
Covered lines:48
Uncovered lines:94
Coverable lines:142
Total lines:355
Line coverage:33.8% (48 of 142)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CatalogController()0%110100%
Awake()0%110100%
Update()0%330100%
AddWearablesToCatalog(...)0%20400%
AddWearablesToCatalog(...)0%20400%
AddWearablesToCatalog(...)0%2100%
WearablesRequestFailed(...)0%20400%
RemoveWearablesFromCatalog(...)0%6200%
ClearWearableCatalog()0%6200%
RequestWearable(...)0%20400%
RequestOwnedWearables(...)0%330100%
RequestBaseWearables()0%12300%
RemoveWearablesInUse(...)0%4.123050%
ResolvePendingWearablePromise(...)0%12300%
ResolvePendingWearablesByContextPromise(...)0%3.043083.33%
CheckForSendingPendingRequests()0%11.534022.22%
CheckForRequestsTimeOuts()0%20.155015.38%
CheckForRequestsByContextTimeOuts()0%550100%
CheckForUnusedWearables()0%20.155015.38%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/CatalogController/CatalogController.cs

#LineLine coverage
 1using System;
 2using DCL;
 3using DCL.Helpers;
 4using DCL.Interface;
 5using System.Collections.Generic;
 6using UnityEngine;
 7
 8public class CatalogController : MonoBehaviour
 9{
 110    public static bool VERBOSE = false;
 11    private const string OWNED_WEARABLES_CONTEXT = "OwnedWearables";
 12    private const string BASE_WEARABLES_CONTEXT = "BaseWearables";
 13    private const int FRAMES_TO_CHECK_FOR_SENDING_PENDING_REQUESTS = 1;
 14    private const float TIME_TO_CHECK_FOR_UNUSED_WEARABLES = 10f;
 15    private const float REQUESTS_TIME_OUT_SECONDS = 45;
 16
 017    public static CatalogController i { get; private set; }
 18
 019    public static BaseDictionary<string, WearableItem> wearableCatalog => DataStore.i.wearables;
 20
 121    private static Dictionary<string, int> wearablesInUseCounters = new Dictionary<string, int>();
 122    private static Dictionary<string, Promise<WearableItem>> awaitingWearablePromises = new Dictionary<string, Promise<W
 123    private static Dictionary<string, float> pendingWearableRequestedTimes = new Dictionary<string, float>();
 124    private static Dictionary<string, Promise<WearableItem[]>> awaitingWearablesByContextPromises = new Dictionary<strin
 125    private static Dictionary<string, float> pendingWearablesByContextRequestedTimes = new Dictionary<string, float>();
 126    private static List<string> pendingRequestsToSend = new List<string>();
 27    private float timeSinceLastUnusedWearablesCheck = 0f;
 28
 24629    public void Awake() { i = this; }
 30
 31    private void Update()
 32    {
 33        // All the requests happened during the same frames interval are sent together
 2125334        if (Time.frameCount % FRAMES_TO_CHECK_FOR_SENDING_PENDING_REQUESTS == 0)
 35        {
 2125336            CheckForSendingPendingRequests();
 2125337            CheckForRequestsTimeOuts();
 2125338            CheckForRequestsByContextTimeOuts();
 39        }
 40
 41        // Check unused wearables (to be removed from our catalog) only every [TIME_TO_CHECK_FOR_UNUSED_WEARABLES] secon
 2125342        timeSinceLastUnusedWearablesCheck += Time.deltaTime;
 2125343        if (timeSinceLastUnusedWearablesCheck >= TIME_TO_CHECK_FOR_UNUSED_WEARABLES)
 44        {
 145            CheckForUnusedWearables();
 146            timeSinceLastUnusedWearablesCheck = 0f;
 47        }
 2125348    }
 49
 50    public void AddWearablesToCatalog(string payload)
 51    {
 052        if (VERBOSE)
 053            Debug.Log("add wearables: " + payload);
 54
 055        WearablesRequestResponse request = null;
 56
 57        try
 58        {
 059            request = JsonUtility.FromJson<WearablesRequestResponse>(payload);
 060        }
 061        catch (Exception e)
 62        {
 063            Debug.LogError($"Fail to parse wearables json {e}");
 064        }
 65
 066        if (request == null)
 067            return;
 68
 069        AddWearablesToCatalog(request.wearables);
 70
 071        if (!string.IsNullOrEmpty(request.context))
 72        {
 073            ResolvePendingWearablesByContextPromise(request.context, request.wearables);
 074            pendingWearablesByContextRequestedTimes.Remove(request.context);
 75        }
 076    }
 77
 78    public void AddWearablesToCatalog(WearableItem[] wearableItems)
 79    {
 080        foreach (WearableItem wearableItem in wearableItems)
 81        {
 082            if (!wearableCatalog.ContainsKey(wearableItem.id))
 83            {
 084                wearableCatalog.Add(wearableItem.id, wearableItem);
 85
 086                if (!wearablesInUseCounters.ContainsKey(wearableItem.id))
 087                    wearablesInUseCounters.Add(wearableItem.id, 1);
 88
 089                ResolvePendingWearablePromise(wearableItem.id, wearableItem);
 90
 091                pendingWearableRequestedTimes.Remove(wearableItem.id);
 92            }
 93        }
 094    }
 95
 096    public void AddWearablesToCatalog(List<WearableItem> wearableItems) { AddWearablesToCatalog(wearableItems.ToArray())
 97
 98    public void WearablesRequestFailed(string payload)
 99    {
 0100        WearablesRequestFailed requestFailedResponse = JsonUtility.FromJson<WearablesRequestFailed>(payload);
 101
 0102        if (requestFailedResponse.context == BASE_WEARABLES_CONTEXT ||
 103            requestFailedResponse.context == OWNED_WEARABLES_CONTEXT)
 104        {
 0105            ResolvePendingWearablesByContextPromise(
 106                requestFailedResponse.context,
 107                null,
 108                requestFailedResponse.error);
 0109        }
 110        else
 111        {
 0112            string[] failedWearablesIds = requestFailedResponse.context.Split(',');
 0113            for (int i = 0; i < failedWearablesIds.Length; i++)
 114            {
 0115                ResolvePendingWearablePromise(
 116                    failedWearablesIds[i],
 117                    null,
 118                    $"The request for the wearable '{failedWearablesIds[i]}' has failed: {requestFailedResponse.error}")
 119            }
 120        }
 0121    }
 122
 123    public void RemoveWearablesFromCatalog(string payload)
 124    {
 0125        string[] itemIDs = JsonUtility.FromJson<string[]>(payload);
 126
 0127        int count = itemIDs.Length;
 0128        for (int i = 0; i < count; ++i)
 129        {
 0130            wearableCatalog.Remove(itemIDs[i]);
 0131            wearablesInUseCounters.Remove(itemIDs[i]);
 132        }
 0133    }
 134
 135    public void ClearWearableCatalog()
 136    {
 0137        wearableCatalog?.Clear();
 0138        wearablesInUseCounters.Clear();
 0139    }
 140
 141    public static Promise<WearableItem> RequestWearable(string wearableId)
 142    {
 0143        if (VERBOSE)
 0144            Debug.Log("request wearables: " + wearableId);
 145
 146        Promise<WearableItem> promiseResult;
 147
 0148        if (wearableCatalog.TryGetValue(wearableId, out WearableItem wearable))
 149        {
 0150            wearablesInUseCounters[wearableId]++;
 0151            promiseResult = new Promise<WearableItem>();
 0152            promiseResult.Resolve(wearable);
 0153        }
 154        else
 155        {
 0156            if (!awaitingWearablePromises.ContainsKey(wearableId))
 157            {
 0158                promiseResult = new Promise<WearableItem>();
 0159                awaitingWearablePromises.Add(wearableId, promiseResult);
 160
 161                // We accumulate all the requests during the same frames interval to send them all together
 0162                pendingRequestsToSend.Add(wearableId);
 0163            }
 164            else
 165            {
 0166                awaitingWearablePromises.TryGetValue(wearableId, out promiseResult);
 167            }
 168        }
 169
 0170        return promiseResult;
 171    }
 172
 173    public static Promise<WearableItem[]> RequestOwnedWearables(string userId)
 174    {
 175        Promise<WearableItem[]> promiseResult;
 176
 5177        if (!awaitingWearablesByContextPromises.ContainsKey(OWNED_WEARABLES_CONTEXT))
 178        {
 2179            promiseResult = new Promise<WearableItem[]>();
 2180            awaitingWearablesByContextPromises.Add(OWNED_WEARABLES_CONTEXT, promiseResult);
 181
 2182            if (!pendingWearablesByContextRequestedTimes.ContainsKey(OWNED_WEARABLES_CONTEXT))
 2183                pendingWearablesByContextRequestedTimes.Add(OWNED_WEARABLES_CONTEXT, Time.realtimeSinceStartup);
 184
 2185            WebInterface.RequestWearables(
 186                ownedByUser: userId,
 187                wearableIds: null,
 188                collectionIds: null,
 189                context: OWNED_WEARABLES_CONTEXT
 190            );
 2191        }
 192        else
 193        {
 3194            awaitingWearablesByContextPromises.TryGetValue(OWNED_WEARABLES_CONTEXT, out promiseResult);
 195        }
 196
 5197        return promiseResult;
 198    }
 199
 200    public static Promise<WearableItem[]> RequestBaseWearables()
 201    {
 202        Promise<WearableItem[]> promiseResult;
 203
 0204        if (!awaitingWearablesByContextPromises.ContainsKey(BASE_WEARABLES_CONTEXT))
 205        {
 0206            promiseResult = new Promise<WearableItem[]>();
 0207            awaitingWearablesByContextPromises.Add(BASE_WEARABLES_CONTEXT, promiseResult);
 208
 0209            if (!pendingWearablesByContextRequestedTimes.ContainsKey(BASE_WEARABLES_CONTEXT))
 0210                pendingWearablesByContextRequestedTimes.Add(BASE_WEARABLES_CONTEXT, Time.realtimeSinceStartup);
 211
 0212            WebInterface.RequestWearables(
 213                ownedByUser: null,
 214                wearableIds: null,
 215                collectionIds: new string[] { "urn:decentraland:off-chain:base-avatars" },
 216                context: BASE_WEARABLES_CONTEXT
 217            );
 0218        }
 219        else
 220        {
 0221            awaitingWearablesByContextPromises.TryGetValue(BASE_WEARABLES_CONTEXT, out promiseResult);
 222        }
 223
 0224        return promiseResult;
 225    }
 226
 227    public static void RemoveWearablesInUse(List<string> wearablesInUseToRemove)
 228    {
 3038229        foreach (var wearableToRemove in wearablesInUseToRemove)
 230        {
 0231            if (wearablesInUseCounters.ContainsKey(wearableToRemove))
 232            {
 0233                wearablesInUseCounters[wearableToRemove]--;
 234            }
 235        }
 1519236    }
 237
 238    private void ResolvePendingWearablePromise(string wearableId, WearableItem newWearableAddedIntoCatalog = null, strin
 239    {
 0240        if (awaitingWearablePromises.TryGetValue(wearableId, out Promise<WearableItem> promise))
 241        {
 0242            awaitingWearablePromises.Remove(wearableId);
 243
 0244            if (string.IsNullOrEmpty(errorMessage))
 0245                promise.Resolve(newWearableAddedIntoCatalog);
 246            else
 0247                promise.Reject(errorMessage);
 248        }
 0249    }
 250
 251    private void ResolvePendingWearablesByContextPromise(string context, WearableItem[] newWearablesAddedIntoCatalog = n
 252    {
 2253        if (awaitingWearablesByContextPromises.TryGetValue(context, out Promise<WearableItem[]> promise))
 254        {
 2255            awaitingWearablesByContextPromises.Remove(context);
 256
 2257            if (string.IsNullOrEmpty(errorMessage))
 0258                promise.Resolve(newWearablesAddedIntoCatalog);
 259            else
 2260                promise.Reject(errorMessage);
 261        }
 2262    }
 263
 264    private void CheckForSendingPendingRequests()
 265    {
 21253266        if (pendingRequestsToSend.Count > 0)
 267        {
 0268            foreach (var request in pendingRequestsToSend)
 269            {
 0270                if (!pendingWearableRequestedTimes.ContainsKey(request))
 0271                    pendingWearableRequestedTimes.Add(request, Time.realtimeSinceStartup);
 272            }
 273
 0274            WebInterface.RequestWearables(
 275                ownedByUser: null,
 276                wearableIds: pendingRequestsToSend.ToArray(),
 277                collectionIds: null,
 278                context: string.Join(",", pendingRequestsToSend.ToArray())
 279            );
 280
 0281            pendingRequestsToSend.Clear();
 282        }
 21253283    }
 284
 285    private void CheckForRequestsTimeOuts()
 286    {
 21253287        if (pendingWearableRequestedTimes.Count > 0)
 288        {
 0289            List<string> expiredRequestes = new List<string>();
 0290            foreach (var promiseRequestedTime in pendingWearableRequestedTimes)
 291            {
 0292                if ((Time.realtimeSinceStartup - promiseRequestedTime.Value) > REQUESTS_TIME_OUT_SECONDS)
 293                {
 0294                    expiredRequestes.Add(promiseRequestedTime.Key);
 295                }
 296            }
 297
 0298            foreach (var expiredRequestToRemove in expiredRequestes)
 299            {
 0300                pendingWearableRequestedTimes.Remove(expiredRequestToRemove);
 301
 0302                ResolvePendingWearablePromise(
 303                    expiredRequestToRemove,
 304                    null,
 305                    $"The request for the wearable '{expiredRequestToRemove}' has exceed the set timeout!");
 306            }
 307        }
 21253308    }
 309
 310    private void CheckForRequestsByContextTimeOuts()
 311    {
 21253312        if (pendingWearablesByContextRequestedTimes.Count > 0)
 313        {
 4908314            List<string> expiredRequests = new List<string>();
 19632315            foreach (var promiseByContextRequestedTime in pendingWearablesByContextRequestedTimes)
 316            {
 4908317                if ((Time.realtimeSinceStartup - promiseByContextRequestedTime.Value) > REQUESTS_TIME_OUT_SECONDS)
 318                {
 2319                    expiredRequests.Add(promiseByContextRequestedTime.Key);
 320                }
 321            }
 322
 9820323            foreach (var expiredRequestToRemove in expiredRequests)
 324            {
 2325                pendingWearablesByContextRequestedTimes.Remove(expiredRequestToRemove);
 326
 2327                ResolvePendingWearablesByContextPromise(
 328                    expiredRequestToRemove,
 329                    null,
 330                    $"The request for the wearable context '{expiredRequestToRemove}' has exceed the set timeout!");
 331            }
 332        }
 21253333    }
 334
 335    private void CheckForUnusedWearables()
 336    {
 1337        if (wearablesInUseCounters.Count > 0)
 338        {
 0339            List<string> wearablesToDestroy = new List<string>();
 0340            foreach (var wearableInUse in wearablesInUseCounters)
 341            {
 0342                if (wearableInUse.Value <= 0)
 343                {
 0344                    wearablesToDestroy.Add(wearableInUse.Key);
 345                }
 346            }
 347
 0348            foreach (var wearableToDestroy in wearablesToDestroy)
 349            {
 0350                wearableCatalog.Remove(wearableToDestroy);
 0351                wearablesInUseCounters.Remove(wearableToDestroy);
 352            }
 353        }
 1354    }
 355}