< Summary

Class:DCL.NFTAssetRetriever
Assembly:DCL.Components.NFT
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/NFTShape/NFTAsset/NFTAssetLoadHelper.cs
Covered lines:37
Uncovered lines:46
Coverable lines:83
Total lines:186
Line coverage:44.5% (37 of 83)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
LoadNFTAsset()0%12300%
LoadNFTAsset()0%16.7114076%
Dispose()0%3.143075%
GetHeaders()0%56700%
FetchGif()0%12300%
FetchImage()0%12300%
UnloadPromises()0%330100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/LoadableShapes/NFTShape/NFTAsset/NFTAssetLoadHelper.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Threading;
 5using Cysharp.Threading.Tasks;
 6using DCL.Helpers;
 7using NFTShape_Internal;
 8using UnityEngine;
 9using UnityEngine.Networking;
 10
 11namespace DCL
 12{
 13    public interface INFTAssetRetriever : IDisposable
 14    {
 15        IEnumerator LoadNFTAsset(string url, Action<INFTAsset> OnSuccess, Action<Exception> OnFail);
 16        UniTask<INFTAsset> LoadNFTAsset(string url);
 17    }
 18
 19    public class NFTAssetRetriever : INFTAssetRetriever
 20    {
 21        private const string CONTENT_TYPE = "Content-Type";
 22        private const string CONTENT_LENGTH = "Content-Length";
 23        private const string CONTENT_TYPE_GIF = "image/gif";
 24        private const string CONTENT_TYPE_WEBP = "image/webp";
 25        private const long PREVIEW_IMAGE_SIZE_LIMIT = 500000;
 26
 27        protected AssetPromise_Texture imagePromise = null;
 28        protected AssetPromise_Gif gifPromise = null;
 29        private CancellationTokenSource tokenSource;
 30
 31        public async UniTask<INFTAsset> LoadNFTAsset(string url)
 32        {
 033            tokenSource = new CancellationTokenSource();
 034            tokenSource.Token.ThrowIfCancellationRequested();
 035            INFTAsset result = null;
 036            await LoadNFTAsset(url, (nftAsset) =>
 37            {
 038                result = nftAsset;
 039            }, (exception) =>
 40            {
 041                Debug.Log("Fail to load nft " + url + " due to " + exception.Message);
 042            }).WithCancellation(tokenSource.Token);
 43
 044            return result;
 045        }
 46
 47        public IEnumerator LoadNFTAsset(string url, Action<INFTAsset> OnSuccess, Action<Exception> OnFail)
 48        {
 649            if (string.IsNullOrEmpty(url))
 50            {
 051                OnFail?.Invoke(new Exception($"Image url is null!"));
 052                yield break;
 53            }
 54
 655            HashSet<string> headers = new HashSet<string>() {CONTENT_TYPE, CONTENT_LENGTH};
 656            Dictionary<string, string> responseHeaders = new Dictionary<string, string>();
 657            string headerRequestError = string.Empty;
 58
 1259            yield return GetHeaders(url, headers, result => responseHeaders = result, (x) => headerRequestError = x);
 60
 661            if (!string.IsNullOrEmpty(headerRequestError))
 62            {
 063                OnFail?.Invoke(new Exception($"Error fetching headers! ({headerRequestError})"));
 064                yield break;
 65            }
 66
 667            string contentType = responseHeaders[CONTENT_TYPE];
 668            long.TryParse(responseHeaders[CONTENT_LENGTH], out long contentLength);
 669            bool isGif = contentType == CONTENT_TYPE_GIF;
 670            bool isWebp = contentType == CONTENT_TYPE_WEBP;
 71
 672            if (isWebp)
 73            {
 74                // We are going to fallback into gifs until we have proper support
 075                yield return FetchGif(url + "&fm=gif",
 76                    OnSuccess: (promise) =>
 77                    {
 078                        UnloadPromises();
 079                        this.gifPromise = promise;
 080                        OnSuccess?.Invoke(new NFTAsset_Gif(promise.asset));
 081                    },
 082                    OnFail: (exception) => { OnFail?.Invoke(exception); }
 83                );
 84
 085                yield break;
 86            }
 687            if (isGif)
 88            {
 289                yield return FetchGif(url,
 90                    OnSuccess: (promise) =>
 91                    {
 292                        UnloadPromises();
 293                        this.gifPromise = promise;
 294                        OnSuccess?.Invoke(new NFTAsset_Gif(promise.asset));
 295                    },
 096                    OnFail: (exception) => { OnFail?.Invoke(exception); }
 97                );
 98
 299                yield break;
 100            }
 101
 4102            if (contentLength > PREVIEW_IMAGE_SIZE_LIMIT)
 103            {
 1104                OnFail?.Invoke(new System.Exception($"Image is too big! {contentLength} > {PREVIEW_IMAGE_SIZE_LIMIT}"));
 1105                yield break;
 106            }
 107
 3108            yield return FetchImage(url,
 109                OnSuccess: (promise) =>
 110                {
 3111                    UnloadPromises();
 3112                    this.imagePromise = promise;
 3113                    OnSuccess?.Invoke(new NFTAsset_Image(promise.asset));
 3114                },
 0115                OnFail: (exc) => { OnFail?.Invoke(exc); });
 3116        }
 117
 118        public void Dispose()
 119        {
 5120            UnloadPromises();
 5121            tokenSource?.Cancel();
 5122            tokenSource?.Dispose();
 0123        }
 124
 125        protected virtual IEnumerator GetHeaders(string url, HashSet<string> headerField,
 126            Action<Dictionary<string, string>> OnSuccess, Action<string> OnFail)
 127        {
 0128            using (var request = UnityWebRequest.Head(url))
 129            {
 0130                yield return request.SendWebRequest();
 131
 0132                if (request.WebRequestSucceded())
 133                {
 0134                    var result = new Dictionary<string, string>();
 135
 0136                    foreach (var key in headerField)
 137                    {
 0138                        result.Add(key, request.GetResponseHeader(key));
 139                    }
 140
 0141                    OnSuccess?.Invoke(result);
 142                }
 143                else
 144                {
 0145                    OnFail?.Invoke(request.error);
 146                }
 0147            }
 0148        }
 149
 150        protected virtual IEnumerator FetchGif(string url, Action<AssetPromise_Gif> OnSuccess,
 151            Action<Exception> OnFail = null)
 152        {
 0153            AssetPromise_Gif gifPromise = new AssetPromise_Gif(url);
 0154            gifPromise.OnSuccessEvent += texture => { OnSuccess?.Invoke(gifPromise); };
 0155            gifPromise.OnFailEvent += (x, error) => OnFail?.Invoke(error);
 156
 0157            AssetPromiseKeeper_Gif.i.Keep(gifPromise);
 158
 0159            yield return gifPromise;
 0160        }
 161
 162        protected virtual IEnumerator FetchImage(string url, Action<AssetPromise_Texture> OnSuccess,
 163            Action<Exception> OnFail = null)
 164        {
 0165            AssetPromise_Texture texturePromise = new AssetPromise_Texture(url);
 0166            texturePromise.OnSuccessEvent += texture => { OnSuccess?.Invoke(texturePromise); };
 0167            texturePromise.OnFailEvent += (x, error) => OnFail?.Invoke(error);
 168
 0169            AssetPromiseKeeper_Texture.i.Keep(texturePromise);
 170
 0171            yield return texturePromise;
 0172        }
 173
 174        protected virtual void UnloadPromises()
 175        {
 10176            if (gifPromise != null)
 2177                AssetPromiseKeeper_Gif.i.Forget(gifPromise);
 178
 10179            if (imagePromise != null)
 3180                AssetPromiseKeeper_Texture.i.Forget(imagePromise);
 181
 10182            gifPromise = null;
 10183            imagePromise = null;
 10184        }
 185    }
 186}