2025-02-20 10:48:57 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.Networking;
|
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using Unity.EditorCoroutines.Editor;
|
|
|
|
|
using UnityEditor;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace AlicizaX.PackageManager.Editor
|
|
|
|
|
{
|
|
|
|
|
public enum PackageState
|
|
|
|
|
{
|
|
|
|
|
UnInstall,
|
|
|
|
|
InstallLocal,
|
|
|
|
|
Install,
|
|
|
|
|
Update
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public class RepositoryPackageData
|
|
|
|
|
{
|
|
|
|
|
// Repository info
|
|
|
|
|
public string name;
|
|
|
|
|
public string description;
|
|
|
|
|
public string cloneUrl;
|
|
|
|
|
public string htmlUrl;
|
|
|
|
|
public string updatedAt;
|
|
|
|
|
|
|
|
|
|
// Package info
|
|
|
|
|
public string displayName;
|
|
|
|
|
public string version;
|
|
|
|
|
public string unityVersion;
|
|
|
|
|
public string category;
|
|
|
|
|
public string packageDescription;
|
|
|
|
|
public string authorName;
|
|
|
|
|
public PackageState PackageState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public class RepoApiResponse
|
|
|
|
|
{
|
|
|
|
|
public bool ok;
|
|
|
|
|
public List<RepoItem> data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public class RepoItem
|
|
|
|
|
{
|
|
|
|
|
public string name;
|
|
|
|
|
public string description;
|
|
|
|
|
public string clone_url;
|
|
|
|
|
public string html_url;
|
|
|
|
|
public string updated_at;
|
|
|
|
|
public Owner owner;
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public class Owner
|
|
|
|
|
{
|
|
|
|
|
public string login;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public class PackageJsonResponse
|
|
|
|
|
{
|
|
|
|
|
public string name;
|
|
|
|
|
public string displayName;
|
|
|
|
|
public string category;
|
|
|
|
|
public string description;
|
|
|
|
|
public string version;
|
|
|
|
|
public string unity;
|
|
|
|
|
public Author author;
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
public class Author
|
|
|
|
|
{
|
|
|
|
|
public string name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class RepositoryDataFetcher
|
|
|
|
|
{
|
|
|
|
|
private const string BaseApiUrl = "http://101.34.252.46:3000/api/v1/repos/search?q=unity&topic=false";
|
|
|
|
|
private const string PackageJsonPath = "/raw/branch/main/package.json";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void FetchRepositoryData(Action<List<RepositoryPackageData>> callback)
|
|
|
|
|
{
|
2025-02-20 11:44:00 +08:00
|
|
|
|
EditorPrefs.SetString("PackageUpdateDate", DateTime.Now.ToString());
|
2025-02-20 10:48:57 +08:00
|
|
|
|
EditorCoroutineUtility.StartCoroutineOwnerless(FetchDataRoutine(callback));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IEnumerator FetchDataRoutine(Action<List<RepositoryPackageData>> callback)
|
|
|
|
|
{
|
|
|
|
|
// 第一阶段:获取仓库列表
|
|
|
|
|
using (var request = CreateWebRequest(BaseApiUrl))
|
|
|
|
|
{
|
|
|
|
|
yield return request.SendWebRequest();
|
|
|
|
|
|
|
|
|
|
if (!HandleRequestError(request, "Repository request failed"))
|
|
|
|
|
{
|
|
|
|
|
callback?.Invoke(null);
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var repoResponse = JsonConvert.DeserializeObject<RepoApiResponse>(request.downloadHandler.text);
|
|
|
|
|
if (!repoResponse.ok || repoResponse.data == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError("Invalid repository response data");
|
|
|
|
|
callback?.Invoke(null);
|
|
|
|
|
yield break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var results = new List<RepositoryPackageData>();
|
|
|
|
|
var pendingRequests = new Queue<RepoItem>(repoResponse.data);
|
|
|
|
|
|
|
|
|
|
// 第二阶段:逐个获取package.json信息
|
|
|
|
|
while (pendingRequests.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
var repo = pendingRequests.Dequeue();
|
|
|
|
|
var packageData = CreateBaseRepositoryData(repo);
|
|
|
|
|
|
|
|
|
|
var packageUrl = repo.html_url + PackageJsonPath;
|
|
|
|
|
using (var packageRequest = CreateWebRequest(packageUrl))
|
|
|
|
|
{
|
|
|
|
|
yield return packageRequest.SendWebRequest();
|
|
|
|
|
|
|
|
|
|
if (HandleRequestError(packageRequest, $"Package request failed for {repo.name}"))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var packageInfo = JsonConvert.DeserializeObject<PackageJsonResponse>(
|
|
|
|
|
packageRequest.downloadHandler.text);
|
|
|
|
|
|
|
|
|
|
UpdateWithPackageInfo(ref packageData, packageInfo);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"JSON parse error for {repo.name}: {e.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
results.Add(packageData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 防止同时发起太多请求,每帧处理一个
|
|
|
|
|
yield return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
callback?.Invoke(results);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static UnityWebRequest CreateWebRequest(string url)
|
|
|
|
|
{
|
|
|
|
|
var request = new UnityWebRequest(url, "GET");
|
|
|
|
|
request.downloadHandler = new DownloadHandlerBuffer();
|
|
|
|
|
request.SetRequestHeader("accept", "application/json");
|
|
|
|
|
return request;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool HandleRequestError(UnityWebRequest request, string errorMessage)
|
|
|
|
|
{
|
|
|
|
|
if (request.result != UnityWebRequest.Result.Success)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"{errorMessage}: {request.error}");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static RepositoryPackageData CreateBaseRepositoryData(RepoItem repo)
|
|
|
|
|
{
|
|
|
|
|
return new RepositoryPackageData
|
|
|
|
|
{
|
|
|
|
|
name = repo.name,
|
|
|
|
|
description = repo.description,
|
|
|
|
|
cloneUrl = repo.clone_url,
|
|
|
|
|
htmlUrl = repo.html_url,
|
|
|
|
|
updatedAt = repo.updated_at
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void UpdateWithPackageInfo(ref RepositoryPackageData data, PackageJsonResponse package)
|
|
|
|
|
{
|
|
|
|
|
if (package == null) return;
|
2025-02-20 11:44:00 +08:00
|
|
|
|
data.name = package.name;
|
2025-02-20 10:48:57 +08:00
|
|
|
|
data.displayName = package.displayName;
|
|
|
|
|
data.version = package.version;
|
|
|
|
|
data.unityVersion = package.unity;
|
|
|
|
|
data.category = package.category;
|
|
|
|
|
data.packageDescription = package.description;
|
|
|
|
|
|
|
|
|
|
if (package.author != null)
|
|
|
|
|
{
|
|
|
|
|
data.authorName = package.author.name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|