* AWSUploader.cs: chore: await/async

* AVFile.cs:
* AVCloud.cs:
* AVQuery.cs:
* AVLeaderboard.cs:
* QiniuUploader.cs:
* QCloudUploader.cs:
oneRain 2019-09-06 12:24:50 +08:00
parent f3ed814d96
commit aabd25d2e8
7 changed files with 201 additions and 242 deletions

View File

@ -8,15 +8,13 @@ using System.Net.Http.Headers;
namespace LeanCloud.Storage.Internal { namespace LeanCloud.Storage.Internal {
internal class AWSUploader : IFileUploader { 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) { CancellationToken cancellationToken) {
var uploadUrl = fileToken["upload_url"].ToString(); var uploadUrl = fileToken["upload_url"].ToString();
state.ObjectId = fileToken["objectId"].ToString(); state.ObjectId = fileToken["objectId"].ToString();
string url = fileToken["url"] as string; string url = fileToken["url"] as string;
state.Url = new Uri(url, UriKind.Absolute); state.Url = new Uri(url, UriKind.Absolute);
return PutFile(state, uploadUrl, dataStream).OnSuccess(s => { return await PutFile(state, uploadUrl, dataStream);
return s.Result;
});
} }
internal async Task<FileState> PutFile(FileState state, string uploadUrl, Stream dataStream) { internal async Task<FileState> PutFile(FileState state, string uploadUrl, Stream dataStream) {

View File

@ -19,26 +19,28 @@ namespace LeanCloud.Storage.Internal {
bool done; bool done;
private long sliceSize = (long)CommonSize.KB512; 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; fileState = state;
data = dataStream; data = dataStream;
uploadUrl = fileToken["upload_url"].ToString(); uploadUrl = fileToken["upload_url"].ToString();
token = fileToken["token"].ToString(); token = fileToken["token"].ToString();
fileState.ObjectId = fileToken["objectId"].ToString(); fileState.ObjectId = fileToken["objectId"].ToString();
bucket = fileToken["bucket"].ToString(); bucket = fileToken["bucket"].ToString();
var result = await FileSlice(cancellationToken);
return FileSlice(cancellationToken).OnSuccess(t => { if (done) {
if (done) return Task<FileState>.FromResult(state); return state;
var response = t.Result.Item2; }
var resumeData = response["data"] as IDictionary<string, object>; var response = result.Item2;
if (resumeData.ContainsKey("access_url")) return Task<FileState>.FromResult(state); var resumeData = response["data"] as IDictionary<string, object>;
var sliceSession = resumeData["session"].ToString(); if (resumeData.ContainsKey("access_url")) {
var sliceOffset = long.Parse(resumeData["offset"].ToString()); return state;
return UploadSlice(sliceSession, sliceOffset, dataStream, progress, cancellationToken); }
}).Unwrap(); 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, string sessionId,
long offset, long offset,
Stream dataStream, Stream dataStream,
@ -55,21 +57,20 @@ namespace LeanCloud.Storage.Internal {
} }
if (offset == dataLength) { if (offset == dataLength) {
return Task.FromResult<FileState>(fileState); return fileState;
} }
var sliceFile = GetNextBinary(offset, dataStream); var sliceFile = GetNextBinary(offset, dataStream);
return ExcuteUpload(sessionId, offset, sliceFile, cancellationToken).OnSuccess(_ => { var result = await ExcuteUpload(sessionId, offset, sliceFile, cancellationToken);
offset += sliceFile.Length; offset += sliceFile.Length;
if (offset == dataLength) { if (offset == dataLength) {
done = true; done = true;
return Task.FromResult<FileState>(fileState); return fileState;
} }
var response = _.Result.Item2; var response = result.Item2;
var resumeData = response["data"] as IDictionary<string, object>; var resumeData = response["data"] as IDictionary<string, object>;
var sliceSession = resumeData["session"].ToString(); var sliceSession = resumeData["session"].ToString();
return UploadSlice(sliceSession, offset, dataStream, progress, cancellationToken); return await UploadSlice(sliceSession, offset, dataStream, progress, cancellationToken);
}).Unwrap();
} }
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> ExcuteUpload(string sessionId, long offset, byte[] sliceFile, CancellationToken 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); 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(); SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
var body = new Dictionary<string, object>(); var body = new Dictionary<string, object>();
if (data.Length <= (long)CommonSize.KB512) { if (data.Length <= (long)CommonSize.KB512) {
body.Add("op", "upload"); body.Add("op", "upload");
body.Add("sha", HexStringFromBytes(sha1.ComputeHash(data))); body.Add("sha", HexStringFromBytes(sha1.ComputeHash(data)));
var wholeFile = GetNextBinary(0, data); var wholeFile = GetNextBinary(0, data);
return PostToQCloud(body, wholeFile, cancellationToken).OnSuccess(_ => { var result = await PostToQCloud(body, wholeFile, cancellationToken);
if (_.Result.Item1 == HttpStatusCode.OK) { if (result.Item1 == HttpStatusCode.OK) {
done = true; done = true;
} }
return _.Result; return result;
});
} else { } else {
body.Add("op", "upload_slice"); body.Add("op", "upload_slice");
body.Add("filesize", data.Length); body.Add("filesize", data.Length);
@ -101,7 +101,7 @@ namespace LeanCloud.Storage.Internal {
body.Add("slice_size", (long)CommonSize.KB512); body.Add("slice_size", (long)CommonSize.KB512);
} }
return PostToQCloud(body, null, cancellationToken); return await PostToQCloud(body, null, cancellationToken);
} }
public static string HexStringFromBytes(byte[] bytes) { public static string HexStringFromBytes(byte[] bytes) {
var sb = new StringBuilder(); var sb = new StringBuilder();

View File

@ -22,16 +22,15 @@ namespace LeanCloud.Storage.Internal {
internal static string UP_HOST = "https://up.qbox.me"; internal static string UP_HOST = "https://up.qbox.me";
private readonly object mutex = new object(); 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.frozenData = dataStream;
state.CloudName = fileToken["key"] as string; state.CloudName = fileToken["key"] as string;
MergeFromJSON(state, fileToken); MergeFromJSON(state, fileToken);
return UploadNextChunk(state, dataStream, string.Empty, 0, progress).OnSuccess(_ => { await UploadNextChunk(state, dataStream, string.Empty, 0, progress);
return state; 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 totalSize = dataStream.Length;
var remainingSize = totalSize - state.completed; var remainingSize = totalSize - state.completed;
@ -43,29 +42,27 @@ namespace LeanCloud.Storage.Internal {
} }
} }
if (state.completed == totalSize) { if (state.completed == totalSize) {
return QiniuMakeFile(state, state.frozenData, state.token, state.CloudName, totalSize, state.block_ctxes.ToArray(), CancellationToken.None); await QiniuMakeFile(state, state.frozenData, state.token, state.CloudName, totalSize, state.block_ctxes.ToArray(), CancellationToken.None);
} } else if (state.completed % BLOCKSIZE == 0) {
if (state.completed % BLOCKSIZE == 0) {
var firstChunkBinary = GetChunkBinary(state.completed, dataStream); var firstChunkBinary = GetChunkBinary(state.completed, dataStream);
var blockSize = remainingSize > BLOCKSIZE ? BLOCKSIZE : remainingSize; var blockSize = remainingSize > BLOCKSIZE ? BLOCKSIZE : remainingSize;
return MakeBlock(state, firstChunkBinary, blockSize).OnSuccess(t => { var result = await MakeBlock(state, firstChunkBinary, blockSize);
var dict = t.Result; var dict = result;
var ctx = dict["ctx"].ToString(); var ctx = dict["ctx"].ToString();
offset = long.Parse(dict["offset"].ToString()); offset = long.Parse(dict["offset"].ToString());
var host = dict["host"].ToString(); var host = dict["host"].ToString();
state.completed += firstChunkBinary.Length; state.completed += firstChunkBinary.Length;
if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) { if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) {
state.block_ctxes.Add(ctx); state.block_ctxes.Add(ctx);
} }
return UploadNextChunk(state, dataStream, ctx, offset, progress); await UploadNextChunk(state, dataStream, ctx, offset, progress);
}).Unwrap(); } else {
} var chunkBinary = GetChunkBinary(state.completed, dataStream);
var chunkBinary = GetChunkBinary(state.completed, dataStream); var result = await PutChunk(state, chunkBinary, context, offset);
return PutChunk(state, chunkBinary, context, offset).OnSuccess(t => { var dict = result;
var dict = t.Result;
var ctx = dict["ctx"].ToString(); var ctx = dict["ctx"].ToString();
offset = long.Parse(dict["offset"].ToString()); offset = long.Parse(dict["offset"].ToString());
@ -74,9 +71,8 @@ namespace LeanCloud.Storage.Internal {
if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) { if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize) {
state.block_ctxes.Add(ctx); state.block_ctxes.Add(ctx);
} }
await UploadNextChunk(state, dataStream, ctx, offset, progress);
return UploadNextChunk(state, dataStream, ctx, offset, progress); }
}).Unwrap();
} }
byte[] GetChunkBinary(long completed, Stream dataStream) { byte[] GetChunkBinary(long completed, Stream dataStream) {

View File

@ -220,19 +220,18 @@ namespace LeanCloud {
/// <param name="height">captcha image height.</param> /// <param name="height">captcha image height.</param>
/// <param name="cancellationToken">CancellationToken.</param> /// <param name="cancellationToken">CancellationToken.</param>
/// <returns>an instance of Captcha.</returns> /// <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 path = string.Format("requestCaptcha?width={0}&height={1}", width, height);
var command = new AVCommand { var command = new AVCommand {
Path = $"requestCaptcha?width={width}&height={height}", Path = $"requestCaptcha?width={width}&height={height}",
Method = HttpMethod.Get Method = HttpMethod.Get
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary<string, object>; var decoded = AVDecoder.Instance.Decode(result.Item2) as IDictionary<string, object>;
return new Captcha() { return new Captcha {
Token = decoded["captcha_token"] as string, Token = decoded["captcha_token"] as string,
Url = decoded["captcha_url"] as string, Url = decoded["captcha_url"] as string,
}; };
});
} }
/// <summary> /// <summary>
@ -242,7 +241,7 @@ namespace LeanCloud {
/// <param name="code">User's input of this captcha.</param> /// <param name="code">User's input of this captcha.</param>
/// <param name="cancellationToken">CancellationToken.</param> /// <param name="cancellationToken">CancellationToken.</param>
/// <returns></returns> /// <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> { var data = new Dictionary<string, object> {
{ "captcha_token", token }, { "captcha_token", token },
{ "captcha_code", code }, { "captcha_code", code },
@ -252,11 +251,11 @@ namespace LeanCloud {
Method = HttpMethod.Post, Method = HttpMethod.Post,
Content = data Content = data
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).ContinueWith(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
if (!t.Result.Item2.ContainsKey("validate_token")) if (result.Item2.TryGetValue("validate_token", out object tokenObj)) {
throw new KeyNotFoundException("validate_token"); return tokenObj as string;
return t.Result.Item2["validate_token"] as string; }
}); throw new KeyNotFoundException("validate_token");
} }
/// <summary> /// <summary>
@ -264,16 +263,15 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <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 { var command = new AVCommand {
Path = $"statistics/apps/{AVClient.CurrentConfiguration.ApplicationId}/sendPolicy", Path = $"statistics/apps/{AVClient.CurrentConfiguration.ApplicationId}/sendPolicy",
Method = HttpMethod.Get Method = HttpMethod.Get
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => { var data = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var settings = t.Result.Item2; var settings = data.Item2;
var CloudParameters = settings["parameters"] as IDictionary<string, object>; var CloudParameters = settings["parameters"] as IDictionary<string, object>;
return CloudParameters; return CloudParameters;
});
} }
public class RealtimeSignature { public class RealtimeSignature {
@ -283,7 +281,7 @@ namespace LeanCloud {
public string Signature { internal set; get; } 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 { var command = new AVCommand {
Path = "rtm/sign", Path = "rtm/sign",
Method = HttpMethod.Post, Method = HttpMethod.Post,
@ -291,15 +289,14 @@ namespace LeanCloud {
{ "session_token", AVUser.CurrentUser?.SessionToken } { "session_token", AVUser.CurrentUser?.SessionToken }
} }
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var body = t.Result.Item2; var body = result.Item2;
return new RealtimeSignature() { return new RealtimeSignature() {
Nonce = body["nonce"] as string, Nonce = body["nonce"] as string,
Timestamp = (long)body["timestamp"], Timestamp = (long)body["timestamp"],
ClientId = body["client_id"] as string, ClientId = body["client_id"] as string,
Signature = body["signature"] as string, Signature = body["signature"] as string,
}; };
});
} }
/// <summary> /// <summary>

