Beispiel #1
0
        public AssetStoreDownloadOperation(AssetStoreUtils assetStoreUtils, AssetStoreRestAPI assetStoreRestAPI, AssetStoreCachePathProxy assetStoreCachePathProxy, string productId, string oldPath)
        {
            ResolveDependencies(assetStoreUtils, assetStoreRestAPI, assetStoreCachePathProxy);

            m_ProductId      = productId;
            m_ProductOldPath = oldPath;
        }
Beispiel #2
0
 public void ResolveDependencies(AssetStoreUtils assetStoreUtils,
                                 AssetStoreRestAPI assetStoreRestAPI,
                                 AssetStoreCachePathProxy assetStoreCachePathProxy)
 {
     m_AssetStoreUtils          = assetStoreUtils;
     m_AssetStoreRestAPI        = assetStoreRestAPI;
     m_AssetStoreCachePathProxy = assetStoreCachePathProxy;
 }
Beispiel #3
0
 public static AssetStoreProductInfo ParseProductInfo(AssetStoreUtils assetStoreUtils, string productId, IDictionary <string, object> productDetail)
 {
     if (string.IsNullOrEmpty(productId) || productDetail == null || !productDetail.Any())
     {
         return(null);
     }
     return(new AssetStoreProductInfo(assetStoreUtils, productId, productDetail));
 }
Beispiel #4
0
        public AssetStorePackage(AssetStoreUtils assetStoreUtils, IOProxy ioProxy, AssetStorePurchaseInfo purchaseInfo, AssetStoreProductInfo productInfo, AssetStoreLocalInfo localInfo = null)
        {
            ResolveDependencies(assetStoreUtils, ioProxy);

            m_Errors         = new List <UIError>();
            m_Progress       = PackageProgress.None;
            m_Type           = PackageType.AssetStore;
            m_Name           = string.Empty;
            m_ProductId      = productInfo?.id.ToString();
            m_Images         = productInfo?.images ?? new List <PackageImage>();
            m_Links          = productInfo?.links ?? new List <PackageLink>();
            m_VersionList    = new AssetStoreVersionList(assetStoreUtils, ioProxy);
            m_UpmVersionList = new UpmVersionList();
            m_AssetStoreLink = productInfo?.assetStoreLink.url;

            var firstPublishedDateString = productInfo?.firstPublishedDate ?? string.Empty;

            m_FirstPublishedDateTicks = !string.IsNullOrEmpty(firstPublishedDateString) ? DateTime.Parse(firstPublishedDateString).Ticks : 0;

            m_Labels             = purchaseInfo?.tags;
            m_PurchasedTimeTicks = !string.IsNullOrEmpty(purchaseInfo?.purchasedTime) ? DateTime.Parse(purchaseInfo?.purchasedTime).Ticks : 0;
            m_IsHidden           = purchaseInfo?.isHidden == true;

            if (string.IsNullOrEmpty(productInfo?.id) || string.IsNullOrEmpty(productInfo?.versionId))
            {
                AddError(new UIError(UIErrorCode.AssetStorePackageError, L10n.Tr("Invalid product details.")));
            }
            else
            {
                // The version we get from the product info the latest on the server
                // The version we get from the localInfo is the version publisher set when uploading the .unitypackage file
                // The publisher could update the version on the server but NOT upload a new .unitypackage file, that will
                // result in a case where localInfo and productInfo have different version numbers but no update is available
                // Because of this, we prefer showing version from the server (even when localInfo version is different)
                // and we only want to show the localInfo version when `localInfo.canUpdate` is set to true
                var latestVersion = new AssetStorePackageVersion(assetStoreUtils, ioProxy, productInfo);
                if (localInfo != null)
                {
                    if (localInfo.canUpdate)
                    {
                        m_VersionList.AddVersion(new AssetStorePackageVersion(assetStoreUtils, ioProxy, productInfo, localInfo));
                    }
                    else
                    {
                        latestVersion.SetLocalPath(localInfo.packagePath);
                        if (localInfo.canDowngrade)
                        {
                            var warningMessage = string.Format(k_IncompatibleWarningMessage, localInfo.supportedVersion);
                            AddError(new UIError(UIErrorCode.AssetStorePackageError, warningMessage, UIError.Attribute.IsWarning));
                        }
                    }
                }
                m_VersionList.AddVersion(latestVersion);
            }

            LinkPackageAndVersions();
        }
        public void ResolveDependencies(ApplicationProxy application, AssetStoreUtils assetStoreUtils, HttpClientFactory httpClientFactory, IOProxy systemIOProxy)
        {
            m_Application       = application;
            m_HttpClientFactory = httpClientFactory;
            m_IOProxy           = systemIOProxy;

            foreach (var productInfo in m_ProductInfos.Values)
            {
                productInfo.ResolveDependencies(assetStoreUtils);
            }
        }
