< Summary

Class:BuilderAPIController
Assembly:BuilderAPI
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Scripts/BuiilderAPI/BuilderAPIController.cs
Covered lines:67
Uncovered lines:152
Coverable lines:219
Total lines:468
Line coverage:30.5% (67 of 219)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
BuilderAPIController()0%110100%
Initialize(...)0%2.032080%
Dispose()0%2.152066.67%
AskHeadersToKernel(...)0%3.033085.71%
HeadersReceived(...)0%550100%
CallUrl(...)0%110100%
CallWeb()0%1321100%
SetManifest(...)0%2100%
SetThumbnail(...)0%2100%
GetManifestById(...)0%2100%
DeleteProject(...)0%2100%
GetManifestByCoords(...)0%2100%
CreateNewProject(...)0%2100%
GetCompleteCatalog(...)0%110100%
GetAssets(...)0%6.755058.82%
GetAllProjectsData()0%110100%
GetManifestFromProjectId(...)0%2100%
GetManifestFromLandCoordinates(...)0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/DCLPlugins/BuilderInWorld/Scripts/BuiilderAPI/BuilderAPIController.cs

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Linq;
 5using DCL;
 6using DCL.Builder;
 7using DCL.Builder.Manifest;
 8using DCL.Configuration;
 9using DCL.Helpers;
 10using Newtonsoft.Json;
 11using Newtonsoft.Json.Linq;
 12using UnityEngine;
 13using UnityEngine.Networking;
 14
 15public class BuilderAPIController : IBuilderAPIController
 16{
 17    internal const string API_DATEFORMAT = "yyyy-MM-ddThh:mm:ss.fff%K";
 18
 19    internal const string CATALOG_ENDPOINT = "/assetPacks";
 20    internal const string ASSETS_ENDPOINT = "/assets?";
 21    internal const string GET_PROJECTS_ENDPOINT = "/projects";
 22    internal const string DELETE_PROJECTS_ENDPOINT = "/projects/{ID}";
 23    internal const string PROJECT_MANIFEST_ID_ENDPOINT = "/projects/{ID}/manifest";
 24    internal const string PROJECT_MANIFEST_COORDS_ENDPOINT = "/manifests";
 25    internal const string PROJECT_THUMBNAIL_ENDPOINT = "/projects/{ID}/media";
 26
 27    internal const string API_KO_RESPONSE_ERROR = "API response is KO";
 28
 29    internal const string GET = "get";
 30    internal const string PUT = "put";
 31    internal const string POST = "post";
 32    internal const string DELETE = "delete";
 33
 34    public event Action<IWebRequestAsyncOperation> OnWebRequestCreated;
 35
 36    internal IBuilderAPIResponseResolver apiResponseResolver;
 37
 38    private BuilderInWorldBridge builderInWorldBridge;
 39
 440    private Dictionary<string, List<Promise<RequestHeader>>> headersRequests = new Dictionary<string, List<Promise<Reque
 41
 42    public void Initialize(IContext context)
 43    {
 444        apiResponseResolver = new BuilderAPIResponseResolver();
 445        builderInWorldBridge = context.sceneReferences.biwBridgeGameObject.GetComponent<BuilderInWorldBridge>();
 446        if (builderInWorldBridge != null)
 047            builderInWorldBridge.OnHeadersReceived += HeadersReceived;
 448    }
 49
 50    public void Dispose()
 51    {
 452        if (builderInWorldBridge != null)
 053            builderInWorldBridge.OnHeadersReceived -= HeadersReceived;
 454    }
 55
 56    internal Promise<RequestHeader> AskHeadersToKernel(string method, string endpoint)
 57    {
 558        Promise<RequestHeader> promise = new Promise<RequestHeader>();
 559        if (headersRequests.ContainsKey(endpoint))
 160            headersRequests[endpoint].Add(promise);
 61        else
 462            headersRequests.Add(endpoint, new List<Promise<RequestHeader>>() { promise });
 63
 564        if (builderInWorldBridge != null)
 065            builderInWorldBridge.AskKernelForCatalogHeadersWithParams(method, endpoint);
 566        return promise;
 67    }
 68
 69    internal void HeadersReceived(RequestHeader requestHeader)
 70    {
 571        string keyToRemove = "";
 1872        foreach (var request in headersRequests)
 73        {
 474            if (request.Key == requestHeader.endpoint)
 75            {
 476                keyToRemove = request.Key;
 1877                foreach (Promise<RequestHeader> promise in request.Value)
 78                {
 579                    promise.Resolve(requestHeader);
 80                }
 81            }
 82        }
 83
 584        if (headersRequests.ContainsKey(keyToRemove))
 485            headersRequests.Remove(keyToRemove);
 586    }
 87
 88    internal Promise<string> CallUrl(string method, string endpoint, string callParams = "", byte[] body = null, string 
 89    {
 490        Promise<string> resultPromise = new Promise<string>();
 491        Promise<RequestHeader> headersPromise = AskHeadersToKernel(method, endpoint);
 492        headersPromise.Then(request =>
 93        {
 94            switch (method)
 95            {
 96                case GET:
 497                    IWebRequestAsyncOperation webRequest = BIWUtils.MakeGetCall(BIWUrlUtils.GetBuilderAPIBaseUrl() + req
 498                    OnWebRequestCreated?.Invoke(webRequest);
 099                    break;
 100                case PUT:
 0101                    request.body = body;
 0102                    CoroutineStarter.Start(CallWeb(request, resultPromise, contentType, PUT));
 0103                    break;
 104                case POST:
 0105                    request.body = body;
 0106                    CoroutineStarter.Start(CallWeb(request, resultPromise, contentType, POST));
 0107                    break;
 108                case DELETE:
 0109                    CoroutineStarter.Start(CallWeb(request, resultPromise, contentType, DELETE));
 110                    break;
 111            }
 0112        });
 113
 4114        return resultPromise;
 115    }
 116
 117    //This will disappear when we implement the signed fetch call
 118    IEnumerator CallWeb (RequestHeader requestHeader, Promise<string> resultPromise, string contentType, string method)
 119    {
 0120        UnityWebRequest www = null;
 121        switch (method)
 122        {
 123            case PUT:
 0124                www = UnityWebRequest.Put (BIWUrlUtils.GetBuilderAPIBaseUrl() + requestHeader.endpoint, requestHeader.bo
 0125                break;
 126            case POST:
 0127                WWWForm form = new WWWForm();
 0128                form.AddBinaryData("thumbnail", requestHeader.body);
 0129                www = UnityWebRequest.Post(BIWUrlUtils.GetBuilderAPIBaseUrl() + requestHeader.endpoint, form );
 0130                break;
 131            case DELETE:
 0132                www = UnityWebRequest.Delete(BIWUrlUtils.GetBuilderAPIBaseUrl() + requestHeader.endpoint);
 133                break;
 134        }
 135
 0136        if (!string.IsNullOrEmpty(contentType))
 0137            www.SetRequestHeader("Content-Type", contentType);
 138
 0139        foreach (var header in requestHeader.headers)
 140        {
 0141            www.SetRequestHeader(header.Key, header.Value);
 142        }
 143
 0144        yield return www.SendWebRequest();
 145
 0146        if (www.result != UnityWebRequest.Result.Success)
 147        {
 0148            resultPromise.Reject(www.error);
 0149        }
 150        else
 151        {
 152            // Note: The builder API doesn't answer with an structure for the DELETE method so we resolve it as an empty
 0153            if (www.downloadHandler != null)
 154            {
 0155                byte[] byteArray = www.downloadHandler.data;
 0156                string result = System.Text.Encoding.UTF8.GetString(byteArray);
 0157                resultPromise.Resolve(result);
 0158            }
 159            else
 160            {
 0161                resultPromise.Resolve("");
 162            }
 163        }
 164
 0165    }
 166
 167    public Promise<bool> SetManifest(IManifest manifest)
 168    {
 0169        Promise<bool> fullPromise = new Promise<bool>();
 170
 0171        JsonSerializerSettings dateFormatSettings = new JsonSerializerSettings
 172        {
 173            DateFormatString = API_DATEFORMAT,
 174        };
 175
 0176        string jsonManifest = JsonConvert.SerializeObject(manifest, dateFormatSettings);
 177
 0178        byte[] myData = System.Text.Encoding.UTF8.GetBytes(BIWUrlUtils.GetManifestJSON(jsonManifest));
 179
 0180        string endpoint = PROJECT_MANIFEST_ID_ENDPOINT.Replace("{ID}", manifest.project.id);
 0181        var promise =  CallUrl(PUT, endpoint, "", myData, "application/json");
 182
 0183        promise.Then(result =>
 184        {
 0185            var apiResponse = apiResponseResolver.GetResponseFromCall(result);
 0186            if (apiResponse.ok)
 0187                fullPromise.Resolve(true);
 188            else
 0189                fullPromise.Reject(apiResponse.error);
 0190        });
 191
 0192        promise.Catch(error =>
 193        {
 0194            fullPromise.Reject(error);
 0195        });
 196
 0197        return fullPromise;
 198    }
 199
 200    public Promise<bool> SetThumbnail(string id, Texture2D thumbnail)
 201    {
 0202        Promise<bool> fullPromise = new Promise<bool>();
 203
 0204        byte[] myData = thumbnail.EncodeToPNG();
 205
 0206        string endpoint = PROJECT_THUMBNAIL_ENDPOINT.Replace("{ID}", id);
 0207        var promise =  CallUrl(POST, endpoint, "", myData);
 208
 0209        promise.Then(result =>
 210        {
 0211            var apiResponse = apiResponseResolver.GetResponseFromCall(result);
 0212            if (apiResponse.ok)
 0213                fullPromise.Resolve(true);
 214            else
 0215                fullPromise.Reject(apiResponse.error);
 0216        });
 217
 0218        promise.Catch(error =>
 219        {
 0220            fullPromise.Reject(error);
 0221        });
 222
 0223        return fullPromise;
 224    }
 225
 226    public Promise<Manifest> GetManifestById(string idProject)
 227    {
 0228        Promise<Manifest> fullNewProjectPromise = new Promise<Manifest>();
 229
 0230        string url = PROJECT_MANIFEST_ID_ENDPOINT.Replace("{ID}", idProject);
 0231        var promise =  CallUrl(GET, url);
 232
 0233        promise.Then(result =>
 234        {
 0235            Manifest manifest = null;
 236
 237            try
 238            {
 0239                var x = JObject.Parse(result);
 240
 241                //We check if the object contains the version attribute, if it contains it it is a manifest
 0242                if (x["version"] != null)
 243                {
 0244                    manifest = JsonConvert.DeserializeObject<Manifest>(result);
 0245                    fullNewProjectPromise.Resolve(manifest);
 0246                }
 247                else
 248                {
 0249                    APIResponse response = JsonConvert.DeserializeObject<APIResponse>(result);
 0250                    if (!response.ok)
 0251                        fullNewProjectPromise.Reject(BIWSettings.PROJECT_NOT_FOUND);
 252                }
 0253            }
 0254            catch (Exception e)
 255            {
 0256                fullNewProjectPromise.Reject(e.Message);
 0257            }
 0258        });
 0259        promise.Catch(error =>
 260        {
 0261            fullNewProjectPromise.Reject(error);
 0262        });
 0263        return fullNewProjectPromise;
 264    }
 265
 266    public Promise<bool> DeleteProject(string id)
 267    {
 0268        Promise<bool> fullPromise = new Promise<bool>();
 269
 0270        string endpoint = DELETE_PROJECTS_ENDPOINT.Replace("{ID}", id);
 0271        var promise =  CallUrl(DELETE, endpoint);
 272
 0273        promise.Then(result =>
 274        {
 0275            fullPromise.Resolve(true);
 0276        });
 277
 0278        promise.Catch(error =>
 279        {
 0280            fullPromise.Reject(error);
 0281        });
 282
 0283        return fullPromise;
 284    }
 285
 286    public Promise<Manifest> GetManifestByCoords(string landCoords)
 287    {
 0288        Promise<Manifest> fullNewProjectPromise = new Promise<Manifest>();
 289
 0290        string callParams =  "?creation_coords_eq=" + landCoords;
 0291        var promise =  CallUrl(GET, PROJECT_MANIFEST_COORDS_ENDPOINT, callParams );
 292
 0293        promise.Then(result =>
 294        {
 0295            Manifest manifest = null;
 296
 297            try
 298            {
 0299                var jsonObject = JObject.Parse(result);
 300
 301                //We check if the object contains the version attribute, if it contains it it is a manifest
 302                //The API has two version , one with the APIResponse and one who don't
 0303                if (jsonObject["version"] != null)
 304                {
 0305                    manifest = JsonConvert.DeserializeObject<Manifest>(result);
 0306                    fullNewProjectPromise.Resolve(manifest);
 0307                }
 308                // Sometimes the API respond that OK but the data is empty so we need to check that
 0309                else if (jsonObject["data"].HasValues && jsonObject["data"].First["version"] != null)
 310                {
 0311                    APIResponse response = JsonConvert.DeserializeObject<APIResponse>(result);
 0312                    manifest = JsonConvert.DeserializeObject<Manifest[]>(response.data.ToString())[0];
 0313                    fullNewProjectPromise.Resolve(manifest);
 0314                }
 315                else
 316                {
 0317                    APIResponse response = JsonConvert.DeserializeObject<APIResponse>(result);
 0318                    fullNewProjectPromise.Reject(BIWSettings.PROJECT_NOT_FOUND);
 319                }
 0320            }
 0321            catch (Exception e)
 322            {
 0323                fullNewProjectPromise.Reject(e.Message);
 0324            }
 0325        });
 0326        promise.Catch(error =>
 327        {
 0328            fullNewProjectPromise.Reject(error);
 0329        });
 0330        return fullNewProjectPromise;
 331    }
 332
 333    public Promise<ProjectData> CreateNewProject(ProjectData newProject)
 334    {
 0335        Promise<ProjectData> fullNewProjectPromise = new Promise<ProjectData>();
 0336        Manifest builderManifest = BIWUtils.CreateManifestFromProject(newProject);
 337
 0338        JsonSerializerSettings dateFormatSettings = new JsonSerializerSettings
 339        {
 340            DateFormatString = API_DATEFORMAT,
 341        };
 342
 0343        string jsonManifest = JsonConvert.SerializeObject(builderManifest, dateFormatSettings);
 0344        byte[] myData = System.Text.Encoding.UTF8.GetBytes(BIWUrlUtils.GetManifestJSON(jsonManifest));
 345
 0346        string endpoint = PROJECT_MANIFEST_ID_ENDPOINT.Replace("{ID}", newProject.id);
 0347        var promise =  CallUrl(PUT, endpoint, "", myData, "application/json");
 348
 0349        promise.Then(result =>
 350        {
 0351            var apiResponse = apiResponseResolver.GetResponseFromCall(result);
 0352            if (apiResponse.ok)
 0353                fullNewProjectPromise.Resolve(JsonConvert.DeserializeObject<ProjectData>(apiResponse.data.ToString()));
 354            else
 0355                fullNewProjectPromise.Reject(apiResponse.error);
 0356        });
 357
 0358        promise.Catch(error =>
 359        {
 0360            fullNewProjectPromise.Reject(error);
 0361        });
 362
 0363        return fullNewProjectPromise;
 364    }
 365
 366    public Promise<bool> GetCompleteCatalog(string ethAddres)
 367    {
 1368        Promise<bool> fullCatalogPromise = new Promise<bool>();
 369
 1370        var promiseDefaultCatalog =  CallUrl(GET, CATALOG_ENDPOINT, "?owner=default");
 1371        var promiseOwnedCatalog = CallUrl(GET, CATALOG_ENDPOINT, "?owner=" + ethAddres);
 1372        int amountOfCatalogReceived = 0;
 373
 374        // Note: In order to get the full catalog we need to do 2 calls, the default one and the specific one
 375        // This is done in order to cache the response in the server
 1376        promiseDefaultCatalog.Then(catalogJson =>
 377        {
 1378            AssetCatalogBridge.i.AddFullSceneObjectCatalog(catalogJson);
 379
 1380            amountOfCatalogReceived++;
 1381            if (amountOfCatalogReceived >= 2)
 0382                fullCatalogPromise.Resolve(true);
 1383        });
 1384        promiseDefaultCatalog.Reject("Unable to get default catalog");
 385
 1386        promiseOwnedCatalog.Then(catalogJson =>
 387        {
 1388            AssetCatalogBridge.i.AddFullSceneObjectCatalog(catalogJson);
 389
 1390            amountOfCatalogReceived++;
 1391            if (amountOfCatalogReceived >= 2)
 1392                fullCatalogPromise.Resolve(true);
 1393        });
 394
 1395        promiseOwnedCatalog.Reject("Unable to get owned catalog");
 396
 1397        return fullCatalogPromise;
 398    }
 399
 400    public Promise<bool> GetAssets(List<string> assetsIds)
 401    {
 1402        List<string> assetsToAsk = new List<string>();
 2403        foreach (string assetsId in assetsIds)
 404        {
 0405            if (!AssetCatalogBridge.i.sceneObjectCatalog.ContainsKey(assetsId))
 0406                assetsToAsk.Add(assetsId);
 407        }
 408
 1409        string query = "";
 2410        foreach (string assetsId in assetsToAsk)
 411        {
 0412            if (string.IsNullOrEmpty(query))
 0413                query += "id=" + assetsId;
 414            else
 0415                query += "&id=" + assetsId;
 416        }
 417
 1418        Promise<bool> fullCatalogPromise = new Promise<bool>();
 419
 1420        var promise =  CallUrl(GET, ASSETS_ENDPOINT , query);
 421
 1422        promise.Then(apiResult =>
 423        {
 1424            var assets = apiResponseResolver.GetArrayFromCall<SceneObject>(apiResult);
 1425            if (assets != null)
 426            {
 1427                AssetCatalogBridge.i.AddScenesObjectToSceneCatalog(assets);
 1428                fullCatalogPromise.Resolve(true);
 1429            }
 430            else
 431            {
 0432                fullCatalogPromise.Reject(API_KO_RESPONSE_ERROR);
 433            }
 0434        });
 435
 1436        return fullCatalogPromise;
 437    }
 438
 439    public Promise<List<ProjectData>> GetAllProjectsData()
 440    {
 1441        Promise<List<ProjectData>> fullCatalogPromise = new Promise< List<ProjectData>>();
 442
 1443        var promise =  CallUrl(GET, GET_PROJECTS_ENDPOINT);
 444
 1445        promise.Then(result =>
 446        {
 1447            List<ProjectData> allManifest = apiResponseResolver.GetArrayFromCall<ProjectData>(result).ToList();
 1448            fullCatalogPromise.Resolve(allManifest);
 1449        });
 1450        promise.Catch(error =>
 451        {
 0452            fullCatalogPromise.Reject(error);
 0453        });
 1454        return fullCatalogPromise;
 455    }
 456
 457    public Manifest GetManifestFromProjectId(string projectId)
 458    {
 459        //TODO: Implement functionality
 0460        return null;
 461    }
 462
 463    public Manifest GetManifestFromLandCoordinates(string landCoords)
 464    {
 465        //TODO: Implement functionality
 0466        return null;
 467    }
 468}