View File

@ -265,11 +265,8 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <param name="progress">The progress callback.</param> /// <param name="progress">The progress callback.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
public Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress = null, CancellationToken cancellationToken = default) { public async Task SaveAsync(IProgress<AVUploadProgressEventArgs> progress = null, CancellationToken cancellationToken = default) {
return FileController.SaveAsync(state, dataStream, progress, cancellationToken) state = await FileController.SaveAsync(state, dataStream, progress, cancellationToken);
.OnSuccess(t => {
state = t.Result;
});
} }
#endregion #endregion
@ -320,11 +317,9 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <remarks>获取之后并没有实际执行下载只是加载了文件的元信息以及物理地址Url /// <remarks>获取之后并没有实际执行下载只是加载了文件的元信息以及物理地址Url
/// </remarks> /// </remarks>
public static Task<AVFile> GetFileWithObjectIdAsync(string objectId, CancellationToken cancellationToken = default) { public static async Task<AVFile> GetFileWithObjectIdAsync(string objectId, CancellationToken cancellationToken = default) {
return FileController.GetAsync(objectId, cancellationToken).OnSuccess(_ => { var fileState = await FileController.GetAsync(objectId, cancellationToken);
var filestate = _.Result; return new AVFile(fileState);
return new AVFile(filestate);
});
} }
public static AVFile CreateWithoutData(string objectId) { public static AVFile CreateWithoutData(string objectId) {

View File

@ -10,8 +10,7 @@ using System.Text.RegularExpressions;
using Newtonsoft.Json; using Newtonsoft.Json;
using LeanCloud.Storage.Internal; using LeanCloud.Storage.Internal;
namespace LeanCloud namespace LeanCloud {
{
public class AVQuery<T> where T : AVObject { public class AVQuery<T> where T : AVObject {
public string ClassName { public string ClassName {
get; internal set; get; internal set;
@ -24,7 +23,8 @@ namespace LeanCloud
return $"classes/{Uri.EscapeDataString(ClassName)}"; return $"classes/{Uri.EscapeDataString(ClassName)}";
} }
return path; return path;
} set { }
set {
path = value; path = value;
} }
} }
@ -202,56 +202,41 @@ namespace LeanCloud
}); });
} }
public Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default) public async Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default) {
{ IEnumerable<IObjectState> states = await QueryController.FindAsync(this, AVUser.CurrentUser, cancellationToken);
return QueryController.FindAsync<T>(this, AVUser.CurrentUser, cancellationToken).OnSuccess(t => { return (from state in states
IEnumerable<IObjectState> states = t.Result; select AVObject.FromState<T>(state, ClassName));
return (from state in states
select AVObject.FromState<T>(state, ClassName));
});
} }
public Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default) public async Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default) {
{ IObjectState state = await QueryController.FirstAsync<T>(this, AVUser.CurrentUser, cancellationToken);
return QueryController.FirstAsync<T>(this, AVUser.CurrentUser, cancellationToken).OnSuccess(t => { return state == null ? default : AVObject.FromState<T>(state, ClassName);
IObjectState state = t.Result;
return state == null ? default : AVObject.FromState<T>(state, ClassName);
});
} }
public Task<T> FirstAsync(CancellationToken cancellationToken = default) public async Task<T> FirstAsync(CancellationToken cancellationToken = default) {
{ var result = await FirstOrDefaultAsync(cancellationToken);
return FirstOrDefaultAsync(cancellationToken).OnSuccess(t => if (result == null) {
{ throw new AVException(AVException.ErrorCode.ObjectNotFound,
if (t.Result == null) "No results matched the query.");
{ }
throw new AVException(AVException.ErrorCode.ObjectNotFound, return result;
"No results matched the query.");
}
return t.Result;
});
} }
public Task<int> CountAsync(CancellationToken cancellationToken = default) public Task<int> CountAsync(CancellationToken cancellationToken = default) {
{
return QueryController.CountAsync(this, AVUser.CurrentUser, cancellationToken); 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) AVQuery<T> singleItemQuery = new AVQuery<T>(ClassName)
.WhereEqualTo("objectId", objectId); .WhereEqualTo("objectId", objectId);
singleItemQuery = new AVQuery<T>(singleItemQuery, includes: this.includes, selectedKeys: this.selectedKeys, limit: 1); singleItemQuery = new AVQuery<T>(singleItemQuery, includes: this.includes, selectedKeys: this.selectedKeys, limit: 1);
return singleItemQuery.FindAsync(cancellationToken).OnSuccess(t => var result = await singleItemQuery.FindAsync(cancellationToken);
{ var first = result.FirstOrDefault();
var result = t.Result.FirstOrDefault(); if (first == null) {
if (result == null) throw new AVException(AVException.ErrorCode.ObjectNotFound,
{ "Object with the given objectId not found.");
throw new AVException(AVException.ErrorCode.ObjectNotFound, }
"Object with the given objectId not found."); return first;
}
return result;
});
} }
#region CQL #region CQL
@ -289,22 +274,20 @@ namespace LeanCloud
return RebuildObjectFromCloudQueryResult(queryString); return RebuildObjectFromCloudQueryResult(queryString);
} }
internal static Task<IEnumerable<T>> RebuildObjectFromCloudQueryResult(string queryString) { internal static async Task<IEnumerable<T>> RebuildObjectFromCloudQueryResult(string queryString) {
var command = new AVCommand { var command = new AVCommand {
Path = queryString, Path = queryString,
Method = HttpMethod.Get Method = HttpMethod.Get
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: CancellationToken.None).OnSuccess(t => var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, CancellationToken.None);
{ var items = result.Item2["results"] as IList<object>;
var items = t.Result.Item2["results"] as IList<object>; var className = result.Item2["className"].ToString();
var className = t.Result.Item2["className"].ToString();
IEnumerable<IObjectState> states = (from item in items IEnumerable<IObjectState> states = (from item in items
select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance)); select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance));
return (from state in states return from state in states
select AVObject.FromState<T>(state, className)); select AVObject.FromState<T>(state, className);
});
} }
#endregion #endregion

