Ejemplo n.º 1
0
        /// <summary>
        /// Obtain token using itSeez3D username and password. Not for production use!
        /// </summary>
        private AsyncWebRequest <AccessData> AuthorizePasswordGrantTypeAsync(
            string clientId,
            string clientSecret,
            string username,
            string password
            )
        {
            Debug.LogWarning("Don't use this auth method in production, use other grant types!");
            var request = new AsyncWebRequest <AccessData> (AvatarSdkMgr.Str(Strings.RequestingApiToken));

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(clientId))
            {
                request.SetError("itSeez3D credentials not provided");
                Debug.LogError(request.ErrorMessage);
                return(request);
            }

            var form = new Dictionary <string, string> ()
            {
                { "grant_type", "password" },
                { "username", username },
                { "password", password },
                { "client_id", clientId },
                { "client_secret", clientSecret },
            };
            Func <UnityWebRequest> webRequestFactory = () => HttpPost(GetUrl("o", "token"), form);

            AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(webRequestFactory, request));
            return(request);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Download pages until the desired number of items is requested.
        /// </summary>
        public virtual AsyncWebRequest <DataType[]> AvatarJsonArrayRequest <DataType> (string url, int maxItems = int.MaxValue)
        {
            var request = new AsyncWebRequest <DataType[]> ();

            AvatarSdkMgr.SpawnCoroutine(AwaitMultiplePages(url, request, maxItems));
            return(request);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Send HTTP GET request, deserialize response as DataType.
        /// </summary>
        /// <returns>Async request object that will contain an instance of DataType on success.</returns>
        public virtual AsyncWebRequest <DataType> AvatarJsonRequest <DataType> (string url)
        {
            var request = new AsyncWebRequest <DataType> ();

            AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(() => HttpGet(url), request));
            return(request);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Edit avatar name/description on the server.
        /// </summary>
        public virtual AsyncWebRequest EditAvatarAsync(AvatarData avatar, string name = null, string description = null)
        {
            var request = new AsyncWebRequest(AvatarSdkMgr.Str(Strings.EditingAvatar));

            byte[] requestBodyData = null;
            using (var requestBody = new MultipartBody()) {
                requestBody.WriteTextField("name", name);
                requestBody.WriteTextField("description", description);
                requestBody.WriteFooter();
                requestBodyData = requestBody.GetRequestBodyData();

                Func <UnityWebRequest> webRequestFactory = () => {
                    var webRequest = UnityWebRequest.Post(avatar.url, " ");
                    webRequest.chunkedTransfer = false;
                    webRequest.method          = "PATCH";
                    webRequest.uploadHandler   = new UploadHandlerRaw(requestBodyData);
                    webRequest.SetRequestHeader(
                        "Content-Type", string.Format("multipart/form-data; boundary=\"{0}\"", requestBody.Boundary)
                        );
                    SetAuthHeaders(webRequest);
                    return(webRequest);
                };

                Debug.LogFormat("Uploading photo...");
                AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(webRequestFactory, request));
                return(request);
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Send HTTP GET request, deserialize response as Page<T>.
        /// </summary>
        /// <returns>Async request object that will contain an instance of Page<T> on success.</returns>
        public virtual AsyncWebRequest <Page <T> > AvatarJsonPageRequest <T> (string url)
        {
            var request = new AsyncWebRequest <Page <T> > ();

            AvatarSdkMgr.SpawnCoroutine(AwaitJsonPageWebRequest(() => HttpGet(url), request));
            return(request);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Obtain token using client credentials.
        /// </summary>
        private AsyncWebRequest <AccessData> AuthorizeClientCredentialsGrantTypeAsync(AccessCredentials credentials)
        {
            var request = new AsyncWebRequest <AccessData> (AvatarSdkMgr.Str(Strings.RequestingApiToken));
            Func <UnityWebRequest> webRequestFactory = () => GenerateAuthRequest(credentials);

            AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(webRequestFactory, request));
            return(request);
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Call AwaitWebRequestFunc, interpret response as JSON.
 /// </summary>
 public virtual IEnumerator AwaitJsonWebRequest <DataType> (
     Func <UnityWebRequest> webRequestFactory,
     AsyncWebRequest <DataType> request)
 {
     yield return(AwaitWebRequestFunc(webRequestFactory, request, (r) => {
         return JsonUtility.FromJson <DataType> (r.downloadHandler.text);
     }));
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Download file.
        /// </summary>
        public virtual AsyncWebRequest <byte[]> AvatarDataRequestAsync(string url)
        {
            Debug.LogFormat("Downloading from {0}...", url);
            var request = new AsyncWebRequest <byte[]> ();

            AvatarSdkMgr.SpawnCoroutine(AwaitDataAsync(() => HttpGet(url), request));
            return(request);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Call AwaitWebRequestFunc for paginated requests.
        /// </summary>
        public virtual IEnumerator AwaitJsonPageWebRequest <T> (
            Func <UnityWebRequest> webRequestFactory,
            AsyncWebRequest <Page <T> > request
            )
        {
            yield return(AwaitWebRequestFunc(webRequestFactory, request, (r) => {
                // Unity JsonUtility does not support Json array parsing, so we have to hack around it
                // by wrapping it into object with a single array field.
                var wrappedArrayJson = string.Format("{{ \"content\": {0} }}", r.downloadHandler.text);
                var page = JsonUtility.FromJson <Page <T> > (wrappedArrayJson);
                var paginationHeader = r.GetResponseHeader("Link");

                // parse "Link" header to get links to adjacent pages
                if (!string.IsNullOrEmpty(paginationHeader))
                {
                    var regex = new Regex(@".*\<(?<link>.+)\>.+rel=""(?<kind>.*)""");
                    var tokens = paginationHeader.Split(',');
                    foreach (var token in tokens)
                    {
                        var match = regex.Match(token);
                        if (!match.Success)
                        {
                            continue;
                        }

                        string link = match.Groups ["link"].Value, kind = match.Groups ["kind"].Value;
                        if (string.IsNullOrEmpty(link) || string.IsNullOrEmpty(kind))
                        {
                            continue;
                        }

                        if (kind == "first")
                        {
                            page.firstPageUrl = link;
                        }
                        else if (kind == "next")
                        {
                            page.nextPageUrl = link;
                        }
                        else if (kind == "prev")
                        {
                            page.prevPageUrl = link;
                        }
                        else if (kind == "last")
                        {
                            page.lastPageUrl = link;
                        }
                    }
                }
                return page;
            }));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Delete avatar record on the server (does not delete local files).
        /// </summary>
        public virtual AsyncWebRequest DeleteAvatarAsync(AvatarData avatar)
        {
            var request = new AsyncWebRequest(AvatarSdkMgr.Str(Strings.DeletingAvatarOnServer));

            Func <UnityWebRequest> webRequestFactory = () => {
                var webRequest = UnityWebRequest.Delete(avatar.url);
                SetAuthHeaders(webRequest);
                webRequest.downloadHandler = new DownloadHandlerBuffer();
                return(webRequest);
            };

            AvatarSdkMgr.SpawnCoroutine(AwaitWebRequest(webRequestFactory, request));
            return(request);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Register unique player UID that is used later to sign the requests.
        /// </summary>
        /// <param name="comment">Arbitrary data associated with player UID.</param>
        public virtual AsyncWebRequest <Player> RegisterPlayerAsync(string comment = "")
        {
            var r    = new AsyncWebRequest <Player> (AvatarSdkMgr.Str(Strings.RegisteringPlayerID));
            var form = new Dictionary <string, string> ()
            {
                { "comment", comment },
            };
            Func <UnityWebRequest> webRequestFactory = () => {
                var webRequest = HttpPost(GetUrl("players"), form);
                SetAuthHeaders(webRequest);
                return(webRequest);
            };

            AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(webRequestFactory, r));
            return(r);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Request to get available resources for the pipeline
        /// </summary>
        public virtual AsyncWebRequest <string> GetResourcesAsync(PipelineType pipelineType, AvatarResourcesSubset resourcesSubset)
        {
            string subsetStr = "available";

            if (resourcesSubset == AvatarResourcesSubset.DEFAULT)
            {
                subsetStr = "default";
            }

            var url = GetUrl("resources", subsetStr, pipelineType.GetPipelineTypeName());

            url = UrlWithParams(url, "pipeline_subtype", pipeline_subtype);
            var request = new AsyncWebRequest <string>(Strings.GettingResourcesList);

            AvatarSdkMgr.SpawnCoroutine(AwaitStringDataAsync(() => HttpGet(url), request));
            return(request);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Send the request, wait till it finishes and process the result.
        /// </summary>
        /// <returns>The web request func.</returns>
        /// <param name="webRequestFactory">Function that returns the new copy of UnityWebRequest
        /// (needed for retry).</param>
        /// <param name="request">"Parent" async request object to report progress to.</param>
        /// <param name="parseDataFunc">Function that takes care of parsing data (usually JSON parsing).</param>
        private IEnumerator AwaitWebRequestFunc <T> (
            Func <UnityWebRequest> webRequestFactory,
            AsyncWebRequest <T> request,
            Func <UnityWebRequest, T> parseDataFunc
            )
        {
            UnityWebRequest webRequest = null;

            StatusCode status = new StatusCode();
            string     error  = string.Empty;

            int  numAttempts = 2, lastAttempt = numAttempts - 1;
            bool goodResponse = false;

            for (int attempt = 0; attempt < numAttempts; ++attempt)
            {
                webRequest = webRequestFactory();
                yield return(AwaitAndTrackProgress(webRequest, request));

                if (goodResponse = IsGoodResponse(webRequest, out status, out error))
                {
                    break;
                }

                // all API requests have Authorization header, except for authorization requests
                bool isAuthRequest = webRequest.GetRequestHeader("Authorization") == null;

                Debug.LogWarningFormat("Server error: {0}, request: {1}", error, webRequest.url);
                if (status.Value != (long)StatusCode.Code.UNAUTHORIZED || isAuthRequest)
                {
                    // cannot recover, request has failed
                    break;
                }

                if (attempt == lastAttempt)
                {
                    Debug.LogError("No more retries left");
                    break;
                }

                Debug.LogWarning("Auth issue, let's try one more time after refreshing access token");
                yield return(AuthorizeAsync());
            }

            if (!goodResponse)
            {
                Debug.LogErrorFormat("Could not send the request, status: {0}, error: {1}", status, error);
                request.Status = status;
                request.SetError(error);
                yield break;
            }

            T data = default(T);

            try {
                data = parseDataFunc(webRequest);
            } catch (Exception ex) {
                Debug.LogException(ex);
            }

            if (data == null)
            {
                request.SetError("Could not parse request data");
                yield break;
            }
            else
            {
                request.Result = data;
            }

            request.IsDone = true;
        }
Ejemplo n.º 14
0
        /// <summary>
        /// DownloadAndSaveAvatarModelAsync implementation.
        /// </summary>
        private static IEnumerator DownloadAndSaveAvatarModel(
            Connection connection,
            AvatarData avatar,
            bool withHaircutPointClouds,
            bool withBlendshapes,
            AsyncRequest <AvatarData> request
            )
        {
            // By initializing multiple requests at the same time (without yield between them) we're
            // starting them in parallel. In this particular case we're downloading multiple files at the same time,
            // which is usually a bit faster than sequential download.
            var meshZip        = connection.DownloadMeshZipAsync(avatar);
            var textureRequest = connection.DownloadTextureBytesAsync(avatar);

            var download = new List <AsyncRequest> {
                meshZip, textureRequest
            };
            AsyncWebRequest <byte[]> allHaircutPointCloudsZip = null, blendshapesZip = null;

                        #if BLENDSHAPES_IN_PLY_OR_FBX
            // just a sample of how to get blendshapes in a different format

            AsyncWebRequest <byte[]> blendshapesZipFbx = null, blendshapesZipPly = null;
                        #endif

            if (withHaircutPointClouds)
            {
                allHaircutPointCloudsZip = connection.DownloadAllHaircutPointCloudsZipAsync(avatar);
                download.Add(allHaircutPointCloudsZip);
            }

            if (withBlendshapes)
            {
                blendshapesZip = connection.DownloadBlendshapesZipAsync(avatar);
                download.Add(blendshapesZip);

                                #if BLENDSHAPES_IN_PLY_OR_FBX
                // just a sample of how to get blendshapes in a different format

                blendshapesZipFbx = connection.DownloadBlendshapesZipAsync(avatar, BlendshapesFormat.FBX);
                download.Add(blendshapesZipFbx);

                blendshapesZipPly = connection.DownloadBlendshapesZipAsync(avatar, BlendshapesFormat.PLY);
                download.Add(blendshapesZipPly);
                                #endif
            }

            // continue execution when all requests finish
            yield return(request.AwaitSubrequests(0.9f, download.ToArray()));

            // return if any of the requests failed
            if (request.IsError)
            {
                yield break;
            }

            // save all the results to disk, also in parallel
            var saveMeshZip = CoreTools.SaveAvatarFileAsync(meshZip.Result, avatar.code, AvatarFile.MESH_ZIP);
            var saveTexture = CoreTools.SaveAvatarFileAsync(textureRequest.Result, avatar.code, AvatarFile.TEXTURE);

            var save = new List <AsyncRequest> ()
            {
                saveMeshZip, saveTexture
            };
            AsyncRequest <string> saveHaircutPointsZip = null, saveBlendshapesZip = null;
            if (allHaircutPointCloudsZip != null)
            {
                saveHaircutPointsZip = CoreTools.SaveAvatarFileAsync(allHaircutPointCloudsZip.Result, avatar.code, AvatarFile.ALL_HAIRCUT_POINTS_ZIP);
                save.Add(saveHaircutPointsZip);
            }

            if (blendshapesZip != null)
            {
                saveBlendshapesZip = CoreTools.SaveAvatarFileAsync(blendshapesZip.Result, avatar.code, AvatarFile.BLENDSHAPES_ZIP);
                save.Add(saveBlendshapesZip);
            }

                        #if BLENDSHAPES_IN_PLY_OR_FBX
            // just a sample of how to get blendshapes in a different format

            if (blendshapesZipFbx != null)
            {
                var saveBlendshapesZipFbx = CoreTools.SaveAvatarFileAsync(blendshapesZipFbx.Result, avatar.code, AvatarFile.BLENDSHAPES_FBX_ZIP);
                save.Add(saveBlendshapesZipFbx);
            }

            if (blendshapesZipPly != null)
            {
                var saveBlendshapesZipPly = CoreTools.SaveAvatarFileAsync(blendshapesZipPly.Result, avatar.code, AvatarFile.BLENDSHAPES_PLY_ZIP);
                save.Add(saveBlendshapesZipPly);
            }
                        #endif

            yield return(request.AwaitSubrequests(0.95f, save.ToArray()));

            if (request.IsError)
            {
                yield break;
            }

            var unzipMesh = CoreTools.UnzipFileAsync(saveMeshZip.Result);

            var unzip = new List <AsyncRequest> ()
            {
                unzipMesh
            };
            AsyncRequest <string> unzipHaircutPoints = null, unzipBlendshapes = null;
            if (saveHaircutPointsZip != null)
            {
                unzipHaircutPoints = CoreTools.UnzipFileAsync(saveHaircutPointsZip.Result);
                unzip.Add(unzipHaircutPoints);
            }
            if (saveBlendshapesZip != null)
            {
                unzipBlendshapes = UnzipBlendshapes(saveBlendshapesZip.Result, avatar.code);
                unzip.Add(unzipBlendshapes);
            }

            yield return(request.AwaitSubrequests(0.99f, unzip.ToArray()));

            if (request.IsError)
            {
                yield break;
            }

            // delete all .zip files we don't need anymore
            try {
                foreach (var fileToDelete in new AvatarFile[] { AvatarFile.MESH_ZIP, AvatarFile.ALL_HAIRCUT_POINTS_ZIP, AvatarFile.BLENDSHAPES_ZIP })
                {
                    CoreTools.DeleteAvatarFile(avatar.code, fileToDelete);
                }
            } catch (Exception ex) {
                // error here is not critical, we can just ignore it
                Debug.LogException(ex);
            }

            request.Result = avatar;
            request.IsDone = true;
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Variation of AwaitWebRequestFunc when we don't actually need the result.
 /// </summary>
 public virtual IEnumerator AwaitWebRequest(Func <UnityWebRequest> webRequestFactory, AsyncWebRequest request)
 {
     yield return(AwaitWebRequestFunc(webRequestFactory, request, (r) => new object()));
 }
Ejemplo n.º 16
0
        /// <summary>
        /// Upload photo and create avatar instance on the server. Calculations will start right away after the photo is uploaded.
        /// </summary>
        public virtual AsyncWebRequest <AvatarData> CreateAvatarWithPhotoAsync(
            string name, string description, byte[] photoBytes, bool forcePowerOfTwoTexture = false,
            PipelineType pipeline = PipelineType.FACE, AvatarResources resources = null
            )
        {
            var request = new AsyncWebRequest <AvatarData> (AvatarSdkMgr.Str(Strings.UploadingPhoto), TrackProgress.UPLOAD);

#if UNITY_2017_1_OR_NEWER
            Func <UnityWebRequest> webRequestFactory = () =>
            {
                List <IMultipartFormSection> formData = new List <IMultipartFormSection>();
                formData.Add(new MultipartFormDataSection("name", name));
                if (!string.IsNullOrEmpty(description))
                {
                    formData.Add(new MultipartFormDataSection("description", description));
                }
                formData.Add(new MultipartFormFileSection("photo", photoBytes, "photo.jpg", "application/octet-stream"));
                formData.Add(new MultipartFormDataSection("preserve_original_texture", (!forcePowerOfTwoTexture).ToString()));
                formData.Add(new MultipartFormDataSection("pipeline", pipeline.GetPipelineTypeName()));

                if (resources != null)
                {
                    formData.Add(new MultipartFormDataSection("pipeline_subtype", pipeline_subtype));
                    formData.Add(new MultipartFormDataSection("resources", CoreTools.GetAvatarCalculationParamsJson(resources)));
                }

                var webRequest = UnityWebRequest.Post(GetUrl("avatars"), formData);
                webRequest.chunkedTransfer = false;
                SetAuthHeaders(webRequest);
                return(webRequest);
            };

            Debug.LogFormat("Uploading photo...");
            AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(webRequestFactory, request));
            return(request);
#else
            // Unity 5.5.0 (and probably earlier versions) have a weird bug in default multipart form data
            // implementation, which causes incorrect boundaries between data fields. To work around this bug the
            // multipart request body is constructed manually, see below.
            byte[] requestBodyData = null;
            using (var requestBody = new MultipartBody()) {
                requestBody.WriteTextField("name", name);
                requestBody.WriteTextField("description", description);
                requestBody.WriteFileField("photo", "photo.jpg", photoBytes);
                requestBody.WriteTextField("preserve_original_texture", (!forcePowerOfTwoTexture).ToString());
                requestBody.WriteTextField("pipeline", pipeline.GetPipelineTypeName());

                if (resources != null)
                {
                    requestBody.WriteTextField("pipeline_subtype", pipeline_subtype);
                    requestBody.WriteTextField("resources", CoreTools.GetAvatarCalculationParamsJson(resources));
                }

                requestBody.WriteFooter();
                requestBodyData = requestBody.GetRequestBodyData();

                Func <UnityWebRequest> webRequestFactory = () => {
                    var webRequest = UnityWebRequest.Post(GetUrl("avatars"), " ");
                    webRequest.uploadHandler = new UploadHandlerRaw(requestBodyData);
                    webRequest.SetRequestHeader(
                        "Content-Type", string.Format("multipart/form-data; boundary=\"{0}\"", requestBody.Boundary)
                        );
                    webRequest.chunkedTransfer = false;
                    SetAuthHeaders(webRequest);
                    return(webRequest);
                };

                Debug.LogFormat("Uploading photo...");
                AvatarSdkMgr.SpawnCoroutine(AwaitJsonWebRequest(webRequestFactory, request));
                return(request);
            }
#endif
        }
Ejemplo n.º 17
0
 /// <summary>
 /// Call AwaitWebRequestFunc for binary data.
 /// </summary>
 public virtual IEnumerator AwaitDataAsync(Func <UnityWebRequest> webRequestFactory, AsyncWebRequest <byte[]> request)
 {
     yield return(AwaitWebRequestFunc(webRequestFactory, request, (r) => r.downloadHandler.data));
 }
Ejemplo n.º 18
0
 /// <summary>
 /// Call AwaitWebRequestFunc for string data.
 /// </summary>
 public virtual IEnumerator AwaitStringDataAsync(Func <UnityWebRequest> webRequestFactory, AsyncWebRequest <string> request)
 {
     yield return(AwaitWebRequestFunc(webRequestFactory, request, (r) => r.downloadHandler.text));
 }
Ejemplo n.º 19
0
        /// <summary>
        /// Helper routine that waits until the request finishes and updates progress for the request object.
        /// </summary>
        private static IEnumerator AwaitAndTrackProgress <T> (UnityWebRequest webRequest, AsyncWebRequest <T> request)
        {
                        #if UNITY_2017_2_OR_NEWER
            webRequest.SendWebRequest();
                        #else
            webRequest.Send();
                        #endif
            do
            {
                yield return(null);

                switch (request.ProgressTracking)
                {
                case TrackProgress.DOWNLOAD:
                    request.Progress = webRequest.downloadProgress;
                    break;

                case TrackProgress.UPLOAD:
                    request.Progress = webRequest.uploadProgress;
                    break;
                }

                request.BytesDownloaded = webRequest.downloadedBytes;
                request.BytesUploaded   = webRequest.uploadedBytes;
            } while(!webRequest.isDone);
        }