Beispiel #6
0
 public void ResolveDependencies(AssetStoreUtils assetStoreUtils, IOProxy ioProxy)
 {
     if (m_Versions == null)
     {
         return;
     }
     foreach (var version in m_Versions)
     {
         version.ResolveDependencies(assetStoreUtils, ioProxy);
     }
 }
Beispiel #7
0
        private AssetStoreProductInfo(AssetStoreUtils assetStoreUtils, string productId, IDictionary <string, object> productDetail)
        {
            ResolveDependencies(assetStoreUtils);

            id          = productId;
            description = CleanUpHtml(productDetail.GetString("description")) ?? string.Empty;

            var publisher = productDetail.GetDictionary("productPublisher");

            if (publisher != null)
            {
                if (publisher.GetString("url") == "http://unity3d.com")
                {
                    author = "Unity Technologies Inc.";
                }
                else
                {
                    author = publisher.GetString("name") ?? L10n.Tr("Unknown publisher");
                }
                publisherId = publisher.GetString("externalRef") ?? string.Empty;
            }
            else
            {
                author      = string.Empty;
                publisherId = string.Empty;
            }

            packageName        = productDetail.GetString("packageName") ?? string.Empty;
            category           = productDetail.GetDictionary("category")?.GetString("name") ?? string.Empty;
            publishNotes       = CleanUpHtml(productDetail.GetString("publishNotes") ?? string.Empty, false);
            firstPublishedDate = productDetail.GetDictionary("properties")?.GetString("firstPublishedDate");

            var versionInfo = productDetail.GetDictionary("version");

            if (versionInfo != null)
            {
                versionString = versionInfo.GetString("name");
                versionId     = versionInfo.GetString("id");
                publishedDate = versionInfo.GetString("publishedDate");
            }

            displayName = productDetail.GetString("displayName");

            supportedVersions = productDetail.GetList <string>("supportedUnityVersions")?.ToList();

            state = productDetail.GetString("state");

            images    = GetImagesFromProductDetails(productDetail);
            links     = GetLinksFromProductDetails(productDetail);
            sizeInfos = GetSizeInfoFromProductDetails(productDetail);

            assetStoreLink = GetAssetStoreLinkFromProductDetails(productDetail);
        }
