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(); } }
/// <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); }