private IEnumerator LoadProfileIcon(string uri)
        {
            if (Profile == null)
            {
                yield break;
            }
            using (UnityWebRequest www = UnityCompat.GetTexture(uri + kIconSizeSuffix)) {
                yield return(UnityCompat.SendWebRequest(www));

                if (UnityCompat.IsNetworkError(www) || www.responseCode >= 400)
                {
                    Debug.LogErrorFormat("Error downloading {0}, error {1}", uri, www.responseCode);
                    Profile.icon = null;
                }
                else
                {
                    // Convert the texture to a circle and set it as the user's avatar in the UI.
                    Texture2D profileImage = DownloadHandlerTexture.GetContent(www);
                    Profile.icon = Sprite.Create(CropSquareTextureToCircle(profileImage),
                                                 new Rect(0, 0, profileImage.width, profileImage.height), new Vector2(0.5f, 0.5f),
                                                 USER_AVATAR_PIXELS_PER_UNIT);
                }
                if (m_OnProfileUpdated != null)
                {
                    m_OnProfileUpdated();
                }
            }
        }
        // I have a refresh token, I need an access token.
        public IEnumerator <object> Reauthorize(Action successCallback, Action <string> failureCallback)
        {
            m_AccessToken = null;
            if (!String.IsNullOrEmpty(m_RefreshToken))
            {
                Dictionary <string, string> parameters = new Dictionary <string, string>();
                parameters.Add("client_id", m_ClientId);
                parameters.Add("client_secret", m_ClientSecret);
                parameters.Add("refresh_token", m_RefreshToken);
                parameters.Add("grant_type", "refresh_token");
                using (UnityWebRequest www = UnityWebRequest.Post(m_AccessTokenUri, parameters)) {
                    yield return(UnityCompat.SendWebRequest(www));

                    if (UnityCompat.IsNetworkError(www))
                    {
                        failureCallback("Network error");
                        yield break;
                    }

                    if (www.responseCode == 400 || www.responseCode == 401)
                    {
                        // Refresh token revoked or expired - forget it
                        m_RefreshToken = null;
                        PlayerPrefs.DeleteKey(m_PlayerPrefRefreshKey);
                        failureCallback("No valid refresh token, could not reauthorize");
                    }
                    else
                    {
                        JObject json = JObject.Parse(www.downloadHandler.text);
                        m_AccessToken = json["access_token"].ToString();
                        successCallback();
                    }
                }
            }
        }
        /// I have nothing.  Open browser to authorize permissions then get refresh and access tokens.
        public IEnumerator <object> Authorize(System.Action onSuccess, System.Action onFailure,
                                              bool launchSignInFlowIfNeeded)
        {
            if (String.IsNullOrEmpty(m_RefreshToken))
            {
                if (!launchSignInFlowIfNeeded)
                {
                    // We need to launch the sign-in flow. If we are not allowed to, then we have failed.
                    onFailure();
                    yield break;
                }

                if (m_HttpListener == null)
                {
                    // Listener is not yet running. Let's try to start it.
                    if (!StartHttpListener(out m_HttpPort, out m_HttpListener))
                    {
                        // Failed to start HTTP listener.
                        Debug.LogError("Failed to start HTTP listener for authentication flow.");
                        if (onFailure != null)
                        {
                            onFailure();
                        }
                        yield break;
                    }
                    // HTTP listener successfully started.
                }

                StringBuilder sb = new StringBuilder(m_RequestTokenUri)
                                   .Append("?client_id=").Append(Uri.EscapeDataString(m_ClientId))
                                   .Append("&redirect_uri=").Append("http://localhost:").Append(m_HttpPort).Append(m_CallbackPath)
                                   .Append("&response_type=code")
                                   .Append("&scope=").Append(m_OAuthScope);

                // Something about the url makes OpenURL() not work on OSX, so use a workaround
                if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.OSXPlayer)
                {
                    System.Diagnostics.Process.Start(sb.ToString());
                }
                else
                {
                    Application.OpenURL(sb.ToString());
                }

                if (m_WaitingOnAuthorization)
                {
                    // A previous attempt is already waiting
                    yield break;
                }
                m_WaitingOnAuthorization = true;
                m_VerificationCode       = null;
                m_VerificationError      = false;

                // Wait for verification
                while (m_VerificationCode == null && !m_VerificationError)
                {
                    yield return(null);
                }

                if (m_VerificationError)
                {
                    Debug.LogError("Account verification failed");
                    Debug.LogFormat("Verification error {0}", m_VerificationCode);
                    m_WaitingOnAuthorization = false;
                    yield break;
                }

                // Exchange for tokens
                var parameters = new Dictionary <string, string>();
                parameters.Add("code", m_VerificationCode);
                parameters.Add("client_id", m_ClientId);
                parameters.Add("client_secret", m_ClientSecret);
                parameters.Add("redirect_uri", String.Format("http://localhost:{0}{1}", m_HttpPort, m_CallbackPath));
                parameters.Add("grant_type", "authorization_code");

                UnityWebRequest www = UnityWebRequest.Post(m_AccessTokenUri, parameters);

                yield return(UnityCompat.SendWebRequest(www));

                if (UnityCompat.IsNetworkError(www))
                {
                    Debug.LogError("Network error");
                    m_WaitingOnAuthorization = false;
                    yield break;
                }
                else if (www.responseCode >= 400)
                {
                    Debug.LogError("Authorization failed");
                    Debug.LogFormat("Authorization error {0}", www.downloadHandler.text);
                    m_WaitingOnAuthorization = false;
                    yield break;
                }

                JObject json = JObject.Parse(www.downloadHandler.text);
                if (json != null)
                {
                    SetTokens(json["access_token"].ToString(), json["refresh_token"].ToString());
                }
                m_WaitingOnAuthorization = false;
            }

            yield return(GetUserInfo());

            if (LoggedIn)
            {
                onSuccess();
            }
            else
            {
                onFailure();
            }
        }
