VersionFlow/Assets/VersionFlow/Editor/PatchUploader/PatchUploaderImpl/PatchUpLoader_AliOSS.cs

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;
}
}
}