* AWSUploader.cs: chore: await/async
* AVFile.cs: * AVCloud.cs: * AVQuery.cs: * AVLeaderboard.cs: * QiniuUploader.cs: * QCloudUploader.cs:
parent
f3ed814d96
commit
aabd25d2e8
|
@ -8,15 +8,13 @@ using System.Net.Http.Headers;
|
|||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
internal class AWSUploader : IFileUploader {
|
||||
public Task<FileState> Upload(FileState state, Stream dataStream, IDictionary<string, object> fileToken, IProgress<AVUploadProgressEventArgs> progress,
|
||||
public async Task<FileState> Upload(FileState state, Stream dataStream, IDictionary<string, object> fileToken, IProgress<AVUploadProgressEventArgs> progress,
|
||||
CancellationToken cancellationToken) {
|
||||
var uploadUrl = fileToken["upload_url"].ToString();
|
||||
state.ObjectId = fileToken["objectId"].ToString();
|
||||
string url = fileToken["url"] as string;
|
||||
state.Url = new Uri(url, UriKind.Absolute);
|
||||
return PutFile(state, uploadUrl, dataStream).OnSuccess(s => {
|
||||
return s.Result;
|
||||
});
|
||||
return await PutFile(state, uploadUrl, dataStream);
|
||||
}
|
||||
|
||||
internal async Task<FileState> PutFile(FileState state, string uploadUrl, Stream dataStream) {
|
||||
|
|
|
@ -19,26 +19,28 @@ namespace LeanCloud.Storage.Internal {
|
|||
bool done;
|
||||
private long sliceSize = (long)CommonSize.KB512;
|
||||
|
||||
public Task<FileState> Upload(FileState state, Stream dataStream, IDictionary<string, object> fileToken, IProgress<AVUploadProgressEventArgs> progress, CancellationToken cancellationToken) {
|
||||
public async Task<FileState> Upload(FileState state, Stream dataStream, IDictionary<string, object> fileToken, IProgress<AVUploadProgressEventArgs> progress, CancellationToken cancellationToken) {
|
||||
fileState = state;
|
||||
data = dataStream;
|
||||
uploadUrl = fileToken["upload_url"].ToString();
|
||||
token = fileToken["token"].ToString();
|
||||
fileState.ObjectId = fileToken["objectId"].ToString();
|
||||
bucket = fileToken["bucket"].ToString();
|
||||
|
||||
return FileSlice(cancellationToken).OnSuccess(t => {
|
||||
if (done) return Task<FileState>.FromResult(state);
|
||||
var response = t.Result.Item2;
|
||||
var resumeData = response["data"] as IDictionary<string, object>;
|
||||
if (resumeData.ContainsKey("access_url")) return Task<FileState>.FromResult(state);
|
||||
var sliceSession = resumeData["session"].ToString();
|
||||
var sliceOffset = long.Parse(resumeData["offset"].ToString());
|
||||
return UploadSlice(sliceSession, sliceOffset, dataStream, progress, cancellationToken);
|
||||
}).Unwrap();
|
||||
var result = await FileSlice(cancellationToken);
|
||||
if (done) {
|
||||
return state;
|
||||
}
|
||||
var response = result.Item2;
|
||||
var resumeData = response["data"] as IDictionary<string, object>;
|
||||
if (resumeData.ContainsKey("access_url")) {
|
||||
return state;
|
||||
}
|
||||
var sliceSession = resumeData["session"].ToString();
|
||||
var sliceOffset = long.Parse(resumeData["offset"].ToString());
|
||||
return await UploadSlice(sliceSession, sliceOffset, dataStream, progress, cancellationToken);
|
||||
}
|
||||
|
||||
Task<FileState> UploadSlice(
|
||||
async Task<FileState> UploadSlice(
|
||||
string sessionId,
|
||||
long offset,
|
||||
Stream dataStream,
|
||||
|
@ -55,21 +57,20 @@ namespace LeanCloud.Storage.Internal {
|
|||
}
|
||||
|
||||
if (offset == dataLength) {
|
||||
return Task.FromResult<FileState>(fileState);
|
||||
return fileState;
|
||||
}
|
||||
|
||||
var sliceFile = GetNextBinary(offset, dataStream);
|
||||
return ExcuteUpload(sessionId, offset, sliceFile, cancellationToken).OnSuccess(_ => {
|
||||
offset += sliceFile.Length;
|
||||
if (offset == dataLength) {
|
||||
done = true;
|
||||
return Task.FromResult<FileState>(fileState);
|
||||
}
|
||||
var response = _.Result.Item2;
|
||||
var resumeData = response["data"] as IDictionary<string, object>;
|
||||
var sliceSession = resumeData["session"].ToString();
|
||||
return UploadSlice(sliceSession, offset, dataStream, progress, cancellationToken);
|
||||
}).Unwrap();
|
||||
var result = await ExcuteUpload(sessionId, offset, sliceFile, cancellationToken);
|
||||
offset += sliceFile.Length;
|
||||
if (offset == dataLength) {
|
||||
done = true;
|
||||
return fileState;
|
||||
}
|
||||
var response = result.Item2;
|
||||
var resumeData = response["data"] as IDictionary<string, object>;
|
||||
var sliceSession = resumeData["session"].ToString();
|
||||
return await UploadSlice(sliceSession, offset, dataStream, progress, cancellationToken);
|
||||
}
|
||||
|
||||
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> ExcuteUpload(string sessionId, long offset, byte[] sliceFile, CancellationToken cancellationToken) {
|
||||
|
@ -81,19 +82,18 @@ namespace LeanCloud.Storage.Internal {
|
|||
return PostToQCloud(body, sliceFile, cancellationToken);
|
||||
}
|
||||
|
||||
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> FileSlice(CancellationToken cancellationToken) {
|
||||
async Task<Tuple<HttpStatusCode, IDictionary<string, object>>> FileSlice(CancellationToken cancellationToken) {
|
||||
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
|
||||
var body = new Dictionary<string, object>();
|
||||
if (data.Length <= (long)CommonSize.KB512) {
|
||||
body.Add("op", "upload");
|
||||
body.Add("sha", HexStringFromBytes(sha1.ComputeHash(data)));
|
||||
var wholeFile = GetNextBinary(0, data);
|
||||
return PostToQCloud(body, wholeFile, cancellationToken).OnSuccess(_ => {
|
||||
if (_.Result.Item1 == HttpStatusCode.OK) {
|
||||
done = true;
|
||||
}
|
||||
return _.Result;
|
||||
});
|
||||
var result = await PostToQCloud(body, wholeFile, cancellationToken);
|
||||
if (result.Item1 == HttpStatusCode.OK) {
|
||||
done = true;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
body.Add("op", "upload_slice");
|
||||
body.Add("filesize", data.Length);
|
||||
|
@ -101,7 +101,7 @@ namespace LeanCloud.Storage.Internal {
|
|||
body.Add("slice_size", (long)CommonSize.KB512);
|
||||
}
|
||||
|
||||
return PostToQCloud(body, null, cancellationToken);
|
||||
return await PostToQCloud(body, null, cancellationToken);
|
||||
}
|
||||
public static string HexStringFromBytes(byte[] bytes) {
|
||||
var sb = new StringBuilder();
|
||||
|
|
|
@ -22,16 +22,15 @@ namespace LeanCloud.Storage.Internal {
|
|||
internal static string UP_HOST = "https://up.qbox.me";
|
||||
private readonly object mutex = new object();
|
||||
|
||||
public Task<FileState> Upload(FileState state, Stream dataStream, IDictionary<string, object> fileToken, IProgress<AVUploadProgressEventArgs> progress, CancellationToken cancellationToken) {
|
||||
public async Task<FileState> Upload(FileState state, Stream dataStream, IDictionary<string, object> fileToken, IProgress<AVUploadProgressEventArgs> progress, CancellationToken cancellationToken) {
|
||||
state.frozenData = dataStream;
|
||||
state.CloudName = fileToken["key"] as string;
|
||||
MergeFromJSON(state, fileToken);
|
||||
return UploadNextChunk(state, dataStream, string.Empty, 0, progress).OnSuccess(_ => {
|
||||
return state;
|
||||
});
|
||||
await UploadNextChunk(state, dataStream, string.Empty, 0, progress);
|
||||
return state;
|
||||
}
|
||||
|
||||
Task UploadNextChunk(FileState state, Stream dataStream, string context, long offset, IProgress<AVUploadProgressEventArgs> progress) {
|
||||
async Task UploadNextChunk(FileState state, Stream dataStream, string context, long offset, IProgress<AVUploadProgressEventArgs> progress) {
|
||||
var totalSize = dataStream.Length;
|
||||
var remainingSize = totalSize - state.completed;
|
||||
|
||||
|
@ -43,29 +42,27 @@ namespace LeanCloud.Storage.Internal {
|
|||
}
|
||||
}
|
||||
if (state.completed == totalSize) {
|
||||
return QiniuMakeFile(state, state.frozenData, state.token, state.CloudName, totalSize, state.block_ctxes.ToArray(), CancellationToken.None);
|
||||
}
|
||||
if (state.completed % BLOCKSIZE == 0) {
|
||||
await QiniuMakeFile(state, state.frozenData, state.token, state.CloudName, totalSize, state.block_ctxes.ToArray(), CancellationToken.None);
|
||||
} else if (state.completed % BLOCKSIZE == 0) {
|
||||
var firstChunkBinary = GetChunkBinary(state.completed, dataStream);
|
||||
|
||||
var blockSize = remainingSize > BLOCKSIZE ? BLOCKSIZE : remainingSize;
|
||||
return MakeBlock(state, firstChunkBinary, blockSize).OnSuccess(t => {
|
||||
var dict = t.Result;
|
||||
var ctx = dict["ctx"].ToString();
|
||||
offset = long.Parse(dict["offset"].ToString());
|
||||
var host = dict["host"].ToString();
|
||||
var result = await MakeBlock(state, firstChunkBinary, blockSize);
|
||||
var dict = result;
|
||||
var ctx = dict["ctx"].ToString();
|
||||
offset = long.Parse(dict["offset"].ToString());
|
||||
var host = dict["host"].ToString();
|
||||
|
||||
state.completed += firstChunkBinary.Length;
|
||||
if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) {
|
||||
state.block_ctxes.Add(ctx);
|
||||
}
|
||||
state.completed += firstChunkBinary.Length;
|
||||
if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) {
|
||||
state.block_ctxes.Add(ctx);
|
||||
}
|
||||
|
||||
return UploadNextChunk(state, dataStream, ctx, offset, progress);
|
||||
}).Unwrap();
|
||||
}
|
||||
var chunkBinary = GetChunkBinary(state.completed, dataStream);
|
||||
return PutChunk(state, chunkBinary, context, offset).OnSuccess(t => {
|
||||
var dict = t.Result;
|
||||
await UploadNextChunk(state, dataStream, ctx, offset, progress);
|
||||
} else {
|
||||
var chunkBinary = GetChunkBinary(state.completed, dataStream);
|
||||
var result = await PutChunk(state, chunkBinary, context, offset);
|
||||
var dict = result;
|
||||
var ctx = dict["ctx"].ToString();
|
||||
|
||||
offset = long.Parse(dict["offset"].ToString());
|
||||
|
@ -74,9 +71,8 @@ namespace LeanCloud.Storage.Internal {
|
|||
if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) {
|
||||
state.block_ctxes.Add(ctx);
|
||||
}
|
||||
|
||||
return UploadNextChunk(state, dataStream, ctx, offset, progress);
|
||||
}).Unwrap();
|
||||
await UploadNextChunk(state, dataStream, ctx, offset, progress);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] GetChunkBinary(long completed, Stream dataStream) {
|
||||
|
|
|
@ -220,19 +220,18 @@ namespace LeanCloud {
|
|||
/// <param name="height">captcha image height.</param>
|
||||
/// <param name="cancellationToken">CancellationToken.</param>
|
||||
/// <returns>an instance of Captcha.</returns>
|
||||
public static Task<Captcha> RequestCaptchaAsync(int width = 85, int height = 30, CancellationToken cancellationToken = default) {
|
||||
public static async Task<Captcha> RequestCaptchaAsync(int width = 85, int height = 30, CancellationToken cancellationToken = default) {
|
||||
var path = string.Format("requestCaptcha?width={0}&height={1}", width, height);
|
||||
var command = new AVCommand {
|
||||
Path = $"requestCaptcha?width={width}&height={height}",
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => {
|
||||
var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary<string, object>;
|
||||
return new Captcha() {
|
||||
Token = decoded["captcha_token"] as string,
|
||||
Url = decoded["captcha_url"] as string,
|
||||
};
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
|
||||
var decoded = AVDecoder.Instance.Decode(result.Item2) as IDictionary<string, object>;
|
||||
return new Captcha {
|
||||
Token = decoded["captcha_token"] as string,
|
||||
Url = decoded["captcha_url"] as string,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -242,7 +241,7 @@ namespace LeanCloud {
|
|||
/// <param name="code">User's input of this captcha.</param>
|
||||
/// <param name="cancellationToken">CancellationToken.</param>
|
||||
/// <returns></returns>
|
||||
public static Task<string> VerifyCaptchaAsync(string code, string token, CancellationToken cancellationToken = default) {
|
||||
public static async Task<string> VerifyCaptchaAsync(string code, string token, CancellationToken cancellationToken = default) {
|
||||
var data = new Dictionary<string, object> {
|
||||
{ "captcha_token", token },
|
||||
{ "captcha_code", code },
|
||||
|
@ -252,11 +251,11 @@ namespace LeanCloud {
|
|||
Method = HttpMethod.Post,
|
||||
Content = data
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).ContinueWith(t => {
|
||||
if (!t.Result.Item2.ContainsKey("validate_token"))
|
||||
throw new KeyNotFoundException("validate_token");
|
||||
return t.Result.Item2["validate_token"] as string;
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
|
||||
if (result.Item2.TryGetValue("validate_token", out object tokenObj)) {
|
||||
return tokenObj as string;
|
||||
}
|
||||
throw new KeyNotFoundException("validate_token");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -264,16 +263,15 @@ namespace LeanCloud {
|
|||
/// </summary>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<IDictionary<string, object>> GetCustomParametersAsync(CancellationToken cancellationToken = default) {
|
||||
public static async Task<IDictionary<string, object>> GetCustomParametersAsync(CancellationToken cancellationToken = default) {
|
||||
var command = new AVCommand {
|
||||
Path = $"statistics/apps/{AVClient.CurrentConfiguration.ApplicationId}/sendPolicy",
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => {
|
||||
var settings = t.Result.Item2;
|
||||
var CloudParameters = settings["parameters"] as IDictionary<string, object>;
|
||||
return CloudParameters;
|
||||
});
|
||||
var data = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
|
||||
var settings = data.Item2;
|
||||
var CloudParameters = settings["parameters"] as IDictionary<string, object>;
|
||||
return CloudParameters;
|
||||
}
|
||||
|
||||
public class RealtimeSignature {
|
||||
|
@ -283,7 +281,7 @@ namespace LeanCloud {
|
|||
public string Signature { internal set; get; }
|
||||
}
|
||||
|
||||
public static Task<RealtimeSignature> RequestRealtimeSignatureAsync(CancellationToken cancellationToken = default) {
|
||||
public static async Task<RealtimeSignature> RequestRealtimeSignatureAsync(CancellationToken cancellationToken = default) {
|
||||
var command = new AVCommand {
|
||||
Path = "rtm/sign",
|
||||
Method = HttpMethod.Post,
|
||||
|
@ -291,15 +289,14 @@ namespace LeanCloud {
|
|||
{ "session_token", AVUser.CurrentUser?.SessionToken }
|
||||
}
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => {
|
||||
var body = t.Result.Item2;
|
||||
return new RealtimeSignature() {
|
||||
Nonce = body["nonce"] as string,
|
||||
Timestamp = (long)body["timestamp"],
|
||||
ClientId = body["client_id"] as string,
|
||||
Signature = body["signature"] as string,
|
||||
};
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
|
||||
var body = result.Item2;
|
||||
return new RealtimeSignature() {
|
||||
Nonce = body["nonce"] as string,
|
||||
Timestamp = (long)body["timestamp"],
|
||||
ClientId = body["client_id"] as string,
|
||||
Signature = body["signature"] as string,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -265,11 +265,8 @@ namespace LeanCloud {
|
|||
/// </summary>
|
||||
/// <param name="progress">The progress callback.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
public Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress = null, CancellationToken cancellationToken = default) {
|
||||
return FileController.SaveAsync(state, dataStream, progress, cancellationToken)
|
||||
.OnSuccess(t => {
|
||||
state = t.Result;
|
||||
});
|
||||
public async Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress = null, CancellationToken cancellationToken = default) {
|
||||
state = await FileController.SaveAsync(state, dataStream, progress, cancellationToken);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -320,11 +317,9 @@ namespace LeanCloud {
|
|||
/// </summary>
|
||||
/// <remarks>获取之后并没有实际执行下载,只是加载了文件的元信息以及物理地址(Url)
|
||||
/// </remarks>
|
||||
public static Task<AVFile> GetFileWithObjectIdAsync(string objectId, CancellationToken cancellationToken = default) {
|
||||
return FileController.GetAsync(objectId, cancellationToken).OnSuccess(_ => {
|
||||
var filestate = _.Result;
|
||||
return new AVFile(filestate);
|
||||
});
|
||||
public static async Task<AVFile> GetFileWithObjectIdAsync(string objectId, CancellationToken cancellationToken = default) {
|
||||
var fileState = await FileController.GetAsync(objectId, cancellationToken);
|
||||
return new AVFile(fileState);
|
||||
}
|
||||
|
||||
public static AVFile CreateWithoutData(string objectId) {
|
||||
|
|
|
@ -10,8 +10,7 @@ using System.Text.RegularExpressions;
|
|||
using Newtonsoft.Json;
|
||||
using LeanCloud.Storage.Internal;
|
||||
|
||||
namespace LeanCloud
|
||||
{
|
||||
namespace LeanCloud {
|
||||
public class AVQuery<T> where T : AVObject {
|
||||
public string ClassName {
|
||||
get; internal set;
|
||||
|
@ -24,7 +23,8 @@ namespace LeanCloud
|
|||
return $"classes/{Uri.EscapeDataString(ClassName)}";
|
||||
}
|
||||
return path;
|
||||
} set {
|
||||
}
|
||||
set {
|
||||
path = value;
|
||||
}
|
||||
}
|
||||
|
@ -202,56 +202,41 @@ namespace LeanCloud
|
|||
});
|
||||
}
|
||||
|
||||
public Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return QueryController.FindAsync<T>(this, AVUser.CurrentUser, cancellationToken).OnSuccess(t => {
|
||||
IEnumerable<IObjectState> states = t.Result;
|
||||
return (from state in states
|
||||
select AVObject.FromState<T>(state, ClassName));
|
||||
});
|
||||
public async Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default) {
|
||||
IEnumerable<IObjectState> states = await QueryController.FindAsync(this, AVUser.CurrentUser, cancellationToken);
|
||||
return (from state in states
|
||||
select AVObject.FromState<T>(state, ClassName));
|
||||
}
|
||||
|
||||
public Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return QueryController.FirstAsync<T>(this, AVUser.CurrentUser, cancellationToken).OnSuccess(t => {
|
||||
IObjectState state = t.Result;
|
||||
return state == null ? default : AVObject.FromState<T>(state, ClassName);
|
||||
});
|
||||
public async Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default) {
|
||||
IObjectState state = await QueryController.FirstAsync<T>(this, AVUser.CurrentUser, cancellationToken);
|
||||
return state == null ? default : AVObject.FromState<T>(state, ClassName);
|
||||
}
|
||||
|
||||
public Task<T> FirstAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return FirstOrDefaultAsync(cancellationToken).OnSuccess(t =>
|
||||
{
|
||||
if (t.Result == null)
|
||||
{
|
||||
throw new AVException(AVException.ErrorCode.ObjectNotFound,
|
||||
"No results matched the query.");
|
||||
}
|
||||
return t.Result;
|
||||
});
|
||||
public async Task<T> FirstAsync(CancellationToken cancellationToken = default) {
|
||||
var result = await FirstOrDefaultAsync(cancellationToken);
|
||||
if (result == null) {
|
||||
throw new AVException(AVException.ErrorCode.ObjectNotFound,
|
||||
"No results matched the query.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task<int> CountAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
public Task<int> CountAsync(CancellationToken cancellationToken = default) {
|
||||
return QueryController.CountAsync(this, AVUser.CurrentUser, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<T> GetAsync(string objectId, CancellationToken cancellationToken)
|
||||
{
|
||||
public async Task<T> GetAsync(string objectId, CancellationToken cancellationToken) {
|
||||
AVQuery<T> singleItemQuery = new AVQuery<T>(ClassName)
|
||||
.WhereEqualTo("objectId", objectId);
|
||||
singleItemQuery = new AVQuery<T>(singleItemQuery, includes: this.includes, selectedKeys: this.selectedKeys, limit: 1);
|
||||
return singleItemQuery.FindAsync(cancellationToken).OnSuccess(t =>
|
||||
{
|
||||
var result = t.Result.FirstOrDefault();
|
||||
if (result == null)
|
||||
{
|
||||
throw new AVException(AVException.ErrorCode.ObjectNotFound,
|
||||
"Object with the given objectId not found.");
|
||||
}
|
||||
return result;
|
||||
});
|
||||
var result = await singleItemQuery.FindAsync(cancellationToken);
|
||||
var first = result.FirstOrDefault();
|
||||
if (first == null) {
|
||||
throw new AVException(AVException.ErrorCode.ObjectNotFound,
|
||||
"Object with the given objectId not found.");
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
#region CQL
|
||||
|
@ -289,22 +274,20 @@ namespace LeanCloud
|
|||
return RebuildObjectFromCloudQueryResult(queryString);
|
||||
}
|
||||
|
||||
internal static Task<IEnumerable<T>> RebuildObjectFromCloudQueryResult(string queryString) {
|
||||
internal static async Task<IEnumerable<T>> RebuildObjectFromCloudQueryResult(string queryString) {
|
||||
var command = new AVCommand {
|
||||
Path = queryString,
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: CancellationToken.None).OnSuccess(t =>
|
||||
{
|
||||
var items = t.Result.Item2["results"] as IList<object>;
|
||||
var className = t.Result.Item2["className"].ToString();
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, CancellationToken.None);
|
||||
var items = result.Item2["results"] as IList<object>;
|
||||
var className = result.Item2["className"].ToString();
|
||||
|
||||
IEnumerable<IObjectState> states = (from item in items
|
||||
select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance));
|
||||
IEnumerable<IObjectState> states = (from item in items
|
||||
select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance));
|
||||
|
||||
return (from state in states
|
||||
select AVObject.FromState<T>(state, className));
|
||||
});
|
||||
return from state in states
|
||||
select AVObject.FromState<T>(state, className);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -138,7 +138,7 @@ namespace LeanCloud {
|
|||
/// <param name="order">排序方式</param>
|
||||
/// <param name="versionChangeInterval">版本更新频率</param>
|
||||
/// <param name="updateStrategy">成绩更新策略</param>
|
||||
public static Task<AVLeaderboard> CreateLeaderboard(string statisticName,
|
||||
public static async Task<AVLeaderboard> CreateLeaderboard(string statisticName,
|
||||
AVLeaderboardOrder order = AVLeaderboardOrder.DESCENDING,
|
||||
AVLeaderboardUpdateStrategy updateStrategy = AVLeaderboardUpdateStrategy.BETTER,
|
||||
AVLeaderboardVersionChangeInterval versionChangeInterval = AVLeaderboardVersionChangeInterval.WEEK) {
|
||||
|
@ -157,14 +157,13 @@ namespace LeanCloud {
|
|||
Method = HttpMethod.Post,
|
||||
Content = data
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
try {
|
||||
var leaderboard = Parse(t.Result.Item2);
|
||||
return leaderboard;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
try {
|
||||
var leaderboard = Parse(result.Item2);
|
||||
return leaderboard;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -195,7 +194,7 @@ namespace LeanCloud {
|
|||
/// <param name="user">用户</param>
|
||||
/// <param name="statistics">成绩</param>
|
||||
/// <param name="overwrite">是否强行覆盖</param>
|
||||
public static Task<List<AVStatistic>> UpdateStatistics(AVUser user, Dictionary<string, double> statistics, bool overwrite = false) {
|
||||
public static async Task<List<AVStatistic>> UpdateStatistics(AVUser user, Dictionary<string, double> statistics, bool overwrite = false) {
|
||||
if (user == null) {
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
@ -219,18 +218,17 @@ namespace LeanCloud {
|
|||
Method = HttpMethod.Post,
|
||||
Content = data
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
try {
|
||||
List<AVStatistic> statisticList = new List<AVStatistic>();
|
||||
List<object> list = t.Result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
return statisticList;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
try {
|
||||
List<AVStatistic> statisticList = new List<AVStatistic>();
|
||||
List<object> list = result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
});
|
||||
return statisticList;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -239,7 +237,7 @@ namespace LeanCloud {
|
|||
/// <returns>成绩列表</returns>
|
||||
/// <param name="user">用户</param>
|
||||
/// <param name="statisticNames">名称列表</param>
|
||||
public static Task<List<AVStatistic>> GetStatistics(AVUser user, List<string> statisticNames = null) {
|
||||
public static async Task<List<AVStatistic>> GetStatistics(AVUser user, List<string> statisticNames = null) {
|
||||
if (user == null) {
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
@ -252,18 +250,17 @@ namespace LeanCloud {
|
|||
Path = path,
|
||||
Method = HttpMethod.Post
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
try {
|
||||
List<AVStatistic> statisticList = new List<AVStatistic>();
|
||||
List<object> list = t.Result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
return statisticList;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
try {
|
||||
List<AVStatistic> statisticList = new List<AVStatistic>();
|
||||
List<object> list = result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
});
|
||||
return statisticList;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -271,7 +268,7 @@ namespace LeanCloud {
|
|||
/// </summary>
|
||||
/// <param name="user">用户</param>
|
||||
/// <param name="statisticNames">名称列表</param>
|
||||
public static Task DeleteStatistics(AVUser user, List<string> statisticNames) {
|
||||
public static async Task DeleteStatistics(AVUser user, List<string> statisticNames) {
|
||||
if (user == null) {
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
@ -285,7 +282,7 @@ namespace LeanCloud {
|
|||
Path = path,
|
||||
Method = HttpMethod.Delete,
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -294,21 +291,20 @@ namespace LeanCloud {
|
|||
/// <returns>排行榜归档列表</returns>
|
||||
/// <param name="skip">跳过数量</param>
|
||||
/// <param name="limit">分页数量</param>
|
||||
public Task<List<AVLeaderboardArchive>> GetArchives(int skip = 0, int limit = 10) {
|
||||
public async Task<List<AVLeaderboardArchive>> GetArchives(int skip = 0, int limit = 10) {
|
||||
var path = string.Format("leaderboard/leaderboards/{0}/archives", StatisticName);
|
||||
path = string.Format("{0}?skip={1}&limit={2}", path, skip, limit);
|
||||
var command = new AVCommand {
|
||||
Path = path,
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
List<AVLeaderboardArchive> archives = new List<AVLeaderboardArchive>();
|
||||
List<object> list = t.Result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
archives.Add(AVLeaderboardArchive.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
return archives;
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
List<AVLeaderboardArchive> archives = new List<AVLeaderboardArchive>();
|
||||
List<object> list = result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
archives.Add(AVLeaderboardArchive.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
return archives;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -336,7 +332,7 @@ namespace LeanCloud {
|
|||
return GetResults(AVUser.CurrentUser, version, skip, limit, selectUserKeys, includeStatistics);
|
||||
}
|
||||
|
||||
Task<List<AVRanking>> GetResults(AVUser user,
|
||||
async Task<List<AVRanking>> GetResults(AVUser user,
|
||||
int version, int skip, int limit,
|
||||
List<string> selectUserKeys,
|
||||
List<string> includeStatistics) {
|
||||
|
@ -361,18 +357,17 @@ namespace LeanCloud {
|
|||
Path = path,
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
try {
|
||||
List<AVRanking> rankingList = new List<AVRanking>();
|
||||
List<object> list = t.Result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
rankingList.Add(AVRanking.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
return rankingList;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
try {
|
||||
List<AVRanking> rankingList = new List<AVRanking>();
|
||||
List<object> list = result.Item2["results"] as List<object>;
|
||||
foreach (object obj in list) {
|
||||
rankingList.Add(AVRanking.Parse(obj as IDictionary<string, object>));
|
||||
}
|
||||
});
|
||||
return rankingList;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -380,14 +375,13 @@ namespace LeanCloud {
|
|||
/// </summary>
|
||||
/// <returns>排行榜对象</returns>
|
||||
/// <param name="updateStrategy">更新策略</param>
|
||||
public Task<AVLeaderboard> UpdateUpdateStrategy(AVLeaderboardUpdateStrategy updateStrategy) {
|
||||
public async Task<AVLeaderboard> UpdateUpdateStrategy(AVLeaderboardUpdateStrategy updateStrategy) {
|
||||
var data = new Dictionary<string, object> {
|
||||
{ "updateStrategy", updateStrategy.ToString().ToLower() }
|
||||
};
|
||||
return Update(data).OnSuccess(t => {
|
||||
UpdateStrategy = (AVLeaderboardUpdateStrategy)Enum.Parse(typeof(AVLeaderboardUpdateStrategy), t.Result["updateStrategy"].ToString().ToUpper());
|
||||
return this;
|
||||
});
|
||||
var result = await Update(data);
|
||||
UpdateStrategy = (AVLeaderboardUpdateStrategy)Enum.Parse(typeof(AVLeaderboardUpdateStrategy), result["updateStrategy"].ToString().ToUpper());
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -395,67 +389,63 @@ namespace LeanCloud {
|
|||
/// </summary>
|
||||
/// <returns>排行榜对象</returns>
|
||||
/// <param name="versionChangeInterval">版本更新频率</param>
|
||||
public Task<AVLeaderboard> UpdateVersionChangeInterval(AVLeaderboardVersionChangeInterval versionChangeInterval) {
|
||||
public async Task<AVLeaderboard> UpdateVersionChangeInterval(AVLeaderboardVersionChangeInterval versionChangeInterval) {
|
||||
var data = new Dictionary<string, object> {
|
||||
{ "versionChangeInterval", versionChangeInterval.ToString().ToLower() }
|
||||
};
|
||||
return Update(data).OnSuccess(t => {
|
||||
VersionChangeInterval = (AVLeaderboardVersionChangeInterval)Enum.Parse(typeof(AVLeaderboardVersionChangeInterval), t.Result["versionChangeInterval"].ToString().ToUpper());
|
||||
return this;
|
||||
});
|
||||
var result = await Update(data);
|
||||
VersionChangeInterval = (AVLeaderboardVersionChangeInterval)Enum.Parse(typeof(AVLeaderboardVersionChangeInterval), result["versionChangeInterval"].ToString().ToUpper());
|
||||
return this;
|
||||
}
|
||||
|
||||
Task<IDictionary<string,object>> Update(Dictionary<string, object> data) {
|
||||
async Task<IDictionary<string,object>> Update(Dictionary<string, object> data) {
|
||||
var path = string.Format("leaderboard/leaderboards/{0}", StatisticName);
|
||||
var command = new AVCommand {
|
||||
Path = path,
|
||||
Method = HttpMethod.Put,
|
||||
Content = data
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
return t.Result.Item2;
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
return result.Item2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拉取排行榜数据
|
||||
/// </summary>
|
||||
/// <returns>排行榜对象</returns>
|
||||
public Task<AVLeaderboard> Fetch() {
|
||||
public async Task<AVLeaderboard> Fetch() {
|
||||
var path = string.Format("leaderboard/leaderboards/{0}", StatisticName);
|
||||
var command = new AVCommand {
|
||||
Path = path,
|
||||
Method = HttpMethod.Get
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
try {
|
||||
// 反序列化 Leaderboard 对象
|
||||
var leaderboard = Parse(t.Result.Item2);
|
||||
return leaderboard;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
try {
|
||||
// 反序列化 Leaderboard 对象
|
||||
var leaderboard = Parse(result.Item2);
|
||||
return leaderboard;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置排行榜
|
||||
/// </summary>
|
||||
/// <returns>排行榜对象</returns>
|
||||
public Task<AVLeaderboard> Reset() {
|
||||
public async Task<AVLeaderboard> Reset() {
|
||||
var path = string.Format("leaderboard/leaderboards/{0}/incrementVersion", StatisticName);
|
||||
var command = new AVCommand {
|
||||
Path = path,
|
||||
Method = HttpMethod.Put
|
||||
};
|
||||
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => {
|
||||
try {
|
||||
Init(t.Result.Item2);
|
||||
return this;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
});
|
||||
var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
|
||||
try {
|
||||
Init(result.Item2);
|
||||
return this;
|
||||
} catch (Exception e) {
|
||||
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
Loading…
Reference in New Issue