示例#4
0
        /// <summary>
        /// Co-routine that services one PendingRequest. This method must be called with StartCoroutine.
        /// </summary>
        /// <param name="request">The request to service.</param>
        private IEnumerator HandleWebRequest(PendingRequest request, BufferHolder bufferHolder)
        {
            // NOTE: This method runs on the main thread, but never blocks -- the blocking part of the work is
            // done by yielding the UnityWebRequest, which releases the main thread for other tasks while we
            // are waiting for the web request to complete (by the miracle of coroutines).

            // Let the caller create the UnityWebRequest, configuring it as they want. The caller can set the URL,
            // method, headers, anything they want. The only thing they can't do is call Send(), as we're in charge
            // of doing that.
            UnityWebRequest webRequest = request.creationCallback();

            PtDebug.LogVerboseFormat("Web request: {0} {1}", webRequest.method, webRequest.url);

            bool cacheAllowed = cache != null && webRequest.method == "GET" && request.maxAgeMillis != CACHE_NONE;

            // Check the cache (if it's a GET request and cache is enabled).
            if (cacheAllowed)
            {
                bool   cacheHit      = false;
                byte[] cacheData     = null;
                bool   cacheReadDone = false;
                cache.RequestRead(webRequest.url, request.maxAgeMillis, (bool success, byte[] data) =>
                {
                    cacheHit      = success;
                    cacheData     = data;
                    cacheReadDone = true;
                });
                while (!cacheReadDone)
                {
                    yield return(null);
                }
                if (cacheHit)
                {
                    PtDebug.LogVerboseFormat("Web request CACHE HIT: {0}, response: {1} bytes",
                                             webRequest.url, cacheData.Length);
                    request.completionCallback(PolyStatus.Success(), /* responseCode */ 200, cacheData);

                    // Return the buffer to the pool for reuse.
                    CleanUpAfterWebRequest(bufferHolder);

                    yield break;
                }
                else
                {
                    PtDebug.LogVerboseFormat("Web request CACHE MISS: {0}.", webRequest.url);
                }
            }

            DownloadHandlerBuffer handler = new DownloadHandlerBuffer();

            webRequest.downloadHandler = handler;

            // We need to asset that we actually succeeded in setting the download handler, because this can fail
            // if, for example, the creation callback mistakenly called Send().
            PolyUtils.AssertTrue(webRequest.downloadHandler == handler,
                                 "Couldn't set download handler. It's either disposed of, or the creation callback mistakenly called Send().");

            // Start the web request. This will suspend this coroutine until the request is done.
            PtDebug.LogVerboseFormat("Sending web request: {0}", webRequest.url);
            yield return(UnityCompat.SendWebRequest(webRequest));

            // Request is finished. Call user-supplied callback.
            PtDebug.LogVerboseFormat("Web request finished: {0}, HTTP response code {1}, response: {2}",
                                     webRequest.url, webRequest.responseCode, webRequest.downloadHandler.text);
            PolyStatus status = UnityCompat.IsNetworkError(webRequest) ? PolyStatus.Error(webRequest.error) : PolyStatus.Success();

            request.completionCallback(status, (int)webRequest.responseCode, webRequest.downloadHandler.data);

            // Cache the result, if applicable.
            if (!UnityCompat.IsNetworkError(webRequest) && cacheAllowed)
            {
                byte[] data = webRequest.downloadHandler.data;
                if (data != null && data.Length > 0)
                {
                    byte[] copy = new byte[data.Length];
                    Buffer.BlockCopy(data, 0, copy, 0, data.Length);
                    cache.RequestWrite(webRequest.url, copy);
                }
            }

            // Clean up.
            webRequest.Dispose();
            CleanUpAfterWebRequest(bufferHolder);
        }