241 lines
9.4 KiB
C#
241 lines
9.4 KiB
C#
using AlibabaCloud.SDK.Cdn20180510;
|
|
using AlibabaCloud.SDK.Cdn20180510.Models;
|
|
using Aliyun.OSS;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using static AlibabaCloud.SDK.Cdn20180510.Models.DescribeRefreshTasksResponseBody.DescribeRefreshTasksResponseBodyTasks;
|
|
using static VersionFlow.Editors.ICDNPerformer;
|
|
|
|
namespace VersionFlow.Editors
|
|
{
|
|
[Description("阿里云OSS")]
|
|
public class PatchUpLoader_AliOSS : PatchUploader<PatchUpLoader_AliOSS.Config>,
|
|
ICDNPerformer,
|
|
IAsyncDownloader
|
|
{
|
|
private OssClient m_ossClient;
|
|
private Client m_cdnClient;
|
|
|
|
protected override void OnCfgChanged()
|
|
{
|
|
try
|
|
{
|
|
m_ossClient = new OssClient(m_cfg.endPoint, m_cfg.accessKeyId, m_cfg.accessKeySecret);
|
|
m_cdnClient = new Client(new AlibabaCloud.OpenApiClient.Models.Config { AccessKeyId = m_cfg.accessKeyId, AccessKeySecret = m_cfg.accessKeySecret });
|
|
Debug.Log("AliOSS SDK 初始化成功");
|
|
}
|
|
catch
|
|
{
|
|
Debug.LogError("AliOSS SDK 初始化失败,请检查相关参数配置");
|
|
}
|
|
}
|
|
|
|
public override void UploadFile(string remoteFilePath, MemoryStream localfileStream)
|
|
{
|
|
var filePathInBucket = $"{m_cfg.UploadPath}/{remoteFilePath}";
|
|
|
|
ObjectMetadata metadata = new ObjectMetadata() { ContentEncoding = "identity" };
|
|
m_ossClient.PutObject(m_cfg.BucketName, filePathInBucket, localfileStream, metadata);
|
|
}
|
|
|
|
public override void DeleteFile(string remoteFilePath)
|
|
{
|
|
m_ossClient.DeleteObject(m_cfg.BucketName, remoteFilePath);
|
|
}
|
|
|
|
void ICDNPerformer.CDNRefresh(IEnumerable<string> refreshPaths)
|
|
{
|
|
var client = m_cdnClient;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
var vfSetting = m_builder.vfSetting;
|
|
|
|
var refreshFileUrls = refreshPaths.Select(path => $"{vfSetting.RootPath}/{path}").ToList();
|
|
var refreshDirectoryUrls = PathHelper.GetSameRoot(refreshFileUrls);
|
|
|
|
var response = client.DescribeRefreshQuota(new DescribeRefreshQuotaRequest());
|
|
int dirRemian = int.Parse(response.Body.DirRemain);
|
|
int fileUrlRemain = int.Parse(response.Body.UrlQuota);
|
|
|
|
Debug.Log($"目录刷新配额剩余:[{dirRemian},本次目录刷新数量:[{refreshDirectoryUrls.Count}]");
|
|
Debug.Log($"URL刷新配额剩余:[{fileUrlRemain},本次URL刷新数量:[{refreshFileUrls.Count}]");
|
|
|
|
var request = new RefreshObjectCachesRequest { Force = true };
|
|
|
|
if (dirRemian >= refreshDirectoryUrls.Count)
|
|
{
|
|
Debug.Log($"以目录形式刷新");
|
|
foreach (var path in refreshDirectoryUrls)
|
|
{
|
|
sb.Append($"{path}/\n");
|
|
}
|
|
request.ObjectPath = sb.ToString();
|
|
request.ObjectType = "Directory";
|
|
}
|
|
else if (fileUrlRemain >= refreshFileUrls.Count)
|
|
{
|
|
Debug.Log($"以URL形式刷新");
|
|
foreach (var path in refreshFileUrls)
|
|
{
|
|
sb.Append($"{path}\n");
|
|
}
|
|
request.ObjectPath = sb.ToString();
|
|
request.ObjectType = "File";
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("刷新配额不足,无法刷新CDN资源");
|
|
}
|
|
|
|
request.ObjectPath = request.ObjectPath.Remove(request.ObjectPath.Length - 1);
|
|
|
|
try
|
|
{
|
|
Debug.Log($"刷新CDN资源:\n{request.ObjectPath}");
|
|
var refreshResponse = client.RefreshObjectCaches(request);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogError($"刷新cdn失败,请检查刷新路径{request.ObjectPath}\n或者是其他原因导致\n{ex}");
|
|
}
|
|
}
|
|
|
|
async Task<List<TaskReport>> ICDNPerformer.GetRefreshingTaskAsync()
|
|
{
|
|
var result = new List<TaskReport>();
|
|
await FetchTask(result, "Refreshing", "file", 10000);
|
|
await FetchTask(result, "Refreshing", "directory", 100);
|
|
await FetchTask(result, "Failed", "file", 10000);
|
|
await FetchTask(result, "Failed", "directory", 100);
|
|
await FetchTask(result, "Complete", "file", 100);
|
|
await FetchTask(result, "Complete", "directory", 100);
|
|
|
|
return result;
|
|
|
|
TaskReport ToReport(DescribeRefreshTasksResponseBodyTasksCDNTask alicdnTask)
|
|
{
|
|
var temp = alicdnTask.Process.Replace("%", string.Empty);
|
|
var progress = int.Parse(temp) / 100f;
|
|
|
|
TaskReport taskReport = new TaskReport()
|
|
{
|
|
Describ = alicdnTask.ObjectPath,
|
|
Progress = progress,
|
|
Status = alicdnTask.Status switch
|
|
{
|
|
"Complete" => ICDNPerformer.TaskStatus.Complete,
|
|
"Refreshing" => ICDNPerformer.TaskStatus.Running,
|
|
"Failed" => ICDNPerformer.TaskStatus.Error,
|
|
_ => ICDNPerformer.TaskStatus.Error
|
|
}
|
|
};
|
|
|
|
return taskReport;
|
|
}
|
|
|
|
async Task FetchTask(List<TaskReport> list, string status, string objType, int maxQueryCount)
|
|
{
|
|
int queriedCount = 0;
|
|
for (int page = 1; page <= 10000 && queriedCount <= maxQueryCount; page++)
|
|
{
|
|
var response = await m_cdnClient.DescribeRefreshTasksAsync(new DescribeRefreshTasksRequest
|
|
{
|
|
Status = status,
|
|
PageSize = 100,
|
|
PageNumber = page,
|
|
ObjectType = objType
|
|
});
|
|
|
|
var tasks = response.Body.Tasks.CDNTask;
|
|
if (tasks.Count == 0) break;
|
|
|
|
var old = list.Count;
|
|
list.AddRange(tasks.Select(t => ToReport(t)));
|
|
var newAdd = list.Count - old;
|
|
queriedCount += newAdd;
|
|
}
|
|
}
|
|
}
|
|
public override byte[] DownloadFile(string remoteFilePath)
|
|
{
|
|
if (!CheckFileExist(remoteFilePath)) return null;
|
|
|
|
var fileObj = m_ossClient.GetObject(m_cfg.BucketName, $"{m_cfg.UploadPath}/{remoteFilePath}");
|
|
if (fileObj == null) return null;
|
|
|
|
byte[] buffer = new byte[fileObj.ContentLength];
|
|
int readed = 0;
|
|
while (readed < buffer.Length - 1)
|
|
{
|
|
int read = fileObj.Content.Read(buffer, readed, buffer.Length - readed);
|
|
readed += read;
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
public void DownloadFileAsync(IAsyncDownloader.DownloadTask reporter)
|
|
{
|
|
CancellationTokenSource cancelSrc = new CancellationTokenSource();
|
|
Task.Run(() =>
|
|
{
|
|
if (!CheckFileExist(reporter.RemotePath))
|
|
{
|
|
reporter.Cancel("文件未找到");
|
|
return;
|
|
}
|
|
|
|
Action<IAsyncDownloader.DownloadTask> reporterCallback = (sender) =>
|
|
{
|
|
if (sender.Status == IAsyncDownloader.EnumDownloaderStatus.Cancel)
|
|
{
|
|
cancelSrc.Cancel();
|
|
}
|
|
};
|
|
reporter.OnStateUpdate += reporterCallback;
|
|
|
|
var getObjectRequest = new GetObjectRequest(m_cfg.BucketName, $"{m_cfg.UploadPath}/{reporter.RemotePath}");
|
|
getObjectRequest.StreamTransferProgress += (object sender, StreamTransferProgressArgs args) =>
|
|
{
|
|
reporter.Report((ulong)args.TransferredBytes, (ulong)args.TotalBytes);
|
|
};
|
|
var ossObject = m_ossClient.GetObject(getObjectRequest);
|
|
List<byte> data = new List<byte>();
|
|
using (var stream = ossObject.Content)
|
|
{
|
|
var buffer = new byte[1024 * 1024];
|
|
var bytesRead = 0;
|
|
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
|
|
{
|
|
data.AddRange(buffer.Take(bytesRead));
|
|
}
|
|
}
|
|
reporter.Finish(data.ToArray());
|
|
}, cancelSrc.Token);
|
|
}
|
|
|
|
bool CheckFileExist(string relativePath)
|
|
{
|
|
relativePath = relativePath.Replace('\\', '/').TrimStart('/');
|
|
string filePathInBucket = $"{m_cfg.UploadPath}/{relativePath}";
|
|
return m_ossClient.DoesObjectExist(m_cfg.BucketName, filePathInBucket);
|
|
}
|
|
|
|
[Serializable]
|
|
public struct Config
|
|
{
|
|
public string BucketName;
|
|
public string UploadPath;
|
|
public string accessKeyId;
|
|
public string accessKeySecret;
|
|
public string endPoint;
|
|
}
|
|
}
|
|
} |