Beispiel #8
0
        private void GetUserInfo(Action <UserInfo> doneCallback)
        {
            GetTokenInfo(tokenInfo =>
            {
                if (m_UserInfo?.isValid ?? false)
                {
                    doneCallback?.Invoke(m_UserInfo);
                    m_OnError = null;
                    return;
                }

                m_OnUserInfoFetched += doneCallback;

                if (m_UserInfoRequest != null)
                {
                    return;
                }

                m_UserInfoRequest = m_HttpClientFactory.GetASyncHTTPClient($"{host}{k_UserInfoUri}/{tokenInfo.sub}");
                m_UserInfoRequest.header["Authorization"] = "Bearer " + tokenInfo.accessToken;
                m_UserInfoRequest.doneCallback            = httpClient =>
                {
                    m_UserInfoRequest = null;
                    m_UserInfo        = null;

                    var response = AssetStoreUtils.ParseResponseAsDictionary(httpClient);
                    if (response != null)
                    {
                        if (response.ContainsKey("errorMessage"))
                        {
                            OnOperationError(string.Format(L10n.Tr("Error while getting user info: {0}"), response.GetString("errorMessage")));
                            return;
                        }

                        var userInfo = new UserInfo(response, tokenInfo);
                        if (userInfo.isValid)
                        {
                            m_UserInfo = userInfo;
                            m_OnUserInfoFetched?.Invoke(m_UserInfo);
                            m_OnUserInfoFetched = null;
                            // note that we only clear error callbacks on the when user info is fetched
                            // as we need the error callback to be present for the whole process.
                            m_OnError = null;
                        }
                        else
                        {
                            OnOperationError(L10n.Tr("User info invalid"));
                        }
                    }
                };
                m_UserInfoRequest.Begin();
            });
        }
Beispiel #9
0
        private void GetTokenInfo(Action <TokenInfo> doneCallback)
        {
            GetAccessToken(accessToken =>
            {
                if (m_TokenInfo?.IsValid() ?? false)
                {
                    doneCallback?.Invoke(m_TokenInfo);
                    return;
                }

                m_OnTokenInfoFetched += doneCallback;

                if (m_TokenRequest != null)
                {
                    return;
                }

                m_TokenRequest = m_HttpClientFactory.GetASyncHTTPClient($"{host}{k_TokenInfoUri}?access_token={accessToken.accessToken}");
                m_TokenRequest.doneCallback = httpClient =>
                {
                    m_TokenRequest = null;
                    m_TokenInfo    = null;

                    var response = AssetStoreUtils.ParseResponseAsDictionary(httpClient);
                    if (response != null)
                    {
                        if (response.ContainsKey("errorMessage"))
                        {
                            OnOperationError(string.Format(L10n.Tr("Error while getting token info: {0}"), response.GetString("errorMessage")));
                            return;
                        }

                        var tokenInfo = new TokenInfo(response);
                        if (tokenInfo.IsValid())
                        {
                            m_TokenInfo = tokenInfo;
                            m_OnTokenInfoFetched?.Invoke(m_TokenInfo);
                            m_OnTokenInfoFetched = null;
                        }
                        else
                        {
                            OnOperationError(L10n.Tr("Token info invalid"));
                        }
                    }
                };
                m_TokenRequest.Begin();
            });
        }
Beispiel #10
0
        public AssetStorePackage(AssetStoreUtils assetStoreUtils, IOProxy ioProxy, AssetStorePurchaseInfo purchaseInfo, AssetStoreProductInfo productInfo, UpmPackage package)
        {
            ResolveDependencies(assetStoreUtils, ioProxy);

            m_Errors    = new List <UIError>();
            m_Progress  = PackageProgress.None;
            m_Type      = PackageType.AssetStore;
            m_Name      = package?.name ?? string.Empty;
            m_ProductId = productInfo?.id.ToString();

            m_Images      = productInfo?.images ?? new List <PackageImage>();
            m_Links       = productInfo?.links ?? new List <PackageLink>();
            m_VersionList = new AssetStoreVersionList(assetStoreUtils, ioProxy);

            m_Labels             = purchaseInfo?.tags;
            m_IsHidden           = purchaseInfo?.isHidden == true;
            m_PurchasedTimeTicks = !string.IsNullOrEmpty(purchaseInfo?.purchasedTime) ? DateTime.Parse(purchaseInfo?.purchasedTime).Ticks : 0;

            m_UpmVersionList = package?.versions as UpmVersionList ?? new UpmVersionList();
            if (productInfo != null)
            {
                foreach (var version in m_UpmVersionList.Cast <UpmPackageVersion>())
                {
                    version.UpdateProductInfo(productInfo);
                }
            }

            m_AssetStoreLink = productInfo?.assetStoreLink.url;

            var firstPublishedDateString = productInfo?.firstPublishedDate ?? string.Empty;

            m_FirstPublishedDateTicks = !string.IsNullOrEmpty(firstPublishedDateString) ? DateTime.Parse(firstPublishedDateString).Ticks : 0;

            if (purchaseInfo == null)
            {
                AddError(new UIError(UIErrorCode.AssetStorePackageError, L10n.Tr("Unable to get asset purchase details because you may not have purchased this package.")));
            }
            if (string.IsNullOrEmpty(productInfo?.id) || string.IsNullOrEmpty(productInfo?.versionId))
            {
                AddError(new UIError(UIErrorCode.AssetStorePackageError, L10n.Tr("Unable to retrieve asset product details.")));
            }
            else if (string.IsNullOrEmpty(package?.name))
            {
                AddError(new UIError(UIErrorCode.AssetStorePackageError, L10n.Tr("Unable to retrieve asset package info.")));
            }

            LinkPackageAndVersions();
        }
