update libs

This commit is contained in:
Kirill Chikalin
2025-02-13 17:48:12 +03:00
parent e17e7c2786
commit 275dc598c7
816 changed files with 22479 additions and 10792 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25799fb31cd475347af7f5442c231797
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
using AssetStoreTools.Api.Responses;
using AssetStoreTools.Utility;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace AssetStoreTools.Api
{
internal abstract class AuthenticationBase : IAuthenticationType
{
protected Uri LoginUrl = ApiUtility.CreateUri(Constants.Api.AuthenticateUrl, true);
protected FormUrlEncodedContent AuthenticationContent;
protected FormUrlEncodedContent GetAuthenticationContent(params KeyValuePair<string, string>[] content)
{
var baseContent = Constants.Api.DefaultAssetStoreQuery();
try { baseContent.Add("license_hash", ApiUtility.GetLicenseHash()); } catch { ASDebug.LogWarning("Could not retrieve license hash"); }
try { baseContent.Add("hardware_hash", ApiUtility.GetHardwareHash()); } catch { ASDebug.LogWarning("Could not retrieve hardware hash"); }
foreach (var extraContent in content)
{
baseContent.Add(extraContent.Key, extraContent.Value);
}
return new FormUrlEncodedContent(baseContent);
}
protected AuthenticationResponse ParseResponse(HttpResponseMessage response)
{
try
{
response.EnsureSuccessStatusCode();
var responseString = response.Content.ReadAsStringAsync().Result;
return new AuthenticationResponse(responseString);
}
catch (HttpRequestException e)
{
return new AuthenticationResponse(response.StatusCode, e) { Success = false };
}
}
public abstract Task<AuthenticationResponse> Authenticate(IAssetStoreClient client, CancellationToken cancellationToken = default);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f677e03f1be1048439a1fa5e7a0a37b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Abstractions/AuthenticationBase.cs
uploadId: 724584

View File

@@ -0,0 +1,21 @@
using AssetStoreTools.Api.Models;
using AssetStoreTools.Api.Responses;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal interface IAssetStoreApi
{
Task<AssetStoreToolsVersionResponse> GetLatestAssetStoreToolsVersion(CancellationToken cancellationToken = default);
Task<AuthenticationResponse> Authenticate(IAuthenticationType authenticationType, CancellationToken cancellationToken = default);
void Deauthenticate();
Task<PackagesDataResponse> GetPackages(CancellationToken cancellationToken = default);
Task<CategoryDataResponse> GetCategories(CancellationToken cancellationToken = default);
Task<PackageThumbnailResponse> GetPackageThumbnail(Package package, CancellationToken cancellationToken = default);
Task<RefreshedPackageDataResponse> RefreshPackageMetadata(Package package, CancellationToken cancellationToken = default);
Task<PackageUploadedUnityVersionDataResponse> GetPackageUploadedVersions(Package package, CancellationToken cancellationToken = default);
Task<PackageUploadResponse> UploadPackage(IPackageUploader uploader, IProgress<float> progress = null, CancellationToken cancellationToken = default);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: e616488c25d278741bb0d08168219309
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Abstractions/IAssetStoreApi.cs
uploadId: 724584

View File

@@ -0,0 +1,18 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal interface IAssetStoreClient
{
void SetSessionId(string sessionId);
void ClearSessionId();
Task<HttpResponseMessage> Get(Uri uri, CancellationToken cancellationToken = default);
Task<HttpResponseMessage> Post(Uri uri, HttpContent content, CancellationToken cancellationToken = default);
Task<HttpResponseMessage> Put(Uri uri, HttpContent content, CancellationToken cancellationToken = default);
Task<HttpResponseMessage> Send(HttpRequestMessage request, CancellationToken cancellationToken = default);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: b2bbadec62178cc4189e605367b219e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Abstractions/IAssetStoreClient.cs
uploadId: 724584

View File

@@ -0,0 +1,11 @@
using AssetStoreTools.Api.Responses;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal interface IAuthenticationType
{
Task<AuthenticationResponse> Authenticate(IAssetStoreClient client, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0000dcd6975bc8e4abc546a19f194040
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Abstractions/IAuthenticationType.cs
uploadId: 724584

View File

@@ -0,0 +1,12 @@
using AssetStoreTools.Api.Responses;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal interface IPackageUploader
{
Task<PackageUploadResponse> Upload(IAssetStoreClient client, IProgress<float> progress, CancellationToken cancellationToken = default);
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0fc6c47b1c0a65540a40efbf1491193b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Abstractions/IPackageUploader.cs
uploadId: 724584

View File

@@ -0,0 +1,59 @@
using AssetStoreTools.Api.Responses;
using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal abstract class PackageUploaderBase : IPackageUploader
{
protected const int UploadChunkSizeBytes = 32768;
protected const int UploadResponseTimeoutMs = 10000;
protected abstract void ValidateSettings();
public abstract Task<PackageUploadResponse> Upload(IAssetStoreClient client, IProgress<float> progress = null, CancellationToken cancellationToken = default);
protected void EnsureSuccessResponse(HttpResponseMessage response)
{
try
{
response.EnsureSuccessStatusCode();
}
catch
{
throw new Exception(response.Content.ReadAsStringAsync().Result);
}
}
protected void WaitForUploadCompletion(Task<HttpResponseMessage> response, FileStream requestFileStream, IProgress<float> progress, CancellationToken cancellationToken)
{
// Progress tracking
int updateIntervalMs = 100;
bool allBytesSent = false;
DateTime timeOfCompletion = default;
while (!response.IsCompleted)
{
float uploadProgress = (float)requestFileStream.Position / requestFileStream.Length * 100;
progress?.Report(uploadProgress);
Thread.Sleep(updateIntervalMs);
// A timeout for rare cases, when package uploading reaches 100%, but Put task IsComplete value remains 'False'
if (requestFileStream.Position == requestFileStream.Length)
{
if (!allBytesSent)
{
allBytesSent = true;
timeOfCompletion = DateTime.UtcNow;
}
else if (DateTime.UtcNow.Subtract(timeOfCompletion).TotalMilliseconds > UploadResponseTimeoutMs)
{
throw new TimeoutException();
}
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2718ddd16e425ba4a82ab973724bcff7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Abstractions/PackageUploaderBase.cs
uploadId: 724584

View File

@@ -0,0 +1,76 @@
using AssetStoreTools.Api.Models;
using AssetStoreTools.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditorInternal;
namespace AssetStoreTools.Api
{
internal class ApiUtility
{
public static Uri CreateUri(string url, bool includeDefaultAssetStoreQuery) => CreateUri(url, null, includeDefaultAssetStoreQuery);
public static Uri CreateUri(string url, IDictionary<string, string> queryParameters, bool includeDefaultAssetStoreQuery)
{
IDictionary<string, string> fullQueryParameters = includeDefaultAssetStoreQuery ?
Constants.Api.DefaultAssetStoreQuery() : new Dictionary<string, string>();
if (queryParameters != null && queryParameters.Count > 0)
{
foreach (var kvp in queryParameters)
fullQueryParameters.Add(kvp);
}
var builder = new UriBuilder(url);
if (fullQueryParameters.Count == 0)
return builder.Uri;
var fullQueryParameterString = string.Empty;
foreach (var queryParam in fullQueryParameters)
{
var escapedValue = queryParam.Value != null ? Uri.EscapeDataString(queryParam.Value) : string.Empty;
fullQueryParameterString += $"{queryParam.Key}={escapedValue}&";
}
fullQueryParameterString = fullQueryParameterString.Remove(fullQueryParameterString.Length - 1);
builder.Query = fullQueryParameterString;
return builder.Uri;
}
public static List<Package> CombinePackageData(List<Package> mainPackageData, List<PackageAdditionalData> extraPackageData, List<Category> categoryData)
{
foreach (var package in mainPackageData)
{
var extraData = extraPackageData.FirstOrDefault(x => package.PackageId == x.PackageId);
if (extraData == null)
{
ASDebug.LogWarning($"Could not find extra data for Package {package.PackageId}");
continue;
}
var categoryId = extraData.CategoryId;
var category = categoryData.FirstOrDefault(x => x.Id.ToString() == categoryId);
if (category != null)
package.Category = category.Name;
else
package.Category = "Unknown";
package.Modified = extraData.Modified;
package.Size = extraData.Size;
}
return mainPackageData;
}
public static string GetLicenseHash()
{
return InternalEditorUtility.GetAuthToken().Substring(0, 40);
}
public static string GetHardwareHash()
{
return InternalEditorUtility.GetAuthToken().Substring(40, 40);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5becec0b3c0ba274fb0b01544e63b6c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/ApiUtility.cs
uploadId: 724584

View File

@@ -0,0 +1,268 @@
using AssetStoreTools.Api.Models;
using AssetStoreTools.Api.Responses;
using Newtonsoft.Json.Linq;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal class AssetStoreApi : IAssetStoreApi
{
private IAssetStoreClient _client;
public AssetStoreApi(IAssetStoreClient client)
{
_client = client;
}
public async Task<AssetStoreToolsVersionResponse> GetLatestAssetStoreToolsVersion(CancellationToken cancellationToken = default)
{
try
{
var uri = ApiUtility.CreateUri(Constants.Api.AssetStoreToolsLatestVersionUrl, false);
var response = await _client.Get(uri, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
response.EnsureSuccessStatusCode();
var responseStr = response.Content.ReadAsStringAsync().Result;
return new AssetStoreToolsVersionResponse(responseStr);
}
catch (OperationCanceledException e)
{
return new AssetStoreToolsVersionResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new AssetStoreToolsVersionResponse() { Success = false, Exception = e };
}
}
public async Task<AuthenticationResponse> Authenticate(IAuthenticationType authenticationType, CancellationToken cancellationToken = default)
{
try
{
var loginResponse = await authenticationType.Authenticate(_client, cancellationToken);
if (loginResponse.Success)
{
_client.SetSessionId(loginResponse.User.SessionId);
}
return loginResponse;
}
catch (OperationCanceledException e)
{
return new AuthenticationResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new AuthenticationResponse() { Success = false, Exception = e };
}
}
public void Deauthenticate()
{
_client.ClearSessionId();
}
public async Task<PackagesDataResponse> GetPackages(CancellationToken cancellationToken = default)
{
try
{
var mainDataResponse = await GetPackageDataMain(cancellationToken);
if (!mainDataResponse.Success)
throw mainDataResponse.Exception;
var additionalDataResponse = await GetPackageDataExtra(cancellationToken);
if (!additionalDataResponse.Success)
throw additionalDataResponse.Exception;
var categoryDataResponse = await GetCategories(cancellationToken);
if (!categoryDataResponse.Success)
throw categoryDataResponse.Exception;
var joinedData = ApiUtility.CombinePackageData(mainDataResponse.Packages, additionalDataResponse.Packages, categoryDataResponse.Categories);
return new PackagesDataResponse() { Success = true, Packages = joinedData };
}
catch (OperationCanceledException e)
{
return new PackagesDataResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new PackagesDataResponse() { Success = false, Exception = e };
}
}
private async Task<PackagesDataResponse> GetPackageDataMain(CancellationToken cancellationToken)
{
try
{
var uri = ApiUtility.CreateUri(Constants.Api.GetPackagesUrl, true);
var response = await _client.Get(uri, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
response.EnsureSuccessStatusCode();
var responseStr = response.Content.ReadAsStringAsync().Result;
return new PackagesDataResponse(responseStr);
}
catch (OperationCanceledException e)
{
return new PackagesDataResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new PackagesDataResponse() { Success = false, Exception = e };
}
}
private async Task<PackagesAdditionalDataResponse> GetPackageDataExtra(CancellationToken cancellationToken)
{
try
{
var uri = ApiUtility.CreateUri(Constants.Api.GetPackagesAdditionalDataUrl, true);
var response = await _client.Get(uri, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
response.EnsureSuccessStatusCode();
var responseStr = response.Content.ReadAsStringAsync().Result;
return new PackagesAdditionalDataResponse(responseStr);
}
catch (OperationCanceledException e)
{
return new PackagesAdditionalDataResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new PackagesAdditionalDataResponse() { Success = false, Exception = e };
}
}
public async Task<CategoryDataResponse> GetCategories(CancellationToken cancellationToken)
{
try
{
var uri = ApiUtility.CreateUri(Constants.Api.GetCategoriesUrl, true);
var response = await _client.Get(uri, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
response.EnsureSuccessStatusCode();
var responseStr = response.Content.ReadAsStringAsync().Result;
return new CategoryDataResponse(responseStr);
}
catch (OperationCanceledException e)
{
return new CategoryDataResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new CategoryDataResponse() { Success = false, Exception = e };
}
}
public async Task<PackageThumbnailResponse> GetPackageThumbnail(Package package, CancellationToken cancellationToken = default)
{
try
{
if (string.IsNullOrEmpty(package.IconUrl))
throw new Exception($"Could not retrieve thumbnail for package {package.PackageId} - icon url is null");
var response = await _client.Get(new Uri(package.IconUrl), cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
response.EnsureSuccessStatusCode();
var responseBytes = response.Content.ReadAsByteArrayAsync().Result;
return new PackageThumbnailResponse(responseBytes);
}
catch (OperationCanceledException e)
{
return new PackageThumbnailResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new PackageThumbnailResponse() { Success = false, Exception = e };
}
}
public async Task<RefreshedPackageDataResponse> RefreshPackageMetadata(Package package, CancellationToken cancellationToken = default)
{
try
{
var refreshedPackage = JObject.FromObject(package).DeepClone().ToObject<Package>();
var packagesResponse = await GetPackageDataExtra(cancellationToken);
if (!packagesResponse.Success)
throw packagesResponse.Exception;
// Find the updated package data in the latest data json
var packageRefreshSource = packagesResponse.Packages.FirstOrDefault(x => x.PackageId == refreshedPackage.PackageId);
if (packageRefreshSource == null)
return new RefreshedPackageDataResponse() { Success = false, Exception = new MissingMemberException($"Unable to find downloaded package data for package id {package.PackageId}") };
// Retrieve the category map
var categoryData = await GetCategories(cancellationToken);
if (!categoryData.Success)
return new RefreshedPackageDataResponse() { Success = false, Exception = packagesResponse.Exception };
// Update the package data
refreshedPackage.Name = packageRefreshSource.Name;
refreshedPackage.Status = packageRefreshSource.Status;
var newCategory = categoryData.Categories.FirstOrDefault(x => x.Id.ToString() == packageRefreshSource.CategoryId);
refreshedPackage.Category = newCategory != null ? newCategory.Name : "Unknown";
refreshedPackage.Modified = packageRefreshSource.Modified;
refreshedPackage.Size = packageRefreshSource.Size;
return new RefreshedPackageDataResponse() { Success = true, Package = refreshedPackage };
}
catch (OperationCanceledException)
{
return new RefreshedPackageDataResponse() { Success = false, Cancelled = true };
}
catch (Exception e)
{
return new RefreshedPackageDataResponse() { Success = false, Exception = e };
}
}
public async Task<PackageUploadedUnityVersionDataResponse> GetPackageUploadedVersions(Package package, CancellationToken cancellationToken = default)
{
try
{
var uri = ApiUtility.CreateUri(Constants.Api.GetPackageUploadedVersionsUrl(package.PackageId, package.VersionId), true);
var response = await _client.Get(uri, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
response.EnsureSuccessStatusCode();
var responseStr = response.Content.ReadAsStringAsync().Result;
return new PackageUploadedUnityVersionDataResponse(responseStr);
}
catch (OperationCanceledException e)
{
return new PackageUploadedUnityVersionDataResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new PackageUploadedUnityVersionDataResponse() { Success = false, Exception = e };
}
}
public async Task<PackageUploadResponse> UploadPackage(IPackageUploader uploader, IProgress<float> progress = null, CancellationToken cancellationToken = default)
{
try
{
return await uploader.Upload(_client, progress, cancellationToken);
}
catch (OperationCanceledException e)
{
return new PackageUploadResponse() { Success = false, Cancelled = true, Exception = e };
}
catch (Exception e)
{
return new PackageUploadResponse() { Success = false, Exception = e };
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 684fca3fffd79d944a32d9b3adbfc007
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/AssetStoreApi.cs
uploadId: 724584

View File

@@ -0,0 +1,55 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal class AssetStoreClient : IAssetStoreClient
{
private HttpClient _httpClient;
public AssetStoreClient()
{
ServicePointManager.DefaultConnectionLimit = 500;
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.ConnectionClose = false;
_httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
_httpClient.Timeout = TimeSpan.FromMinutes(1320);
}
public void SetSessionId(string sessionId)
{
ClearSessionId();
if (!string.IsNullOrEmpty(sessionId))
_httpClient.DefaultRequestHeaders.Add("X-Unity-Session", sessionId);
}
public void ClearSessionId()
{
_httpClient.DefaultRequestHeaders.Remove("X-Unity-Session");
}
public Task<HttpResponseMessage> Get(Uri uri, CancellationToken cancellationToken = default)
{
return _httpClient.GetAsync(uri, cancellationToken);
}
public Task<HttpResponseMessage> Post(Uri uri, HttpContent content, CancellationToken cancellationToken = default)
{
return _httpClient.PostAsync(uri, content, cancellationToken);
}
public Task<HttpResponseMessage> Put(Uri uri, HttpContent content, CancellationToken cancellationToken = default)
{
return _httpClient.PutAsync(uri, content, cancellationToken);
}
public Task<HttpResponseMessage> Send(HttpRequestMessage request, CancellationToken cancellationToken = default)
{
return _httpClient.SendAsync(request, cancellationToken);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 80b4527c908161a4b9f06dc393b502f9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/AssetStoreClient.cs
uploadId: 724584

View File

@@ -0,0 +1,25 @@
using AssetStoreTools.Api.Responses;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal class CloudTokenAuthentication : AuthenticationBase
{
public CloudTokenAuthentication(string cloudToken)
{
AuthenticationContent = GetAuthenticationContent(
new KeyValuePair<string, string>("user_access_token", cloudToken)
);
}
public override async Task<AuthenticationResponse> Authenticate(IAssetStoreClient client, CancellationToken cancellationToken)
{
var result = await client.Post(LoginUrl, AuthenticationContent, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
return ParseResponse(result);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 99f1baec74f26a34bb972b19c92d523f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/CloudTokenAuthentication.cs
uploadId: 724584

View File

@@ -0,0 +1,26 @@
using AssetStoreTools.Api.Responses;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal class CredentialsAuthentication : AuthenticationBase
{
public CredentialsAuthentication(string email, string password)
{
AuthenticationContent = GetAuthenticationContent(
new KeyValuePair<string, string>("user", email),
new KeyValuePair<string, string>("pass", password)
);
}
public override async Task<AuthenticationResponse> Authenticate(IAssetStoreClient client, CancellationToken cancellationToken)
{
var result = await client.Post(LoginUrl, AuthenticationContent, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
return ParseResponse(result);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 353e556b63fd441428f387bc85aa612c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/CredentialsAuthentication.cs
uploadId: 724584

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1f83e4b5507886f4b873c22c146b8f6a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Models
{
internal class Category
{
public int Id { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public class AssetStoreCategoryResolver : DefaultContractResolver
{
private Dictionary<string, string> _propertyConversions;
public AssetStoreCategoryResolver()
{
_propertyConversions = new Dictionary<string, string>()
{
{ nameof(Category.Name), "assetstore_name" }
};
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyConversions.ContainsKey(propertyName))
return _propertyConversions[propertyName];
return base.ResolvePropertyName(propertyName);
}
}
public class CachedCategoryResolver : DefaultContractResolver
{
private static CachedCategoryResolver _instance;
public static CachedCategoryResolver Instance => _instance ?? (_instance = new CachedCategoryResolver());
private Dictionary<string, string> _propertyConversion;
private CachedCategoryResolver()
{
this.NamingStrategy = new SnakeCaseNamingStrategy();
_propertyConversion = new Dictionary<string, string>()
{
{ nameof(Category.Name), "name" }
};
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyConversion.ContainsKey(propertyName))
return _propertyConversion[propertyName];
return base.ResolvePropertyName(propertyName);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5897866bc65f5834dab1f17371daada7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Models/Category.cs
uploadId: 724584

View File

@@ -0,0 +1,80 @@
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Models
{
internal class Package
{
public string PackageId { get; set; }
public string VersionId { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public string Category { get; set; }
public bool IsCompleteProject { get; set; }
public string RootGuid { get; set; }
public string RootPath { get; set; }
public string ProjectPath { get; set; }
public string Modified { get; set; }
public string Size { get; set; }
public string IconUrl { get; set; }
public class AssetStorePackageResolver : DefaultContractResolver
{
private static AssetStorePackageResolver _instance;
public static AssetStorePackageResolver Instance => _instance ?? (_instance = new AssetStorePackageResolver());
private Dictionary<string, string> _propertyConversions;
private AssetStorePackageResolver()
{
_propertyConversions = new Dictionary<string, string>()
{
{ nameof(Package.VersionId), "id" },
{ nameof(Package.IsCompleteProject), "is_complete_project" },
{ nameof(Package.RootGuid), "root_guid" },
{ nameof(Package.RootPath), "root_path" },
{ nameof(Package.ProjectPath), "project_path" },
{ nameof(Package.IconUrl), "icon_url" }
};
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyConversions.ContainsKey(propertyName))
return _propertyConversions[propertyName];
return base.ResolvePropertyName(propertyName);
}
}
public class CachedPackageResolver : DefaultContractResolver
{
private static CachedPackageResolver _instance;
public static CachedPackageResolver Instance => _instance ?? (_instance = new CachedPackageResolver());
private Dictionary<string, string> _propertyConversion;
private CachedPackageResolver()
{
this.NamingStrategy = new SnakeCaseNamingStrategy();
_propertyConversion = new Dictionary<string, string>()
{
{ nameof(Package.PackageId), "package_id" },
{ nameof(Package.VersionId), "version_id" },
{ nameof(Package.IsCompleteProject), "is_complete_project" },
{ nameof(Package.RootGuid), "root_guid" },
{ nameof(Package.RootPath), "root_path" },
{ nameof(Package.IconUrl), "icon_url" }
};
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyConversion.ContainsKey(propertyName))
return _propertyConversion[propertyName];
return base.ResolvePropertyName(propertyName);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 7e9f0b99820061b49abf6e8cf544a727
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Models/Package.cs
uploadId: 724584

View File

@@ -0,0 +1,41 @@
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Models
{
internal class PackageAdditionalData
{
public string Name { get; set; }
public string Status { get; set; }
public string PackageId { get; set; }
public string VersionId { get; set; }
public string CategoryId { get; set; }
public string Modified { get; set; }
public string Size { get; set; }
public class AssetStorePackageResolver : DefaultContractResolver
{
private static AssetStorePackageResolver _instance;
public static AssetStorePackageResolver Instance => _instance ?? (_instance = new AssetStorePackageResolver());
private Dictionary<string, string> _propertyConversions;
private AssetStorePackageResolver()
{
_propertyConversions = new Dictionary<string, string>()
{
{ nameof(PackageAdditionalData.PackageId), "id" },
{ nameof(PackageAdditionalData.CategoryId), "category_id" }
};
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyConversions.ContainsKey(propertyName))
return _propertyConversions[propertyName];
return base.ResolvePropertyName(propertyName);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0663f29f3fcd0e34ab77338d1bdbb528
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Models/PackageAdditionalData.cs
uploadId: 724584

View File

@@ -0,0 +1,51 @@
using Newtonsoft.Json.Serialization;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Models
{
internal class User
{
public string Id { get; set; }
public string SessionId { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string PublisherId { get; set; }
public bool IsPublisher => !string.IsNullOrEmpty(PublisherId);
public override string ToString()
{
return
$"{nameof(Id)}: {Id}\n" +
$"{nameof(Name)}: {Name}\n" +
$"{nameof(Username)}: {Username}\n" +
$"{nameof(PublisherId)}: {PublisherId}\n" +
$"{nameof(IsPublisher)}: {IsPublisher}\n" +
$"{nameof(SessionId)}: [HIDDEN]";
}
public class AssetStoreUserResolver : DefaultContractResolver
{
private static AssetStoreUserResolver _instance;
public static AssetStoreUserResolver Instance => _instance ?? (_instance = new AssetStoreUserResolver());
private Dictionary<string, string> _propertyConversions;
private AssetStoreUserResolver()
{
_propertyConversions = new Dictionary<string, string>()
{
{ nameof(User.SessionId), "xunitysession" },
{ nameof(User.PublisherId), "publisher" }
};
}
protected override string ResolvePropertyName(string propertyName)
{
if (_propertyConversions.ContainsKey(propertyName))
return _propertyConversions[propertyName];
return base.ResolvePropertyName(propertyName);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: caf38df5cd685a345a1ebec8f7651c93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Models/User.cs
uploadId: 724584

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 49581213e7b6ca645955cce8ce23ac4b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace AssetStoreTools.Api.Responses
{
/// <summary>
/// A structure used to return the success outcome and the result of Asset Store API calls
/// </summary>
internal class AssetStoreResponse
{
public bool Success { get; set; } = false;
public bool Cancelled { get; set; } = false;
public Exception Exception { get; set; }
public AssetStoreResponse() { }
public AssetStoreResponse(Exception e) : this()
{
Exception = e;
}
protected void ValidateAssetStoreResponse(string json)
{
var dict = JsonConvert.DeserializeObject<JObject>(json);
if (dict == null)
throw new Exception("Response is empty");
// Some json responses return an error field on error
if (dict.ContainsKey("error"))
{
// Server side error message
// Do not write to console since this is an error that
// is "expected" ie. can be handled by the gui.
throw new Exception(dict.GetValue("error").ToString());
}
// Some json responses return status+message fields instead of an error field. Go figure.
else if (dict.ContainsKey("status") && dict.GetValue("status").ToString() != "ok"
&& dict.ContainsKey("message"))
{
throw new Exception(dict.GetValue("message").ToString());
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ee338db031a0cfb459f7cac7f41a5d75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/AssetStoreResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,38 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
namespace AssetStoreTools.Api.Responses
{
internal class AssetStoreToolsVersionResponse : AssetStoreResponse
{
public string Version { get; set; }
public AssetStoreToolsVersionResponse() : base() { }
public AssetStoreToolsVersionResponse(Exception e) : base(e) { }
public AssetStoreToolsVersionResponse(string json)
{
try
{
ValidateAssetStoreResponse(json);
ParseVersion(json);
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
private void ParseVersion(string json)
{
var dict = JsonConvert.DeserializeObject<JObject>(json);
if (!dict.ContainsKey("version"))
throw new Exception("Version was not found");
Version = dict.GetValue("version").ToString();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 40558675926f913478a654350149209e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/AssetStoreToolsVersionResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,74 @@
using AssetStoreTools.Api.Models;
using Newtonsoft.Json;
using System;
using System.Net;
using System.Net.Http;
namespace AssetStoreTools.Api.Responses
{
internal class AuthenticationResponse : AssetStoreResponse
{
public User User { get; set; }
public AuthenticationResponse() : base() { }
public AuthenticationResponse(Exception e) : base(e) { }
public AuthenticationResponse(HttpStatusCode statusCode, HttpRequestException fallbackException)
{
string message;
switch (statusCode)
{
case HttpStatusCode.Unauthorized:
message = "Incorrect email and/or password. Please try again.";
break;
case HttpStatusCode.InternalServerError:
message = "Authentication request failed\nIf you were logging in with your Unity Cloud account, please make sure you are still logged in.\n" +
"This might also be caused by too many invalid login attempts - if that is the case, please try again later.";
break;
default:
Exception = fallbackException;
return;
}
Exception = new Exception(message);
}
public AuthenticationResponse(string json)
{
try
{
ValidateAssetStoreResponse(json);
var serializerSettings = new JsonSerializerSettings()
{
ContractResolver = User.AssetStoreUserResolver.Instance
};
User = JsonConvert.DeserializeObject<User>(json, serializerSettings);
ValidateLoginData();
ValidatePublisher();
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
private void ValidateLoginData()
{
if (string.IsNullOrEmpty(User.Id)
|| string.IsNullOrEmpty(User.SessionId)
|| string.IsNullOrEmpty(User.Name)
|| string.IsNullOrEmpty(User.Username))
throw new Exception("Could not parse the necessary publisher information from the response.");
}
private void ValidatePublisher()
{
if (!User.IsPublisher)
throw new Exception($"Your Unity ID {User.Name} is not currently connected to a publisher account. " +
$"Please create a publisher profile.");
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ec3a5cb59a7e78646b07f800d317874d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/AuthenticationResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,43 @@
using AssetStoreTools.Api.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Responses
{
internal class CategoryDataResponse : AssetStoreResponse
{
public List<Category> Categories { get; set; }
public CategoryDataResponse() : base() { }
public CategoryDataResponse(Exception e) : base(e) { }
public CategoryDataResponse(string json)
{
try
{
var categoryArray = JsonConvert.DeserializeObject<JArray>(json);
Categories = new List<Category>();
var serializer = new JsonSerializer()
{
ContractResolver = new Category.AssetStoreCategoryResolver()
};
foreach (var categoryData in categoryArray)
{
var category = categoryData.ToObject<Category>(serializer);
Categories.Add(category);
}
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: e3789323453f1604286b436f77bdca97
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/CategoryDataResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,31 @@
using System;
using UnityEngine;
namespace AssetStoreTools.Api.Responses
{
internal class PackageThumbnailResponse : AssetStoreResponse
{
public Texture2D Thumbnail { get; set; }
public PackageThumbnailResponse() : base() { }
public PackageThumbnailResponse(Exception e) : base(e) { }
public PackageThumbnailResponse(byte[] textureBytes)
{
try
{
var tex = new Texture2D(1, 1, TextureFormat.RGBA32, false);
var success = tex.LoadImage(textureBytes);
if (!success)
throw new Exception("Could not retrieve image from the provided texture bytes");
Thumbnail = tex;
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: dacfba636b3757e408514b850d715e18
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/PackageThumbnailResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,44 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Responses
{
internal class PackageUploadedUnityVersionDataResponse : AssetStoreResponse
{
public List<string> UnityVersions { get; set; }
public PackageUploadedUnityVersionDataResponse() : base() { }
public PackageUploadedUnityVersionDataResponse(Exception e) : base(e) { }
public PackageUploadedUnityVersionDataResponse(string json)
{
try
{
ValidateAssetStoreResponse(json);
ParseVersionData(json);
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
private void ParseVersionData(string json)
{
var data = JsonConvert.DeserializeObject<JObject>(json);
try
{
var content = data.GetValue("content").ToObject<JObject>();
UnityVersions = content.GetValue("unity_versions").ToObject<List<string>>();
}
catch
{
throw new Exception("Could not parse the unity versions array");
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2552f659a600e124aa952f3ba760ddf3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/PackageUploadedUnityVersionDataResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,59 @@
using AssetStoreTools.Api.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Responses
{
internal class PackagesAdditionalDataResponse : AssetStoreResponse
{
public List<PackageAdditionalData> Packages { get; set; }
public PackagesAdditionalDataResponse() : base() { }
public PackagesAdditionalDataResponse(Exception e) : base(e) { }
public PackagesAdditionalDataResponse(string json)
{
try
{
ValidateAssetStoreResponse(json);
ParseExtraData(json);
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
private void ParseExtraData(string json)
{
var packageDict = JsonConvert.DeserializeObject<JObject>(json);
if (!packageDict.ContainsKey("packages"))
throw new Exception("Response did not not contain the list of packages");
Packages = new List<PackageAdditionalData>();
var serializer = new JsonSerializer()
{
ContractResolver = PackageAdditionalData.AssetStorePackageResolver.Instance
};
var packageArray = packageDict.GetValue("packages").ToObject<JArray>();
foreach (var packageData in packageArray)
{
var package = packageData.ToObject<PackageAdditionalData>(serializer);
// Some fields are based on the latest version in the json
var latestVersion = packageData["versions"].ToObject<JArray>().Last;
package.VersionId = latestVersion["id"].ToString();
package.Modified = latestVersion["modified"].ToString();
package.Size = latestVersion["size"].ToString();
Packages.Add(package);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 88d58ad5e0eea6345b5c83f30ee8ebd5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/PackagesAdditionalDataResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,59 @@
using AssetStoreTools.Api.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
namespace AssetStoreTools.Api.Responses
{
internal class PackagesDataResponse : AssetStoreResponse
{
public List<Package> Packages { get; set; }
public PackagesDataResponse() : base() { }
public PackagesDataResponse(Exception e) : base(e) { }
public PackagesDataResponse(string json)
{
try
{
ValidateAssetStoreResponse(json);
ParseMainData(json);
Success = true;
}
catch (Exception e)
{
Success = false;
Exception = e;
}
}
private void ParseMainData(string json)
{
var packageDict = JsonConvert.DeserializeObject<JObject>(json);
if (!packageDict.ContainsKey("packages"))
throw new Exception("Response did not not contain the list of packages");
Packages = new List<Package>();
var serializer = new JsonSerializer()
{
ContractResolver = Package.AssetStorePackageResolver.Instance
};
foreach (var packageToken in packageDict["packages"])
{
var property = (JProperty)packageToken;
var packageData = property.Value.ToObject<Package>(serializer);
// Package Id is the key of the package object
packageData.PackageId = property.Name;
// Package Icon Url is returned without the https: prefix
if (!string.IsNullOrEmpty(packageData.IconUrl))
packageData.IconUrl = $"https:{packageData.IconUrl}";
Packages.Add(packageData);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 705ec748e689148479f54666993cd79d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/PackagesDataResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,12 @@
using AssetStoreTools.Api.Models;
using System;
namespace AssetStoreTools.Api.Responses
{
internal class RefreshedPackageDataResponse : AssetStoreResponse
{
public Package Package { get; set; }
public RefreshedPackageDataResponse() { }
public RefreshedPackageDataResponse(Exception e) : base(e) { }
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 20f710024d5ed514db02672f12ac361c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/RefreshedPackageDataResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,28 @@
using System;
namespace AssetStoreTools.Api.Responses
{
internal class PackageUploadResponse : AssetStoreResponse
{
public UploadStatus Status { get; set; }
public PackageUploadResponse() : base() { }
public PackageUploadResponse(Exception e) : base(e) { }
public PackageUploadResponse(string json)
{
try
{
ValidateAssetStoreResponse(json);
Status = UploadStatus.Success;
Success = true;
}
catch (Exception e)
{
Success = false;
Status = UploadStatus.Fail;
Exception = e;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 8f1758cfa8119cf49a61b010a04352e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/Responses/UploadResponse.cs
uploadId: 724584

View File

@@ -0,0 +1,25 @@
using AssetStoreTools.Api.Responses;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal class SessionAuthentication : AuthenticationBase
{
public SessionAuthentication(string sessionId)
{
AuthenticationContent = GetAuthenticationContent(
new KeyValuePair<string, string>("reuse_session", sessionId)
);
}
public override async Task<AuthenticationResponse> Authenticate(IAssetStoreClient client, CancellationToken cancellationToken)
{
var result = await client.Post(LoginUrl, AuthenticationContent, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
return ParseResponse(result);
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 02e970f660088cc4b89003608d59cd06
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/SessionAuthentication.cs
uploadId: 724584

View File

@@ -0,0 +1,99 @@
using AssetStoreTools.Api.Responses;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace AssetStoreTools.Api
{
internal class UnityPackageUploadSettings
{
public string VersionId { get; set; }
public string UnityPackagePath { get; set; }
public string RootGuid { get; set; }
public string RootPath { get; set; }
public string ProjectPath { get; set; }
}
internal class UnityPackageUploader : PackageUploaderBase
{
private UnityPackageUploadSettings _settings;
private Uri _uploadUri;
public UnityPackageUploader(UnityPackageUploadSettings settings)
{
_settings = settings;
}
protected override void ValidateSettings()
{
if (string.IsNullOrEmpty(_settings.VersionId))
throw new Exception("Version Id is unset");
if (string.IsNullOrEmpty(_settings.UnityPackagePath)
|| !File.Exists(_settings.UnityPackagePath))
throw new Exception("Package file could not be found");
if (!_settings.UnityPackagePath.EndsWith(".unitypackage"))
throw new Exception("Provided package file is not .unitypackage");
}
public override async Task<PackageUploadResponse> Upload(IAssetStoreClient client, IProgress<float> progress = null, CancellationToken cancellationToken = default)
{
try
{
ValidateSettings();
var endpoint = Constants.Api.UploadUnityPackageUrl(_settings.VersionId);
var query = new Dictionary<string, string>()
{
{ "root_guid", _settings.RootGuid },
{ "root_path", _settings.RootPath },
{ "project_path", _settings.ProjectPath }
};
_uploadUri = ApiUtility.CreateUri(endpoint, query, true);
}
catch (Exception e)
{
return new PackageUploadResponse() { Success = false, Status = UploadStatus.Fail, Exception = e };
}
return await Task.Run(() => UploadTask(client, progress, cancellationToken));
}
private PackageUploadResponse UploadTask(IAssetStoreClient client, IProgress<float> progress, CancellationToken cancellationToken)
{
try
{
using (FileStream requestFileStream = new FileStream(_settings.UnityPackagePath, FileMode.Open, FileAccess.Read))
{
var content = new StreamContent(requestFileStream, UploadChunkSizeBytes);
var response = client.Put(_uploadUri, content, cancellationToken);
WaitForUploadCompletion(response, requestFileStream, progress, cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
EnsureSuccessResponse(response.Result);
var responseStr = response.Result.Content.ReadAsStringAsync().Result;
return new PackageUploadResponse(responseStr);
}
}
catch (OperationCanceledException e)
{
return new PackageUploadResponse() { Success = false, Cancelled = true, Status = UploadStatus.Cancelled, Exception = e };
}
catch (TimeoutException e)
{
return new PackageUploadResponse() { Success = true, Status = UploadStatus.ResponseTimeout, Exception = e };
}
catch (Exception e)
{
return new PackageUploadResponse() { Success = false, Exception = e, Status = UploadStatus.Fail };
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 95bd0284375397f41a2065e07d4ba526
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/UnityPackageUploader.cs
uploadId: 724584

View File

@@ -0,0 +1,11 @@
namespace AssetStoreTools.Api
{
internal enum UploadStatus
{
Default = 0,
Success = 1,
Fail = 2,
Cancelled = 3,
ResponseTimeout = 4
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0a121831a941cb64a8a9d21ca6fda9c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 115
packageName: Asset Store Publishing Tools
packageVersion: 12.0.1
assetPath: Packages/com.unity.asset-store-tools/Editor/Api/UploadStatus.cs
uploadId: 724584