View File

@ -138,7 +138,7 @@ namespace LeanCloud {
/// <param name="order">排序方式</param> /// <param name="order">排序方式</param>
/// <param name="versionChangeInterval">版本更新频率</param> /// <param name="versionChangeInterval">版本更新频率</param>
/// <param name="updateStrategy">成绩更新策略</param> /// <param name="updateStrategy">成绩更新策略</param>
public static Task<AVLeaderboard> CreateLeaderboard(string statisticName, public static async Task<AVLeaderboard> CreateLeaderboard(string statisticName,
AVLeaderboardOrder order = AVLeaderboardOrder.DESCENDING, AVLeaderboardOrder order = AVLeaderboardOrder.DESCENDING,
AVLeaderboardUpdateStrategy updateStrategy = AVLeaderboardUpdateStrategy.BETTER, AVLeaderboardUpdateStrategy updateStrategy = AVLeaderboardUpdateStrategy.BETTER,
AVLeaderboardVersionChangeInterval versionChangeInterval = AVLeaderboardVersionChangeInterval.WEEK) { AVLeaderboardVersionChangeInterval versionChangeInterval = AVLeaderboardVersionChangeInterval.WEEK) {
@ -157,14 +157,13 @@ namespace LeanCloud {
Method = HttpMethod.Post, Method = HttpMethod.Post,
Content = data Content = data
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
try { try {
var leaderboard = Parse(t.Result.Item2); var leaderboard = Parse(result.Item2);
return leaderboard; return leaderboard;
} catch (Exception e) { } catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
} }
});
} }
/// <summary> /// <summary>
@ -195,7 +194,7 @@ namespace LeanCloud {
/// <param name="user">用户</param> /// <param name="user">用户</param>
/// <param name="statistics">成绩</param> /// <param name="statistics">成绩</param>
/// <param name="overwrite">是否强行覆盖</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) { if (user == null) {
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
} }
@ -219,18 +218,17 @@ namespace LeanCloud {
Method = HttpMethod.Post, Method = HttpMethod.Post,
Content = data Content = data
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
try { try {
List<AVStatistic> statisticList = new List<AVStatistic>(); List<AVStatistic> statisticList = new List<AVStatistic>();
List<object> list = t.Result.Item2["results"] as List<object>; List<object> list = result.Item2["results"] as List<object>;
foreach (object obj in list) { foreach (object obj in list) {
statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>)); statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>));
}
return statisticList;
} catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
} }
}); return statisticList;
} catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
}
} }
/// <summary> /// <summary>
@ -239,7 +237,7 @@ namespace LeanCloud {
/// <returns>成绩列表</returns> /// <returns>成绩列表</returns>
/// <param name="user">用户</param> /// <param name="user">用户</param>
/// <param name="statisticNames">名称列表</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) { if (user == null) {
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
} }
@ -252,18 +250,17 @@ namespace LeanCloud {
Path = path, Path = path,
Method = HttpMethod.Post Method = HttpMethod.Post
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
try { try {
List<AVStatistic> statisticList = new List<AVStatistic>(); List<AVStatistic> statisticList = new List<AVStatistic>();
List<object> list = t.Result.Item2["results"] as List<object>; List<object> list = result.Item2["results"] as List<object>;
foreach (object obj in list) { foreach (object obj in list) {
statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>)); statisticList.Add(AVStatistic.Parse(obj as IDictionary<string, object>));
}
return statisticList;
} catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
} }
}); return statisticList;
} catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
}
} }
/// <summary> /// <summary>
@ -271,7 +268,7 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <param name="user">用户</param> /// <param name="user">用户</param>
/// <param name="statisticNames">名称列表</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) { if (user == null) {
throw new ArgumentNullException(nameof(user)); throw new ArgumentNullException(nameof(user));
} }
@ -285,7 +282,7 @@ namespace LeanCloud {
Path = path, Path = path,
Method = HttpMethod.Delete, Method = HttpMethod.Delete,
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command); await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
} }
/// <summary> /// <summary>
@ -294,21 +291,20 @@ namespace LeanCloud {
/// <returns>排行榜归档列表</returns> /// <returns>排行榜归档列表</returns>
/// <param name="skip">跳过数量</param> /// <param name="skip">跳过数量</param>
/// <param name="limit">分页数量</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); var path = string.Format("leaderboard/leaderboards/{0}/archives", StatisticName);
path = string.Format("{0}?skip={1}&limit={2}", path, skip, limit); path = string.Format("{0}?skip={1}&limit={2}", path, skip, limit);
var command = new AVCommand { var command = new AVCommand {
Path = path, Path = path,
Method = HttpMethod.Get Method = HttpMethod.Get
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
List<AVLeaderboardArchive> archives = new List<AVLeaderboardArchive>(); List<AVLeaderboardArchive> archives = new List<AVLeaderboardArchive>();
List<object> list = t.Result.Item2["results"] as List<object>; List<object> list = result.Item2["results"] as List<object>;
foreach (object obj in list) { foreach (object obj in list) {
archives.Add(AVLeaderboardArchive.Parse(obj as IDictionary<string, object>)); archives.Add(AVLeaderboardArchive.Parse(obj as IDictionary<string, object>));
} }
return archives; return archives;
});
} }
/// <summary> /// <summary>
@ -336,7 +332,7 @@ namespace LeanCloud {
return GetResults(AVUser.CurrentUser, version, skip, limit, selectUserKeys, includeStatistics); 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, int version, int skip, int limit,
List<string> selectUserKeys, List<string> selectUserKeys,
List<string> includeStatistics) { List<string> includeStatistics) {
@ -361,18 +357,17 @@ namespace LeanCloud {
Path = path, Path = path,
Method = HttpMethod.Get Method = HttpMethod.Get
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
try { try {
List<AVRanking> rankingList = new List<AVRanking>(); List<AVRanking> rankingList = new List<AVRanking>();
List<object> list = t.Result.Item2["results"] as List<object>; List<object> list = result.Item2["results"] as List<object>;
foreach (object obj in list) { foreach (object obj in list) {
rankingList.Add(AVRanking.Parse(obj as IDictionary<string, object>)); rankingList.Add(AVRanking.Parse(obj as IDictionary<string, object>));
}
return rankingList;
} catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
} }
}); return rankingList;
} catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
}
} }
/// <summary> /// <summary>
@ -380,14 +375,13 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <returns>排行榜对象</returns> /// <returns>排行榜对象</returns>
/// <param name="updateStrategy">更新策略</param> /// <param name="updateStrategy">更新策略</param>
public Task<AVLeaderboard> UpdateUpdateStrategy(AVLeaderboardUpdateStrategy updateStrategy) { public async Task<AVLeaderboard> UpdateUpdateStrategy(AVLeaderboardUpdateStrategy updateStrategy) {
var data = new Dictionary<string, object> { var data = new Dictionary<string, object> {
{ "updateStrategy", updateStrategy.ToString().ToLower() } { "updateStrategy", updateStrategy.ToString().ToLower() }
}; };
return Update(data).OnSuccess(t => { var result = await Update(data);
UpdateStrategy = (AVLeaderboardUpdateStrategy)Enum.Parse(typeof(AVLeaderboardUpdateStrategy), t.Result["updateStrategy"].ToString().ToUpper()); UpdateStrategy = (AVLeaderboardUpdateStrategy)Enum.Parse(typeof(AVLeaderboardUpdateStrategy), result["updateStrategy"].ToString().ToUpper());
return this; return this;
});
} }
/// <summary> /// <summary>
@ -395,67 +389,63 @@ namespace LeanCloud {
/// </summary> /// </summary>
/// <returns>排行榜对象</returns> /// <returns>排行榜对象</returns>
/// <param name="versionChangeInterval">版本更新频率</param> /// <param name="versionChangeInterval">版本更新频率</param>
public Task<AVLeaderboard> UpdateVersionChangeInterval(AVLeaderboardVersionChangeInterval versionChangeInterval) { public async Task<AVLeaderboard> UpdateVersionChangeInterval(AVLeaderboardVersionChangeInterval versionChangeInterval) {
var data = new Dictionary<string, object> { var data = new Dictionary<string, object> {
{ "versionChangeInterval", versionChangeInterval.ToString().ToLower() } { "versionChangeInterval", versionChangeInterval.ToString().ToLower() }
}; };
return Update(data).OnSuccess(t => { var result = await Update(data);
VersionChangeInterval = (AVLeaderboardVersionChangeInterval)Enum.Parse(typeof(AVLeaderboardVersionChangeInterval), t.Result["versionChangeInterval"].ToString().ToUpper()); VersionChangeInterval = (AVLeaderboardVersionChangeInterval)Enum.Parse(typeof(AVLeaderboardVersionChangeInterval), result["versionChangeInterval"].ToString().ToUpper());
return this; 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 path = string.Format("leaderboard/leaderboards/{0}", StatisticName);
var command = new AVCommand { var command = new AVCommand {
Path = path, Path = path,
Method = HttpMethod.Put, Method = HttpMethod.Put,
Content = data Content = data
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
return t.Result.Item2; return result.Item2;
});
} }
/// <summary> /// <summary>
/// 拉取排行榜数据 /// 拉取排行榜数据
/// </summary> /// </summary>
/// <returns>排行榜对象</returns> /// <returns>排行榜对象</returns>
public Task<AVLeaderboard> Fetch() { public async Task<AVLeaderboard> Fetch() {
var path = string.Format("leaderboard/leaderboards/{0}", StatisticName); var path = string.Format("leaderboard/leaderboards/{0}", StatisticName);
var command = new AVCommand { var command = new AVCommand {
Path = path, Path = path,
Method = HttpMethod.Get Method = HttpMethod.Get
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
try { try {
// 反序列化 Leaderboard 对象 // 反序列化 Leaderboard 对象
var leaderboard = Parse(t.Result.Item2); var leaderboard = Parse(result.Item2);
return leaderboard; return leaderboard;
} catch (Exception e) { } catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
} }
});
} }
/// <summary> /// <summary>
/// 重置排行榜 /// 重置排行榜
/// </summary> /// </summary>
/// <returns>排行榜对象</returns> /// <returns>排行榜对象</returns>
public Task<AVLeaderboard> Reset() { public async Task<AVLeaderboard> Reset() {
var path = string.Format("leaderboard/leaderboards/{0}/incrementVersion", StatisticName); var path = string.Format("leaderboard/leaderboards/{0}/incrementVersion", StatisticName);
var command = new AVCommand { var command = new AVCommand {
Path = path, Path = path,
Method = HttpMethod.Put Method = HttpMethod.Put
}; };
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t => { var result = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
try { try {
Init(t.Result.Item2); Init(result.Item2);
return this; return this;
} catch (Exception e) { } catch (Exception e) {
throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message); throw new AVException(AVException.ErrorCode.InvalidJSON, e.Message);
} }
});
} }
/// <summary> /// <summary>