Beispiel #11
0
        public void ResolveDependencies(UnityConnectProxy unityConnect,
                                        AssetStoreCache assetStoreCache,
                                        AssetStoreUtils assetStoreUtils,
                                        AssetStoreRestAPI assetStoreRestAPI,
                                        UpmClient upmClient,
                                        IOProxy ioProxy)
        {
            m_UnityConnect      = unityConnect;
            m_AssetStoreCache   = assetStoreCache;
            m_AssetStoreUtils   = assetStoreUtils;
            m_AssetStoreRestAPI = assetStoreRestAPI;
            m_UpmClient         = upmClient;
            m_IOProxy           = ioProxy;

            m_ListOperation?.ResolveDependencies(unityConnect, assetStoreRestAPI, assetStoreCache);
        }
        public ServicesContainer()
        {
            // In the constructor we only need to worry about creating a brand new instance.
            // In the case of assembly reload, a deserialize step will automatically happen after the constructor
            // to restore all the serializable states/services and we don't need to worry about that
            m_HttpClientFactory    = new HttpClientFactory();
            m_UnityOAuthProxy      = new UnityOAuthProxy();
            m_SelectionProxy       = new SelectionProxy();
            m_AssetDatabaseProxy   = new AssetDatabaseProxy();
            m_UnityConnectProxy    = new UnityConnectProxy();
            m_ApplicationProxy     = new ApplicationProxy();
            m_EditorAnalyticsProxy = new EditorAnalyticsProxy();
            m_IOProxy       = new IOProxy();
            m_SettingsProxy = new PackageManagerProjectSettingsProxy();
            m_ClientProxy   = new ClientProxy();

            m_ResourceLoader   = new ResourceLoader();
            m_ExtensionManager = new ExtensionManager();

            m_AssetStoreCache           = new AssetStoreCache();
            m_AssetStoreClient          = new AssetStoreClient();
            m_AssetStoreOAuth           = new AssetStoreOAuth();
            m_AssetStoreUtils           = new AssetStoreUtils();
            m_AssetStoreRestAPI         = new AssetStoreRestAPI();
            m_AssetStoreDownloadManager = new AssetStoreDownloadManager();
            m_AssetStoreCallQueue       = new AssetStoreCallQueue();
            m_AssetStoreCachePathProxy  = new AssetStoreCachePathProxy();

            m_UpmCache           = new UpmCache();
            m_UpmClient          = new UpmClient();
            m_UpmRegistryClient  = new UpmRegistryClient();
            m_UpmCacheRootClient = new UpmCacheRootClient();

            m_PackageFiltering    = new PackageFiltering();
            m_PackageManagerPrefs = new PackageManagerPrefs();

            m_PackageDatabase = new PackageDatabase();
            m_PageManager     = new PageManager();

            // Since dictionaries doesn't survive through serialization, we always re-create the default registration
            m_RegisteredObjects = new Dictionary <Type, object>();
            RegisterDefaultServices();

            m_DependenciesResolved = false;
            m_InitializeState      = State.NotInitialized;
        }
