using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using LeanCloud.Storage.Internal; namespace LeanCloud { /// /// The AVCloud class provides methods for interacting with LeanCloud Cloud Functions. /// /// /// For example, this sample code calls the /// "validateGame" Cloud Function and calls processResponse if the call succeeded /// and handleError if it failed. /// /// /// var result = /// await AVCloud.CallFunctionAsync<IDictionary<string, object>>("validateGame", parameters); /// /// public static class AVCloud { internal static IAVCloudCodeController CloudCodeController { get { return AVPlugins.Instance.CloudCodeController; } } /// /// Calls a cloud function. /// /// The type of data you will receive from the cloud function. This /// can be an IDictionary, string, IList, AVObject, or any other type supported by /// AVObject. /// The cloud function to call. /// The parameters to send to the cloud function. This /// dictionary can contain anything that could be passed into a AVObject except for /// AVObjects themselves. /// /// The cancellation token. /// The result of the cloud call. public static Task CallFunctionAsync(String name, IDictionary parameters = null, string sesstionToken = null, CancellationToken cancellationToken = default(CancellationToken)) { var sessionTokenTask = AVUser.TakeSessionToken(sesstionToken); return sessionTokenTask.OnSuccess(s => { return CloudCodeController.CallFunctionAsync(name, parameters, s.Result, cancellationToken); }).Unwrap(); } /// /// 远程调用云函数,返回结果会反序列化为 . /// /// /// /// /// /// /// public static Task RPCFunctionAsync(String name, IDictionary parameters = null, string sesstionToken = null, CancellationToken cancellationToken = default(CancellationToken)) { var sessionTokenTask = AVUser.TakeSessionToken(sesstionToken); return sessionTokenTask.OnSuccess(s => { return CloudCodeController.RPCFunction(name, parameters, s.Result, cancellationToken); }).Unwrap(); } /// /// 获取 LeanCloud 服务器的时间 /// /// 如果获取失败,将返回 DateTime.MinValue /// /// /// 服务器的时间 public static Task GetServerDateTimeAsync() { var command = new AVCommand(relativeUri: "date", method: "GET", sessionToken: null, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { DateTime rtn = DateTime.MinValue; if (AVClient.IsSuccessStatusCode(t.Result.Item1)) { var date = AVDecoder.Instance.Decode(t.Result.Item2); if (date != null) { if (date is DateTime) { rtn = (DateTime)date; } } } return rtn; }); } /// /// 请求短信认证。 /// /// 手机号。 /// 应用名称。 /// 进行的操作名称。 /// 验证码失效时间。 /// public static Task RequestSMSCodeAsync(string mobilePhoneNumber, string name, string op, int ttl = 10) { return RequestSMSCodeAsync(mobilePhoneNumber, name, op, ttl, CancellationToken.None); } /// /// 请求发送验证码。 /// /// 是否发送成功。 /// 手机号。 /// 应用名称。 /// 进行的操作名称。 /// 验证码失效时间。 /// Cancellation token。 public static Task RequestSMSCodeAsync(string mobilePhoneNumber, string name, string op, int ttl = 10, CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrEmpty(mobilePhoneNumber)) { throw new AVException(AVException.ErrorCode.MobilePhoneInvalid, "Moblie Phone number is invalid.", null); } Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, }; if (!string.IsNullOrEmpty(name)) { strs.Add("name", name); } if (!string.IsNullOrEmpty(op)) { strs.Add("op", op); } if (ttl > 0) { strs.Add("TTL", ttl); } var command = new AVCommand("requestSmsCode", method: "POST", sessionToken: null, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 请求发送验证码。 /// /// 是否发送成功。 /// 手机号。 public static Task RequestSMSCodeAsync(string mobilePhoneNumber) { return AVCloud.RequestSMSCodeAsync(mobilePhoneNumber, CancellationToken.None); } /// /// 请求发送验证码。 /// /// 是否发送成功。 /// 手机号。 /// Cancellation Token. public static Task RequestSMSCodeAsync(string mobilePhoneNumber, CancellationToken cancellationToken) { return AVCloud.RequestSMSCodeAsync(mobilePhoneNumber, null, null, 0, cancellationToken); } /// /// 发送手机短信,并指定模板以及传入模板所需的参数。 /// Exceptions: /// AVOSCloud.AVException: /// 手机号为空。 /// /// Sms's template /// Template variables env. /// Sms's sign. /// Cancellation token. /// public static Task RequestSMSCodeAsync( string mobilePhoneNumber, string template, IDictionary env, string sign = "", string validateToken = "", CancellationToken cancellationToken = default(CancellationToken)) { if (string.IsNullOrEmpty(mobilePhoneNumber)) { throw new AVException(AVException.ErrorCode.MobilePhoneInvalid, "Moblie Phone number is invalid.", null); } Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, }; strs.Add("template", template); if (String.IsNullOrEmpty(sign)) { strs.Add("sign", sign); } if (String.IsNullOrEmpty(validateToken)) { strs.Add("validate_token", validateToken); } foreach (var key in env.Keys) { strs.Add(key, env[key]); } var command = new AVCommand("requestSmsCode", method: "POST", sessionToken: null, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// /// /// /// public static Task RequestVoiceCodeAsync(string mobilePhoneNumber) { if (string.IsNullOrEmpty(mobilePhoneNumber)) { throw new AVException(AVException.ErrorCode.MobilePhoneInvalid, "Moblie Phone number is invalid.", null); } Dictionary strs = new Dictionary() { { "mobilePhoneNumber", mobilePhoneNumber }, { "smsType", "voice" }, { "IDD","+86" } }; var command = new AVCommand("requestSmsCode", method: "POST", sessionToken: null, data: strs); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// 验证是否是有效短信验证码。 /// /// 是否验证通过。 /// 手机号 /// 验证码。 public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber) { return AVCloud.VerifySmsCodeAsync(code, mobilePhoneNumber, CancellationToken.None); } /// /// 验证是否是有效短信验证码。 /// /// 是否验证通过。 /// 验证码。 /// 手机号 /// Cancellation token. public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber, CancellationToken cancellationToken) { var command = new AVCommand("verifySmsCode/" + code.Trim() + "?mobilePhoneNumber=" + mobilePhoneNumber.Trim(), method: "POST", sessionToken: null, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { return AVClient.IsSuccessStatusCode(t.Result.Item1); }); } /// /// Stands for a captcha result. /// public class Captcha { /// /// Used for captcha verify. /// public string Token { internal set; get; } /// /// Captcha image URL. /// public string Url { internal set; get; } /// /// Verify the user's input of catpcha. /// /// User's input of this captcha. /// CancellationToken. /// public Task VerifyAsync(string code, CancellationToken cancellationToken = default(CancellationToken)) { return AVCloud.VerifyCaptchaAsync(code, Token); } } /// /// Get a captcha image. /// /// captcha image width. /// captcha image height. /// CancellationToken. /// an instance of Captcha. public static Task RequestCaptchaAsync(int width = 85, int height = 30, CancellationToken cancellationToken = default(CancellationToken)) { var path = String.Format("requestCaptcha?width={0}&height={1}", width, height); var command = new AVCommand(path, method: "GET", sessionToken: null, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary; return new Captcha() { Token = decoded["captcha_token"] as string, Url = decoded["captcha_url"] as string, }; }); } /// /// Verify the user's input of catpcha. /// /// The captcha's token, from server. /// User's input of this captcha. /// CancellationToken. /// public static Task VerifyCaptchaAsync(string code, string token, CancellationToken cancellationToken = default(CancellationToken)) { var data = new Dictionary { { "captcha_token", token }, { "captcha_code", code }, }; var command = new AVCommand("verifyCaptcha", method: "POST", sessionToken: null, data: data); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => { if (!t.Result.Item2.ContainsKey("validate_token")) throw new KeyNotFoundException("validate_token"); return t.Result.Item2["validate_token"] as string; }); } /// /// Get the custom cloud parameters, you can set them at console https://leancloud.cn/dashboard/devcomponent.html?appid={your_app_Id}#/component/custom_param /// /// /// public static Task> GetCustomParametersAsync(CancellationToken cancellationToken = default(CancellationToken)) { var command = new AVCommand(string.Format("statistics/apps/{0}/sendPolicy", AVClient.CurrentConfiguration.ApplicationId), method: "GET", sessionToken: null, data: null); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t => { var settings = t.Result.Item2; var CloudParameters = settings["parameters"] as IDictionary; return CloudParameters; }); } public class RealtimeSignature { public string Nonce { internal set; get; } public long Timestamp { internal set; get; } public string ClientId { internal set; get; } public string Signature { internal set; get; } } public static Task RequestRealtimeSignatureAsync(CancellationToken cancellationToken = default(CancellationToken)) { return AVUser.GetCurrentUserAsync(cancellationToken).OnSuccess(t => { return RequestRealtimeSignatureAsync(t.Result, cancellationToken); }).Unwrap(); } public static Task RequestRealtimeSignatureAsync(AVUser user, CancellationToken cancellationToken = default(CancellationToken)) { var command = new AVCommand(string.Format("rtm/sign"), method: "POST", sessionToken: null, data: new Dictionary { { "session_token", user.SessionToken }, } ); return AVPlugins.Instance.CommandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(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, }; }); } /// /// Gets the LeanEngine hosting URL for current app async. /// /// The lean engine hosting URL async. public static Task GetLeanEngineHostingUrlAsync() { return CallFunctionAsync("_internal_extensions_get_domain"); } } /// /// AVRPCC loud function base. /// public class AVRPCCloudFunctionBase { /// /// AVRPCD eserialize. /// public delegate R AVRPCDeserialize(IDictionary result); /// /// AVRPCS erialize. /// public delegate IDictionary AVRPCSerialize

(P parameters); public AVRPCCloudFunctionBase() : this(true) { } public AVRPCCloudFunctionBase(bool noneParameters) { if (noneParameters) { this.Encode = n => { return null; }; } } private AVRPCDeserialize _decode; public AVRPCDeserialize Decode { get { return _decode; } set { _decode = value; } } private AVRPCSerialize

_encode; public AVRPCSerialize

Encode { get { if (_encode == null) { _encode = n => { if (n != null) return Json.Parse(n.ToString()) as IDictionary; return null; }; } return _encode; } set { _encode = value; } } public string FunctionName { get; set; } public Task ExecuteAsync(P parameters) { return AVUser.GetCurrentAsync().OnSuccess(t => { var user = t.Result; var encodedParameters = Encode(parameters); var command = new AVCommand( string.Format("call/{0}", Uri.EscapeUriString(this.FunctionName)), method: "POST", sessionToken: user != null ? user.SessionToken : null, data: encodedParameters); return AVClient.RunCommandAsync(command); }).Unwrap().OnSuccess(s => { var responseBody = s.Result.Item2; if (!responseBody.ContainsKey("result")) { return default(R); } return Decode(responseBody); }); } } public class AVObjectRPCCloudFunction : AVObjectRPCCloudFunction { } public class AVObjectListRPCCloudFunction : AVObjectListRPCCloudFunction { } public class AVObjectListRPCCloudFunction : AVRPCCloudFunctionBase> where R : AVObject { public AVObjectListRPCCloudFunction() : base(true) { this.Decode = this.AVObjectListDeserializer(); } public AVRPCDeserialize> AVObjectListDeserializer() { AVRPCDeserialize> del = data => { var items = data["result"] as IList; return items.Select(item => { var state = AVObjectCoder.Instance.Decode(item as IDictionary, AVDecoder.Instance); return AVObject.FromState(state, state.ClassName); }).ToList() as IList; }; return del; } } public class AVObjectRPCCloudFunction : AVRPCCloudFunctionBase where R : AVObject { public AVObjectRPCCloudFunction() : base(true) { this.Decode = this.AVObjectDeserializer(); } public AVRPCDeserialize AVObjectDeserializer() { AVRPCDeserialize del = data => { var item = data["result"] as object; var state = AVObjectCoder.Instance.Decode(item as IDictionary, AVDecoder.Instance); return AVObject.FromState(state, state.ClassName); }; return del; } } }