Beispiel #13
0
        public AssetStorePackage(AssetStoreUtils assetStoreUtils, IOProxy ioProxy, string productId, UIError error)
        {
            ResolveDependencies(assetStoreUtils, ioProxy);

            m_Errors = new List <UIError> {
                error
            };
            m_Progress  = PackageProgress.None;
            m_Type      = PackageType.AssetStore;
            m_Name      = string.Empty;
            m_ProductId = productId;

            m_Images         = new List <PackageImage>();
            m_Links          = new List <PackageLink>();
            m_VersionList    = new AssetStoreVersionList(assetStoreUtils, ioProxy);
            m_UpmVersionList = new UpmVersionList();

            m_Labels             = new List <string>();
            m_PurchasedTimeTicks = 0;

            LinkPackageAndVersions();
        }
Beispiel #14
0
        public void ResolveDependencies(ApplicationProxy application,
                                        HttpClientFactory httpClientFactory,
                                        UnityConnectProxy unityConnect,
                                        IOProxy ioProxy,
                                        AssetStoreCache assetStoreCache,
                                        AssetStoreUtils assetStoreUtils,
                                        AssetStoreRestAPI assetStoreRestAPI,
                                        AssetStoreCachePathProxy assetStoreCachePathProxy)
        {
            m_Application              = application;
            m_UnityConnect             = unityConnect;
            m_IOProxy                  = ioProxy;
            m_HttpClientFactory        = httpClientFactory;
            m_AssetStoreCache          = assetStoreCache;
            m_AssetStoreUtils          = assetStoreUtils;
            m_AssetStoreRestAPI        = assetStoreRestAPI;
            m_AssetStoreCachePathProxy = assetStoreCachePathProxy;

            foreach (var operation in m_DownloadOperations.Values)
            {
                operation.ResolveDependencies(assetStoreUtils, assetStoreRestAPI, m_AssetStoreCachePathProxy);
            }
        }
Beispiel #15
0
        public AssetStoreVersionList(AssetStoreUtils assetStoreUtils, IOProxy ioProxy)
        {
            ResolveDependencies(assetStoreUtils, ioProxy);

            m_Versions = new List <AssetStorePackageVersion>();
        }
Beispiel #16
0
 public void ResolveDependencies(AssetStoreUtils assetStoreUtils, IOProxy ioProxy)
 {
     m_VersionList?.ResolveDependencies(assetStoreUtils, ioProxy);
 }
Beispiel #17
0
 public void ResolveDependencies(AssetStoreUtils assetStoreUtils, IOProxy ioProxy)
 {
     m_AssetStoreUtils = assetStoreUtils;
     m_IOProxy         = ioProxy;
 }
Beispiel #18
0
        public AssetStorePackageVersion(AssetStoreUtils assetStoreUtils, IOProxy ioProxy, AssetStoreProductInfo productInfo, AssetStoreLocalInfo localInfo = null)
        {
            if (productInfo == null)
            {
                throw new ArgumentNullException(nameof(productInfo));
            }

            ResolveDependencies(assetStoreUtils, ioProxy);

            m_Errors          = new List <UIError>();
            m_Tag             = PackageTag.Downloadable | PackageTag.Importable;
            m_PackageUniqueId = productInfo.id;

            m_Description = productInfo.description;
            m_Author      = productInfo.author;
            m_PublisherId = productInfo.publisherId;

            m_Category = productInfo.category;

            m_PublishNotes = localInfo?.publishNotes ?? productInfo.publishNotes ?? string.Empty;

            m_VersionString = localInfo?.versionString ?? productInfo.versionString ?? string.Empty;
            m_VersionId     = localInfo?.versionId ?? productInfo.versionId ?? string.Empty;
            SemVersionParser.TryParse(m_VersionString.Trim(), out m_Version);

            var publishDateString = localInfo?.publishedDate ?? productInfo.publishedDate ?? string.Empty;

            m_PublishedDateTicks = !string.IsNullOrEmpty(publishDateString) ? DateTime.Parse(publishDateString).Ticks : 0;
            m_DisplayName        = !string.IsNullOrEmpty(productInfo.displayName) ? productInfo.displayName : $"Package {m_PackageUniqueId}@{m_VersionId}";

            m_SupportedUnityVersions = new List <SemVersion>();
            if (localInfo != null)
            {
                var simpleVersion = Regex.Replace(localInfo.supportedVersion, @"(?<major>\d+)\.(?<minor>\d+).(?<patch>\d+)[abfp].+", "${major}.${minor}.${patch}");
                SemVersionParser.TryParse(simpleVersion.Trim(), out m_SupportedUnityVersion);
                m_SupportedUnityVersionString = m_SupportedUnityVersion?.ToString();
            }
            else if (productInfo.supportedVersions?.Any() ?? false)
            {
                foreach (var supportedVersion in productInfo.supportedVersions)
                {
                    SemVersion?version;
                    bool       isVersionParsed = SemVersionParser.TryParse(supportedVersion, out version);

                    if (isVersionParsed)
                    {
                        m_SupportedUnityVersions.Add((SemVersion)version);
                    }
                }

                m_SupportedUnityVersions.Sort((left, right) => (left).CompareTo(right));
                m_SupportedUnityVersion       = m_SupportedUnityVersions.LastOrDefault();
                m_SupportedUnityVersionString = m_SupportedUnityVersion?.ToString();
            }

            m_SizeInfos = new List <PackageSizeInfo>(productInfo.sizeInfos);
            m_SizeInfos.Sort((left, right) => left.supportedUnityVersion.CompareTo(right.supportedUnityVersion));

            var state = productInfo.state ?? string.Empty;

            if (state.Equals("published", StringComparison.InvariantCultureIgnoreCase))
            {
                m_Tag |= PackageTag.Published;
            }
            else if (state.Equals("deprecated", StringComparison.InvariantCultureIgnoreCase))
            {
                m_Tag |= PackageTag.Deprecated;
            }
            else if (state.Equals("disabled", StringComparison.InvariantCultureIgnoreCase))
            {
                m_Tag |= PackageTag.Disabled;
            }

            SetLocalPath(localInfo?.packagePath);
        }
Beispiel #19
0
        private void HandleHttpRequest(Func <IAsyncHTTPClient> httpRequestCreate, Action <Dictionary <string, object> > doneCallbackAction, Action <UIError> errorCallbackAction)
        {
            m_AssetStoreOAuth.FetchUserInfo(
                userInfo =>
            {
                var maxRetryCount = k_MaxRetries;

                void DoHttpRequest(Action <int> retryCallbackAction)
                {
                    var httpRequest = httpRequestCreate();

                    httpRequest.header["Content-Type"]  = "application/json";
                    httpRequest.header["Authorization"] = "Bearer " + userInfo.accessToken;
                    httpRequest.doneCallback            = request =>
                    {
                        // Ignore if aborted
                        if (request.IsAborted())
                        {
                            return;
                        }

                        var responseCode = request.responseCode;
                        if (responseCode == 0)
                        {
                            errorCallbackAction?.Invoke(new UIError(UIErrorCode.AssetStoreRestApiError, k_ErrorMessage, responseCode));
                            return;
                        }

                        if (responseCode >= k_ServerErrorResponseCode)
                        {
                            retryCallbackAction?.Invoke(responseCode);
                            return;
                        }

                        if (responseCode >= k_ClientErrorResponseCode && responseCode < k_ServerErrorResponseCode)
                        {
                            var errorMessage = k_KnownErrors[k_GeneralClientError];
                            k_KnownErrors.TryGetValue(request.responseCode, out errorMessage);
                            errorCallbackAction?.Invoke(new UIError(UIErrorCode.AssetStoreRestApiError, $"{responseCode} {errorMessage}. {k_ErrorMessage}", responseCode));
                            return;
                        }

                        var parsedResult = AssetStoreUtils.ParseResponseAsDictionary(request);
                        if (parsedResult == null)
                        {
                            retryCallbackAction?.Invoke(responseCode);
                        }
                        else
                        {
                            if (parsedResult.ContainsKey("errorMessage"))
                            {
                                var operationErrorCode = parsedResult.ContainsKey("errorCode") ? int.Parse(parsedResult.GetString("errorCode")) : -1;
                                errorCallbackAction?.Invoke(new UIError(UIErrorCode.AssetStoreRestApiError, parsedResult.GetString("errorMessage"), operationErrorCode));
                            }
                            else
                            {
                                doneCallbackAction?.Invoke(parsedResult);
                            }
                        }
                    };

                    httpRequest.Begin();
                }

                void RetryCallbackAction(int lastResponseCode)
                {
                    maxRetryCount--;
                    if (maxRetryCount > 0)
                    {
                        DoHttpRequest(RetryCallbackAction);
                    }
                    else
                    {
                        if (lastResponseCode >= k_ServerErrorResponseCode)
                        {
                            var errorMessage = k_KnownErrors[k_GeneralServerError];
                            k_KnownErrors.TryGetValue(lastResponseCode, out errorMessage);
                            errorCallbackAction?.Invoke(new UIError(UIErrorCode.AssetStoreRestApiError, $"{lastResponseCode} {errorMessage}. {k_ErrorMessage}", lastResponseCode));
                        }
                        else
                        {
                            errorCallbackAction?.Invoke(new UIError(UIErrorCode.AssetStoreRestApiError, k_ErrorMessage, lastResponseCode));
                        }
                    }
                }

                DoHttpRequest(RetryCallbackAction);
            },
                errorCallbackAction);
        }
Beispiel #20
0
 public void ResolveDependencies(AssetStoreUtils assetStoreUtils)
 {
     m_AssetStoreUtils = assetStoreUtils;
 }
Beispiel #21
0
        private void GetAccessToken(Action <AccessToken> doneCallback, string authCode = null, string refreshToken = null)
        {
            m_OnAccessTokenFetched += doneCallback;

            if (m_AccessTokenRequest != null)
            {
                return;
            }

            if (string.IsNullOrEmpty(secret))
            {
                OnGetAccessTokenError(L10n.Tr("Error while getting access token: invalid configuration from Unity Connect"));
                return;
            }

            var authorization = string.Empty;

            if (!string.IsNullOrEmpty(authCode))
            {
                authorization = $"grant_type=authorization_code&code={authCode}";
            }
            else if (!string.IsNullOrEmpty(refreshToken))
            {
                authorization = $"grant_type=refresh_token&refresh_token={refreshToken}";
            }
            else
            {
                return;
            }

            m_AccessTokenRequest = m_HttpClientFactory.PostASyncHTTPClient($"{host}{k_OAuthUri}", $"{authorization}&client_id={k_ServiceId}&client_secret={secret}");
            m_AccessTokenRequest.header["Content-Type"] = "application/x-www-form-urlencoded";
            m_AccessTokenRequest.doneCallback           = httpClient =>
            {
                m_AccessTokenRequest = null;
                m_AccessToken        = null;

                var response = AssetStoreUtils.ParseResponseAsDictionary(httpClient);
                if (response != null)
                {
                    if (response.ContainsKey("errorMessage"))
                    {
                        OnGetAccessTokenError(string.Format(L10n.Tr("Error while getting access token: {0}"), response.GetString("errorMessage")));
                        return;
                    }

                    var accessToken = new AccessToken(response);
                    if (accessToken.IsValid())
                    {
                        m_AccessToken = accessToken;
                        m_OnAccessTokenFetched?.Invoke(m_AccessToken);
                        m_OnAccessTokenFetched = null;
                    }
                    else
                    {
                        OnGetAccessTokenError(L10n.Tr("Access token invalid"));
                    }
                }
            };
            m_AccessTokenRequest.Begin();
        }