chore: 简化

oneRain 2019-08-07 16:35:21 +08:00
parent 905cc943bf
commit 81b2ea993f
45 changed files with 713 additions and 2133 deletions

View File

@ -1,65 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LeanCloud.Storage.Internal;
namespace LeanCloud.Storage.Internal
{
public class AVPlugins : IAVCorePlugins
{

namespace LeanCloud.Storage.Internal {
public class AVPlugins {
private static readonly object instanceMutex = new object();
private static IAVCorePlugins instance;
public static IAVCorePlugins Instance
{
get
{
lock (instanceMutex)
{
private static AVPlugins instance;
public static AVPlugins Instance {
get {
lock (instanceMutex) {
instance = instance ?? new AVPlugins();
return instance;
}
}
set
{
lock (instanceMutex)
{
instance = value;
}
}
}
private readonly object mutex = new object();
#region Server Controllers
private IHttpClient httpClient;
private IAppRouterController appRouterController;
private IAVCommandRunner commandRunner;
private IStorageController storageController;
private HttpClient httpClient;
private AppRouterController appRouterController;
private AVCommandRunner commandRunner;
private StorageController storageController;
private IAVCloudCodeController cloudCodeController;
private IAVConfigController configController;
private IAVFileController fileController;
private IAVObjectController objectController;
private IAVQueryController queryController;
private IAVSessionController sessionController;
private IAVUserController userController;
private IObjectSubclassingController subclassingController;
private AVCloudCodeController cloudCodeController;
private AVFileController fileController;
private AVObjectController objectController;
private AVQueryController queryController;
private AVSessionController sessionController;
private AVUserController userController;
private ObjectSubclassingController subclassingController;
#endregion
#region Current Instance Controller
private IAVCurrentUserController currentUserController;
private IInstallationIdController installationIdController;
private AVCurrentUserController currentUserController;
private InstallationIdController installationIdController;
#endregion
public void Reset()
{
lock (mutex)
{
public void Reset() {
lock (mutex) {
HttpClient = null;
AppRouterController = null;
CommandRunner = null;
@ -77,305 +57,217 @@ namespace LeanCloud.Storage.Internal
}
}
public IHttpClient HttpClient
{
get
{
lock (mutex)
{
public HttpClient HttpClient {
get {
lock (mutex) {
httpClient = httpClient ?? new HttpClient();
return httpClient;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
httpClient = value;
}
}
}
public IAppRouterController AppRouterController
{
get
{
lock (mutex)
{
public AppRouterController AppRouterController {
get {
lock (mutex) {
appRouterController = appRouterController ?? new AppRouterController();
return appRouterController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
appRouterController = value;
}
}
}
public IAVCommandRunner CommandRunner
{
get
{
lock (mutex)
{
commandRunner = commandRunner ?? new AVCommandRunner(HttpClient, InstallationIdController);
public AVCommandRunner CommandRunner {
get {
lock (mutex) {
commandRunner = commandRunner ?? new AVCommandRunner();
return commandRunner;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
commandRunner = value;
}
}
}
#if !UNITY
public IStorageController StorageController
{
get
{
lock (mutex)
{
storageController = storageController ?? new StorageController(AVClient.CurrentConfiguration.ApplicationId);
return storageController;
}
}
set
{
lock (mutex)
{
storageController = value;
}
}
}
#endif
#if UNITY
public IStorageController StorageController
{
get
{
lock (mutex)
{
public StorageController StorageController {
get {
lock (mutex) {
storageController = storageController ?? new StorageController(AVInitializeBehaviour.IsWebPlayer, AVClient.CurrentConfiguration.ApplicationId);
return storageController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
storageController = value;
}
}
}
#else
public StorageController StorageController {
get {
lock (mutex) {
storageController = storageController ?? new StorageController(AVClient.CurrentConfiguration.ApplicationId);
return storageController;
}
}
set {
lock (mutex) {
storageController = value;
}
}
}
#endif
public IAVCloudCodeController CloudCodeController
{
get
{
lock (mutex)
{
cloudCodeController = cloudCodeController ?? new AVCloudCodeController(CommandRunner);
public AVCloudCodeController CloudCodeController {
get {
lock (mutex) {
cloudCodeController = cloudCodeController ?? new AVCloudCodeController();
return cloudCodeController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
cloudCodeController = value;
}
}
}
public IAVFileController FileController
{
get
{
lock (mutex)
{
if (AVClient.CurrentConfiguration.RegionValue == 0)
fileController = fileController ?? new QiniuFileController(CommandRunner);
else if (AVClient.CurrentConfiguration.RegionValue == 2)
fileController = fileController ?? new QCloudCosFileController(CommandRunner);
else if (AVClient.CurrentConfiguration.RegionValue == 1)
fileController = fileController ?? new AWSS3FileController(CommandRunner);
public AVFileController FileController {
get {
if (fileController != null) {
return fileController;
}
lock (mutex) {
switch (AVClient.CurrentConfiguration.RegionValue) {
case 0:
fileController = new QiniuFileController();
break;
case 2:
fileController = new QCloudCosFileController();
break;
case 1:
fileController = new AWSS3FileController();
break;
}
return fileController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
fileController = value;
}
}
}
public IAVConfigController ConfigController
{
get
{
lock (mutex)
{
if (configController == null)
{
configController = new AVConfigController(CommandRunner, StorageController);
}
return configController;
}
}
set
{
lock (mutex)
{
configController = value;
}
}
}
public IAVObjectController ObjectController
{
get
{
lock (mutex)
{
objectController = objectController ?? new AVObjectController(CommandRunner);
public AVObjectController ObjectController {
get {
lock (mutex) {
objectController = objectController ?? new AVObjectController();
return objectController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
objectController = value;
}
}
}
public IAVQueryController QueryController
{
get
{
lock (mutex)
{
if (queryController == null)
{
queryController = new AVQueryController(CommandRunner);
public AVQueryController QueryController {
get {
lock (mutex) {
if (queryController == null) {
queryController = new AVQueryController();
}
return queryController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
queryController = value;
}
}
}
public IAVSessionController SessionController
{
get
{
lock (mutex)
{
sessionController = sessionController ?? new AVSessionController(CommandRunner);
public AVSessionController SessionController {
get {
lock (mutex) {
sessionController = sessionController ?? new AVSessionController();
return sessionController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
sessionController = value;
}
}
}
public IAVUserController UserController
{
get
{
lock (mutex)
{
userController = userController ?? new AVUserController(CommandRunner);
public AVUserController UserController {
get {
lock (mutex) {
userController = userController ?? new AVUserController();
return userController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
userController = value;
}
}
}
public IAVCurrentUserController CurrentUserController
{
get
{
lock (mutex)
{
currentUserController = currentUserController ?? new AVCurrentUserController(StorageController);
public AVCurrentUserController CurrentUserController {
get {
lock (mutex) {
currentUserController = currentUserController ?? new AVCurrentUserController();
return currentUserController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
currentUserController = value;
}
}
}
public IObjectSubclassingController SubclassingController
{
get
{
lock (mutex)
{
if (subclassingController == null)
{
public ObjectSubclassingController SubclassingController {
get {
lock (mutex) {
if (subclassingController == null) {
subclassingController = new ObjectSubclassingController();
subclassingController.AddRegisterHook(typeof(AVUser), () => CurrentUserController.ClearFromMemory());
}
return subclassingController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
subclassingController = value;
}
}
}
public IInstallationIdController InstallationIdController
{
get
{
lock (mutex)
{
installationIdController = installationIdController ?? new InstallationIdController(StorageController);
public InstallationIdController InstallationIdController {
get {
lock (mutex) {
installationIdController = installationIdController ?? new InstallationIdController();
return installationIdController;
}
}
set
{
lock (mutex)
{
set {
lock (mutex) {
installationIdController = value;
}
}

View File

@ -6,17 +6,11 @@ using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http;
namespace LeanCloud.Storage.Internal
{
public class AppRouterController : IAppRouterController
{
namespace LeanCloud.Storage.Internal {
public class AppRouterController {
private AppRouterState currentState;
private readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
/// <summary>
/// Get current app's router state
/// </summary>
/// <returns></returns>
public AppRouterState Get() {
if (string.IsNullOrEmpty(AVClient.CurrentConfiguration.ApplicationId)) {
throw new AVException(AVException.ErrorCode.NotInitialized, "ApplicationId can not be null.");

View File

@ -47,21 +47,12 @@ namespace LeanCloud.Storage.Internal
FetchedAt = DateTime.Now;
}
/// <summary>
/// Is this app router state expired.
/// </summary>
public bool IsExpired {
get {
return DateTime.Now > FetchedAt + TimeSpan.FromSeconds(TTL);
}
}
/// <summary>
/// Get the initial usable router state
/// </summary>
/// <param name="appId">Current app's appId</param>
/// <param name="region">Current app's region</param>
/// <returns>Initial app router state</returns>
public static AppRouterState GetFallbackServers(string appId, AVClient.Configuration.AVRegion region) {
var regionValue = (int)region;
var prefix = appId.Substring(0, 8).ToLower();

View File

@ -1,13 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IAppRouterController
{
AppRouterState Get();
Task<AppRouterState> QueryAsync(CancellationToken cancellationToken);
void Clear();
}
}

View File

@ -7,15 +7,8 @@ using System.Net.Http;
namespace LeanCloud.Storage.Internal
{
public class AVCloudCodeController : IAVCloudCodeController
public class AVCloudCodeController
{
private readonly IAVCommandRunner commandRunner;
public AVCloudCodeController(IAVCommandRunner commandRunner)
{
this.commandRunner = commandRunner;
}
public Task<T> CallFunctionAsync<T>(String name,
IDictionary<string, object> parameters,
string sessionToken,
@ -26,7 +19,7 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = parameters
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary<string, object>;
if (!decoded.ContainsKey("result"))
@ -44,7 +37,7 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = parameters
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary<string, object>;
if (!decoded.ContainsKey("result"))

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IAVCloudCodeController
{
Task<T> CallFunctionAsync<T>(String name,
IDictionary<string, object> parameters,
string sessionToken,
CancellationToken cancellationToken);
Task<T> RPCFunction<T>(string name, IDictionary<string, object> parameters,
string sessionToken,
CancellationToken cancellationToken);
}
}

View File

@ -7,29 +7,15 @@ using System.Threading;
using System.Threading.Tasks;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace LeanCloud.Storage.Internal
{
namespace LeanCloud.Storage.Internal {
/// <summary>
/// Command Runner.
/// </summary>
public class AVCommandRunner : IAVCommandRunner {
public class AVCommandRunner {
public const string APPLICATION_JSON = "application/json";
private readonly System.Net.Http.HttpClient httpClient;
private readonly IInstallationIdController installationIdController;
/// <summary>
///
/// </summary>
/// <param name="httpClient"></param>
/// <param name="installationIdController"></param>
public AVCommandRunner(IHttpClient httpClient, IInstallationIdController installationIdController)
{
this.httpClient = new System.Net.Http.HttpClient();
this.installationIdController = installationIdController;
}
private readonly System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient();
/// <summary>
///
@ -43,7 +29,7 @@ namespace LeanCloud.Storage.Internal
IProgress<AVUploadProgressEventArgs> uploadProgress = null,
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
CancellationToken cancellationToken = default) {
var request = new HttpRequestMessage {
RequestUri = command.Uri,
Method = command.Method,
@ -67,7 +53,7 @@ namespace LeanCloud.Storage.Internal
PrintResponse(response, resultString);
var ret = new Tuple<HttpStatusCode, string>(response.StatusCode, resultString);
var responseCode = ret.Item1;
var contentString = ret.Item2;
@ -105,7 +91,7 @@ namespace LeanCloud.Storage.Internal
async Task<Dictionary<string, string>> GetHeadersAsync() {
var headers = new Dictionary<string, string>();
var installationId = await installationIdController.GetAsync();
var installationId = await AVPlugins.Instance.InstallationIdController.GetAsync();
headers.Add("X-LC-Installation-Id", installationId.ToString());
var conf = AVClient.CurrentConfiguration;
headers.Add("X-LC-Id", conf.ApplicationId);

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IAVCommandRunner
{
/// <summary>
/// Executes <see cref="AVCommand"/> and convert the result into Dictionary.
/// </summary>
/// <param name="command">The command to be run.</param>
/// <param name="uploadProgress">Upload progress callback.</param>
/// <param name="downloadProgress">Download progress callback.</param>
/// <param name="cancellationToken">The cancellation token for the request.</param>
/// <returns></returns>
Task<Tuple<HttpStatusCode, T>> RunCommandAsync<T>(AVCommand command,
IProgress<AVUploadProgressEventArgs> uploadProgress = null,
IProgress<AVDownloadProgressEventArgs> downloadProgress = null,
CancellationToken cancellationToken = default(CancellationToken));
}
}

View File

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Http;
namespace LeanCloud.Storage.Internal {
/// <summary>
/// Config controller.
/// </summary>
internal class AVConfigController : IAVConfigController {
private readonly IAVCommandRunner commandRunner;
/// <summary>
/// Initializes a new instance of the <see cref="AVConfigController"/> class.
/// </summary>
public AVConfigController(IAVCommandRunner commandRunner, IStorageController storageController) {
this.commandRunner = commandRunner;
CurrentConfigController = new AVCurrentConfigController(storageController);
}
public IAVCommandRunner CommandRunner { get; internal set; }
public IAVCurrentConfigController CurrentConfigController { get; internal set; }
public Task<AVConfig> FetchConfigAsync(String sessionToken, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = "config",
Method = HttpMethod.Post,
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(task => {
cancellationToken.ThrowIfCancellationRequested();
return new AVConfig(task.Result.Item2);
}).OnSuccess(task => {
cancellationToken.ThrowIfCancellationRequested();
CurrentConfigController.SetCurrentConfigAsync(task.Result);
return task;
}).Unwrap();
}
}
}

View File

@ -1,75 +0,0 @@
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal {
/// <summary>
/// LeanCloud current config controller.
/// </summary>
internal class AVCurrentConfigController : IAVCurrentConfigController {
private const string CurrentConfigKey = "CurrentConfig";
private readonly TaskQueue taskQueue;
private AVConfig currentConfig;
private IStorageController storageController;
/// <summary>
/// Initializes a new instance of the <see cref="LeanCloud.Storage.Internal.AVCurrentConfigController"/> class.
/// </summary>
public AVCurrentConfigController(IStorageController storageController) {
this.storageController = storageController;
taskQueue = new TaskQueue();
}
public Task<AVConfig> GetCurrentConfigAsync() {
return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => {
if (currentConfig == null) {
return storageController.LoadAsync().OnSuccess(t => {
object tmp;
t.Result.TryGetValue(CurrentConfigKey, out tmp);
string propertiesString = tmp as string;
if (propertiesString != null) {
var dictionary = JsonConvert.DeserializeObject<IDictionary<string, object>>(propertiesString);
currentConfig = new AVConfig(dictionary);
} else {
currentConfig = new AVConfig();
}
return currentConfig;
});
}
return Task.FromResult(currentConfig);
}), CancellationToken.None).Unwrap();
}
public Task SetCurrentConfigAsync(AVConfig config) {
return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => {
currentConfig = config;
var jsonObject = ((IJsonConvertible)config).ToJSON();
var jsonString = JsonConvert.SerializeObject(jsonObject);
return storageController.LoadAsync().OnSuccess(t => t.Result.AddAsync(CurrentConfigKey, jsonString));
}).Unwrap().Unwrap(), CancellationToken.None);
}
public Task ClearCurrentConfigAsync() {
return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => {
currentConfig = null;
return storageController.LoadAsync().OnSuccess(t => t.Result.RemoveAsync(CurrentConfigKey));
}).Unwrap().Unwrap(), CancellationToken.None);
}
public Task ClearCurrentConfigInMemoryAsync() {
return taskQueue.Enqueue(toAwait => toAwait.ContinueWith(_ => {
currentConfig = null;
}), CancellationToken.None);
}
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.Threading.Tasks;
using System.Threading;
namespace LeanCloud.Storage.Internal {
public interface IAVConfigController {
/// <summary>
/// Gets the current config controller.
/// </summary>
/// <value>The current config controller.</value>
IAVCurrentConfigController CurrentConfigController { get; }
/// <summary>
/// Fetches the config from the server asynchronously.
/// </summary>
/// <returns>The config async.</returns>
/// <param name="sessionToken">Session token.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<AVConfig> FetchConfigAsync(String sessionToken, CancellationToken cancellationToken);
}
}

View File

@ -1,31 +0,0 @@
using System;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
public interface IAVCurrentConfigController {
/// <summary>
/// Gets the current config async.
/// </summary>
/// <returns>The current config async.</returns>
Task<AVConfig> GetCurrentConfigAsync();
/// <summary>
/// Sets the current config async.
/// </summary>
/// <returns>The current config async.</returns>
/// <param name="config">Config.</param>
Task SetCurrentConfigAsync(AVConfig config);
/// <summary>
/// Clears the current config async.
/// </summary>
/// <returns>The current config async.</returns>
Task ClearCurrentConfigAsync();
/// <summary>
/// Clears the current config in memory async.
/// </summary>
/// <returns>The current config in memory async.</returns>
Task ClearCurrentConfigInMemoryAsync();
}
}

View File

@ -2,29 +2,17 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using LeanCloud.Storage.Internal;
using System.Net;
using System.Net.Http;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal
{
namespace LeanCloud.Storage.Internal {
/// <summary>
/// AVF ile controller.
/// </summary>
public class AVFileController : IAVFileController
{
protected readonly IAVCommandRunner commandRunner;
/// <summary>
/// Initializes a new instance of the <see cref="T:LeanCloud.Storage.Internal.AVFileController"/> class.
/// </summary>
/// <param name="commandRunner">Command runner.</param>
public AVFileController(IAVCommandRunner commandRunner)
{
this.commandRunner = commandRunner;
}
public class AVFileController {
/// <summary>
/// Saves the async.
/// </summary>
@ -65,16 +53,14 @@ namespace LeanCloud.Storage.Internal
MimeType = state.MimeType
};
}
public Task DeleteAsync(FileState state, string sessionToken, CancellationToken cancellationToken)
{
public Task DeleteAsync(FileState state, string sessionToken, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = $"files/{state.ObjectId}",
Method = HttpMethod.Delete
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
}
internal Task<Tuple<HttpStatusCode, IDictionary<string, object>>> GetFileToken(FileState fileState, CancellationToken cancellationToken)
{
internal Task<Tuple<HttpStatusCode, IDictionary<string, object>>> GetFileToken(FileState fileState, CancellationToken cancellationToken) {
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> rtn;
string currentSessionToken = AVUser.CurrentSessionToken;
string str = fileState.Name;
@ -90,44 +76,38 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = parameters
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
}
public Task<FileState> GetAsync(string objectId, string sessionToken, CancellationToken cancellationToken)
{
public Task<FileState> GetAsync(string objectId, string sessionToken, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = $"files/{objectId}",
Method = HttpMethod.Get
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(_ =>
{
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(_ => {
var result = _.Result;
var jsonData = result.Item2;
cancellationToken.ThrowIfCancellationRequested();
return new FileState
{
return new FileState {
ObjectId = jsonData["objectId"] as string,
Name = jsonData["name"] as string,
Url = new Uri(jsonData["url"] as string, UriKind.Absolute),
};
});
}
internal static string GetUniqueName(FileState fileState)
{
internal static string GetUniqueName(FileState fileState) {
string key = Random(12);
string extension = Path.GetExtension(fileState.Name);
key += extension;
fileState.CloudName = key;
return key;
}
internal static string Random(int length)
{
internal static string Random(int length) {
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
var random = new Random();
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
internal static double CalcProgress(double already, double total)
{
internal static double CalcProgress(double already, double total) {
var pv = (1.0 * already / total);
return Math.Round(pv, 3);
}

View File

@ -6,28 +6,14 @@ using LeanCloud.Storage.Internal;
using System.Collections.Generic;
using System.Net.Http;
namespace LeanCloud.Storage.Internal
{
internal class AWSS3FileController : AVFileController
{
private object mutex = new object();
public AWSS3FileController(IAVCommandRunner commandRunner) : base(commandRunner)
{
}
public override Task<FileState> SaveAsync(FileState state, Stream dataStream, string sessionToken, IProgress<AVUploadProgressEventArgs> progress, CancellationToken cancellationToken = default(System.Threading.CancellationToken))
{
if (state.Url != null)
{
namespace LeanCloud.Storage.Internal {
internal class AWSS3FileController : AVFileController {
public override Task<FileState> SaveAsync(FileState state, Stream dataStream, string sessionToken, IProgress<AVUploadProgressEventArgs> progress, CancellationToken cancellationToken = default(System.Threading.CancellationToken)) {
if (state.Url != null) {
return Task.FromResult(state);
}
return GetFileToken(state, cancellationToken).OnSuccess(t =>
{
return GetFileToken(state, cancellationToken).OnSuccess(t => {
var fileToken = t.Result.Item2;
var uploadUrl = fileToken["upload_url"].ToString();
state.ObjectId = fileToken["objectId"].ToString();
@ -35,14 +21,12 @@ namespace LeanCloud.Storage.Internal
state.Url = new Uri(url, UriKind.Absolute);
return PutFile(state, uploadUrl, dataStream);
}).Unwrap().OnSuccess(s =>
{
}).Unwrap().OnSuccess(s => {
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) {
IList<KeyValuePair<string, string>> makeBlockHeaders = new List<KeyValuePair<string, string>>();
makeBlockHeaders.Add(new KeyValuePair<string, string>("Content-Type", state.MimeType));
var request = new HttpRequest {

View File

@ -1,24 +0,0 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IAVFileController
{
Task<FileState> SaveAsync(FileState state,
Stream dataStream,
String sessionToken,
IProgress<AVUploadProgressEventArgs> progress,
CancellationToken cancellationToken);
Task DeleteAsync(FileState state,
string sessionToken,
CancellationToken cancellationToken);
Task<FileState> GetAsync(string objectId,
string sessionToken,
CancellationToken cancellationToken);
}
}

View File

@ -8,10 +8,8 @@ using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal
{
internal class QCloudCosFileController : AVFileController
{
namespace LeanCloud.Storage.Internal {
internal class QCloudCosFileController : AVFileController {
private object mutex = new object();
FileState fileState;
@ -22,32 +20,24 @@ namespace LeanCloud.Storage.Internal
bool done;
private long sliceSize = (long)CommonSize.KB512;
public QCloudCosFileController(IAVCommandRunner commandRunner) : base(commandRunner)
{
}
public Task<FileState> SaveAsync(FileState state,
Stream dataStream,
string sessionToken,
IProgress<AVUploadProgressEventArgs> progress,
CancellationToken cancellationToken)
{
if (state.Url != null)
{
CancellationToken cancellationToken) {
if (state.Url != null) {
return Task<FileState>.FromResult(state);
}
fileState = state;
data = dataStream;
return GetFileToken(fileState, cancellationToken).OnSuccess(_ =>
{
return GetFileToken(fileState, cancellationToken).OnSuccess(_ => {
var fileToken = _.Result.Item2;
uploadUrl = fileToken["upload_url"].ToString();
token = fileToken["token"].ToString();
fileState.ObjectId = fileToken["objectId"].ToString();
bucket = fileToken["bucket"].ToString();
return FileSlice(cancellationToken).OnSuccess(t =>
{
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>;
@ -65,32 +55,25 @@ namespace LeanCloud.Storage.Internal
long offset,
Stream dataStream,
IProgress<AVUploadProgressEventArgs> progress,
CancellationToken cancellationToken)
{
CancellationToken cancellationToken) {
long dataLength = dataStream.Length;
if (progress != null)
{
lock (mutex)
{
progress.Report(new AVUploadProgressEventArgs()
{
if (progress != null) {
lock (mutex) {
progress.Report(new AVUploadProgressEventArgs() {
Progress = AVFileController.CalcProgress(offset, dataLength)
});
}
}
if (offset == dataLength)
{
if (offset == dataLength) {
return Task.FromResult<FileState>(fileState);
}
var sliceFile = GetNextBinary(offset, dataStream);
return ExcuteUpload(sessionId, offset, sliceFile, cancellationToken).OnSuccess(_ =>
{
return ExcuteUpload(sessionId, offset, sliceFile, cancellationToken).OnSuccess(_ => {
offset += sliceFile.Length;
if (offset == dataLength)
{
if (offset == dataLength) {
done = true;
return Task.FromResult<FileState>(fileState);
}
@ -101,8 +84,7 @@ namespace LeanCloud.Storage.Internal
}).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) {
var body = new Dictionary<string, object>();
body.Add("op", "upload_slice");
body.Add("session", sessionId);
@ -111,26 +93,20 @@ namespace LeanCloud.Storage.Internal
return PostToQCloud(body, sliceFile, cancellationToken);
}
Task<Tuple<HttpStatusCode, IDictionary<string, object>>> FileSlice(CancellationToken cancellationToken)
{
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)
{
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)
{
return PostToQCloud(body, wholeFile, cancellationToken).OnSuccess(_ => {
if (_.Result.Item1 == HttpStatusCode.OK) {
done = true;
}
return _.Result;
});
}
else
{
} else {
body.Add("op", "upload_slice");
body.Add("filesize", data.Length);
body.Add("sha", HexStringFromBytes(sha1.ComputeHash(data)));
@ -139,19 +115,16 @@ namespace LeanCloud.Storage.Internal
return PostToQCloud(body, null, cancellationToken);
}
public static string HexStringFromBytes(byte[] bytes)
{
public static string HexStringFromBytes(byte[] bytes) {
var sb = new StringBuilder();
foreach (byte b in bytes)
{
foreach (byte b in bytes) {
var hex = b.ToString("x2");
sb.Append(hex);
}
return sb.ToString();
}
public static string SHA1HashStringForUTF8String(string s)
{
public static string SHA1HashStringForUTF8String(string s) {
byte[] bytes = Encoding.UTF8.GetBytes(s);
SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();
@ -162,8 +135,7 @@ namespace LeanCloud.Storage.Internal
async Task<Tuple<HttpStatusCode, IDictionary<string, object>>> PostToQCloud(
Dictionary<string, object> body,
byte[] sliceFile,
CancellationToken cancellationToken)
{
CancellationToken cancellationToken) {
IList<KeyValuePair<string, string>> sliceHeaders = new List<KeyValuePair<string, string>>();
sliceHeaders.Add(new KeyValuePair<string, string>("Authorization", this.token));
@ -185,8 +157,7 @@ namespace LeanCloud.Storage.Internal
JsonConvert.DeserializeObject<Dictionary<string, object>>(ret.Item2, new LeanCloudJsonConverter()));
return result;
}
public static Stream HttpUploadFile(byte[] file, string fileName, out string contentType, out long contentLength, IDictionary<string, object> nvc)
{
public static Stream HttpUploadFile(byte[] file, string fileName, out string contentType, out long contentLength, IDictionary<string, object> nvc) {
string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
byte[] boundarybytes = StringToAscii("\r\n--" + boundary + "\r\n");
contentType = "multipart/form-data; boundary=" + boundary;
@ -194,8 +165,7 @@ namespace LeanCloud.Storage.Internal
MemoryStream rs = new MemoryStream();
string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
foreach (string key in nvc.Keys)
{
foreach (string key in nvc.Keys) {
rs.Write(boundarybytes, 0, boundarybytes.Length);
string formitem = string.Format(formdataTemplate, key, nvc[key]);
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
@ -203,8 +173,7 @@ namespace LeanCloud.Storage.Internal
}
rs.Write(boundarybytes, 0, boundarybytes.Length);
if (file != null)
{
if (file != null) {
string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
string header = string.Format(headerTemplate, "fileContent", fileName, "application/octet-stream");
byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
@ -224,11 +193,9 @@ namespace LeanCloud.Storage.Internal
return new MemoryStream(tempBuffer);
}
public static byte[] StringToAscii(string s)
{
public static byte[] StringToAscii(string s) {
byte[] retval = new byte[s.Length];
for (int ix = 0; ix < s.Length; ++ix)
{
for (int ix = 0; ix < s.Length; ++ix) {
char ch = s[ix];
if (ch <= 0x7f) retval[ix] = (byte)ch;
else retval[ix] = (byte)'?';
@ -236,10 +203,8 @@ namespace LeanCloud.Storage.Internal
return retval;
}
byte[] GetNextBinary(long completed, Stream dataStream)
{
if (completed + sliceSize > dataStream.Length)
{
byte[] GetNextBinary(long completed, Stream dataStream) {
if (completed + sliceSize > dataStream.Length) {
sliceSize = dataStream.Length - completed;
}

View File

@ -31,11 +31,6 @@ namespace LeanCloud.Storage.Internal
internal static string UP_HOST = "https://up.qbox.me";
private object mutex = new object();
public QiniuFileController(IAVCommandRunner commandRunner) : base(commandRunner)
{
}
public override Task<FileState> SaveAsync(FileState state,
Stream dataStream,
String sessionToken,
@ -165,7 +160,7 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = parameters
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
}
IList<KeyValuePair<string, string>> GetQiniuRequestHeaders(FileState state)
{

View File

@ -10,7 +10,7 @@ using System.IO;
using NetHttpClient = System.Net.Http.HttpClient;
namespace LeanCloud.Storage.Internal {
public class HttpClient : IHttpClient {
public class HttpClient {
static readonly HashSet<string> HttpContentHeaders = new HashSet<string> {
{ "Allow" },
{ "Content-Disposition" },
@ -41,7 +41,7 @@ namespace LeanCloud.Storage.Internal {
IProgress<AVUploadProgressEventArgs> uploadProgress,
IProgress<AVDownloadProgressEventArgs> downloadProgress,
CancellationToken cancellationToken) {
HttpMethod httpMethod = httpRequest.Method;
HttpRequestMessage message = new HttpRequestMessage(httpMethod, httpRequest.Uri);

View File

@ -1,24 +0,0 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IHttpClient
{
/// <summary>
/// Executes HTTP request to a <see cref="HttpRequest.Uri"/> with <see cref="HttpRequest.Method"/> HTTP verb
/// and <see cref="HttpRequest.Headers"/>.
/// </summary>
/// <param name="httpRequest">The HTTP request to be executed.</param>
/// <param name="uploadProgress">Upload progress callback.</param>
/// <param name="downloadProgress">Download progress callback.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A task that resolves to Htt</returns>
Task<Tuple<HttpStatusCode, string>> ExecuteAsync(HttpRequest httpRequest,
IProgress<AVUploadProgressEventArgs> uploadProgress,
IProgress<AVDownloadProgressEventArgs> downloadProgress,
CancellationToken cancellationToken);
}
}

View File

@ -1,26 +0,0 @@
using LeanCloud.Storage.Internal;
using System;
namespace LeanCloud.Storage.Internal
{
public interface IAVCorePlugins
{
void Reset();
IHttpClient HttpClient { get; }
IAppRouterController AppRouterController { get; }
IAVCommandRunner CommandRunner { get; }
IStorageController StorageController { get; }
IAVCloudCodeController CloudCodeController { get; }
IAVConfigController ConfigController { get; }
IAVFileController FileController { get; }
IAVObjectController ObjectController { get; }
IAVQueryController QueryController { get; }
IAVSessionController SessionController { get; }
IAVUserController UserController { get; }
IObjectSubclassingController SubclassingController { get; }
IAVCurrentUserController CurrentUserController { get; }
IInstallationIdController InstallationIdController { get; }
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
public interface IInstallationIdController {
/// <summary>
/// Sets current <code>installationId</code> and saves it to local storage.
/// </summary>
/// <param name="installationId">The <code>installationId</code> to be saved.</param>
Task SetAsync(Guid? installationId);
/// <summary>
/// Gets current <code>installationId</code> from local storage. Generates a none exists.
/// </summary>
/// <returns>Current <code>installationId</code>.</returns>
Task<Guid?> GetAsync();
/// <summary>
/// Clears current installationId from memory and local storage.
/// </summary>
Task ClearAsync();
}
}

View File

@ -1,66 +1,59 @@
using LeanCloud.Storage.Internal;
using System;
using System.Threading;
using System;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
public class InstallationIdController : IInstallationIdController {
private const string InstallationIdKey = "InstallationId";
private readonly object mutex = new object();
private Guid? installationId;
public class InstallationIdController {
private const string InstallationIdKey = "InstallationId";
private readonly object mutex = new object();
private Guid? installationId;
private readonly IStorageController storageController;
public InstallationIdController(IStorageController storageController) {
this.storageController = storageController;
}
public Task SetAsync(Guid? installationId) {
lock (mutex) {
Task saveTask;
if (installationId == null) {
saveTask = storageController
.LoadAsync()
.OnSuccess(storage => storage.Result.RemoveAsync(InstallationIdKey))
.Unwrap();
} else {
saveTask = storageController
.LoadAsync()
.OnSuccess(storage => storage.Result.AddAsync(InstallationIdKey, installationId.ToString()))
.Unwrap();
}
this.installationId = installationId;
return saveTask;
}
}
public Task<Guid?> GetAsync() {
lock (mutex) {
if (installationId != null) {
return Task.FromResult(installationId);
}
}
return storageController
.LoadAsync()
.OnSuccess<IStorageDictionary<string, object>, Task<Guid?>>(s => {
object id;
s.Result.TryGetValue(InstallationIdKey, out id);
try {
public Task SetAsync(Guid? installationId) {
lock (mutex) {
installationId = new Guid((string)id);
return Task.FromResult(installationId);
}
} catch (Exception) {
var newInstallationId = Guid.NewGuid();
return SetAsync(newInstallationId).OnSuccess<Guid?>(_ => newInstallationId);
}
})
.Unwrap();
}
Task saveTask;
public Task ClearAsync() {
return SetAsync(null);
if (installationId == null) {
saveTask = AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(storage => storage.Result.RemoveAsync(InstallationIdKey))
.Unwrap();
} else {
saveTask = AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(storage => storage.Result.AddAsync(InstallationIdKey, installationId.ToString()))
.Unwrap();
}
this.installationId = installationId;
return saveTask;
}
}
public Task<Guid?> GetAsync() {
lock (mutex) {
if (installationId != null) {
return Task.FromResult(installationId);
}
}
return AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(s => {
object id;
s.Result.TryGetValue(InstallationIdKey, out id);
try {
lock (mutex) {
installationId = new Guid((string)id);
return Task.FromResult(installationId);
}
} catch (Exception) {
var newInstallationId = Guid.NewGuid();
return SetAsync(newInstallationId).OnSuccess<Guid?>(_ => newInstallationId);
}
})
.Unwrap();
}
public Task ClearAsync() {
return SetAsync(null);
}
}
}
}

View File

@ -7,13 +7,7 @@ using LeanCloud.Utilities;
using System.Net.Http;
namespace LeanCloud.Storage.Internal {
public class AVObjectController : IAVObjectController {
private readonly IAVCommandRunner commandRunner;
public AVObjectController(IAVCommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
public class AVObjectController {
public Task<IObjectState> FetchAsync(IObjectState state,
string sessionToken,
CancellationToken cancellationToken) {
@ -21,7 +15,7 @@ namespace LeanCloud.Storage.Internal {
Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}",
Method = HttpMethod.Get
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
});
}
@ -34,7 +28,7 @@ namespace LeanCloud.Storage.Internal {
Path = $"classes/{Uri.EscapeDataString(state.ClassName)}/{Uri.EscapeDataString(state.ObjectId)}?{AVClient.BuildQueryString(queryString)}",
Method = HttpMethod.Get
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
});
}
@ -49,7 +43,7 @@ namespace LeanCloud.Storage.Internal {
Method = state.ObjectId == null ? HttpMethod.Post : HttpMethod.Put,
Content = objectJSON
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = t.Result.Item1 == System.Net.HttpStatusCode.Created;
@ -62,7 +56,7 @@ namespace LeanCloud.Storage.Internal {
IList<IDictionary<string, IAVFieldOperation>> operationsList,
string sessionToken,
CancellationToken cancellationToken) {
var requests = states
.Zip(operationsList, (item, ops) => new AVCommand {
Path = item.ObjectId == null ? $"classes/{Uri.EscapeDataString(item.ClassName)}" : $"classes/{Uri.EscapeDataString(item.ClassName)}/{Uri.EscapeDataString(item.ObjectId)}",
@ -89,7 +83,7 @@ namespace LeanCloud.Storage.Internal {
Path = $"classes/{state.ClassName}/{state.ObjectId}",
Method = HttpMethod.Delete
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
}
public IList<Task> DeleteAllAsync(IList<IObjectState> states,
@ -157,7 +151,7 @@ namespace LeanCloud.Storage.Internal {
{ "requests", encodedRequests }
}
};
commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).ContinueWith(t => {
AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).ContinueWith(t => {
if (t.IsFaulted || t.IsCanceled) {
foreach (var tcs in tcss) {
if (t.IsFaulted) {

View File

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IAVObjectController
{
//Task<IObjectState> FetchAsync(IObjectState state,
// string sessionToken,
// CancellationToken cancellationToken);
Task<IObjectState> FetchAsync(IObjectState state,
IDictionary<string,object> queryString,
string sessionToken,
CancellationToken cancellationToken);
Task<IObjectState> SaveAsync(IObjectState state,
IDictionary<string, IAVFieldOperation> operations,
string sessionToken,
CancellationToken cancellationToken);
IList<Task<IObjectState>> SaveAllAsync(IList<IObjectState> states,
IList<IDictionary<string, IAVFieldOperation>> operationsList,
string sessionToken,
CancellationToken cancellationToken);
Task DeleteAsync(IObjectState state,
string sessionToken,
CancellationToken cancellationToken);
IList<Task> DeleteAllAsync(IList<IObjectState> states,
string sessionToken,
CancellationToken cancellationToken);
}
}

View File

@ -1,24 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IObjectSubclassingController
{
String GetClassName(Type type);
Type GetType(String className);
bool IsTypeValid(String className, Type type);
void RegisterSubclass(Type t);
void UnregisterSubclass(Type t);
void AddRegisterHook(Type t, Action action);
AVObject Instantiate(String className);
IDictionary<String, String> GetPropertyMappings(String className);
}
}

View File

@ -1,24 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using LeanCloud.Storage.Internal;
namespace LeanCloud.Storage.Internal
{
internal class ObjectSubclassingController : IObjectSubclassingController
{
namespace LeanCloud.Storage.Internal {
public class ObjectSubclassingController {
// Class names starting with _ are documented to be reserved. Use this one
// here to allow us to 'inherit' certain properties.
private static readonly string avObjectClassName = "_AVObject";
private readonly ReaderWriterLockSlim mutex;
private readonly IDictionary<String, ObjectSubclassInfo> registeredSubclasses;
private Dictionary<String, Action> registerActions;
private readonly IDictionary<string, ObjectSubclassInfo> registeredSubclasses;
private Dictionary<string, Action> registerActions;
public ObjectSubclassingController()
{
public ObjectSubclassingController() {
mutex = new ReaderWriterLockSlim();
registeredSubclasses = new Dictionary<String, ObjectSubclassInfo>();
registerActions = new Dictionary<string, Action>();
@ -28,15 +23,13 @@ namespace LeanCloud.Storage.Internal
RegisterSubclass(typeof(AVObject));
}
public String GetClassName(Type type)
{
public string GetClassName(Type type) {
return type == typeof(AVObject)
? avObjectClassName
: ObjectSubclassInfo.GetClassName(type.GetTypeInfo());
}
public Type GetType(String className)
{
public Type GetType(string className) {
ObjectSubclassInfo info = null;
mutex.EnterReadLock();
registeredSubclasses.TryGetValue(className, out info);
@ -47,8 +40,7 @@ namespace LeanCloud.Storage.Internal
: null;
}
public bool IsTypeValid(String className, Type type)
{
public bool IsTypeValid(string className, Type type) {
ObjectSubclassInfo subclassInfo = null;
mutex.EnterReadLock();
@ -60,39 +52,30 @@ namespace LeanCloud.Storage.Internal
: subclassInfo.TypeInfo == type.GetTypeInfo();
}
public void RegisterSubclass(Type type)
{
public void RegisterSubclass(Type type) {
TypeInfo typeInfo = type.GetTypeInfo();
if (!typeof(AVObject).GetTypeInfo().IsAssignableFrom(typeInfo))
{
if (!typeof(AVObject).GetTypeInfo().IsAssignableFrom(typeInfo)) {
throw new ArgumentException("Cannot register a type that is not a subclass of AVObject");
}
String className = GetClassName(type);
string className = GetClassName(type);
try
{
try {
// Perform this as a single independent transaction, so we can never get into an
// intermediate state where we *theoretically* register the wrong class due to a
// TOCTTOU bug.
mutex.EnterWriteLock();
ObjectSubclassInfo previousInfo = null;
if (registeredSubclasses.TryGetValue(className, out previousInfo))
{
if (typeInfo.IsAssignableFrom(previousInfo.TypeInfo))
{
if (registeredSubclasses.TryGetValue(className, out previousInfo)) {
if (typeInfo.IsAssignableFrom(previousInfo.TypeInfo)) {
// Previous subclass is more specific or equal to the current type, do nothing.
return;
}
else if (previousInfo.TypeInfo.IsAssignableFrom(typeInfo))
{
} else if (previousInfo.TypeInfo.IsAssignableFrom(typeInfo)) {
// Previous subclass is parent of new child, fallthrough and actually register
// this class.
/* Do nothing */
}
else
{
} else {
throw new ArgumentException(
"Tried to register both " + previousInfo.TypeInfo.FullName + " and " + typeInfo.FullName +
" as the AVObject subclass of " + className + ". Cannot determine the right class " +
@ -102,15 +85,12 @@ namespace LeanCloud.Storage.Internal
}
ConstructorInfo constructor = type.FindConstructor();
if (constructor == null)
{
if (constructor == null) {
throw new ArgumentException("Cannot register a type that does not implement the default constructor!");
}
registeredSubclasses[className] = new ObjectSubclassInfo(type, constructor);
}
finally
{
} finally {
mutex.ExitWriteLock();
}
@ -120,28 +100,24 @@ namespace LeanCloud.Storage.Internal
registerActions.TryGetValue(className, out toPerform);
mutex.ExitReadLock();
if (toPerform != null)
{
if (toPerform != null) {
toPerform();
}
}
public void UnregisterSubclass(Type type)
{
public void UnregisterSubclass(Type type) {
mutex.EnterWriteLock();
registeredSubclasses.Remove(GetClassName(type));
mutex.ExitWriteLock();
}
public void AddRegisterHook(Type t, Action action)
{
public void AddRegisterHook(Type t, Action action) {
mutex.EnterWriteLock();
registerActions.Add(GetClassName(t), action);
mutex.ExitWriteLock();
}
public AVObject Instantiate(String className)
{
public AVObject Instantiate(String className) {
ObjectSubclassInfo info = null;
mutex.EnterReadLock();
@ -153,13 +129,11 @@ namespace LeanCloud.Storage.Internal
: new AVObject(className);
}
public IDictionary<String, String> GetPropertyMappings(String className)
{
public IDictionary<String, String> GetPropertyMappings(String className) {
ObjectSubclassInfo info = null;
mutex.EnterReadLock();
registeredSubclasses.TryGetValue(className, out info);
if (info == null)
{
if (info == null) {
registeredSubclasses.TryGetValue(avObjectClassName, out info);
}
mutex.ExitReadLock();

View File

@ -5,25 +5,13 @@ using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
internal class AVQueryController : IAVQueryController
{
private readonly IAVCommandRunner commandRunner;
public AVQueryController(IAVCommandRunner commandRunner)
{
this.commandRunner = commandRunner;
}
public Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query,
AVUser user,
CancellationToken cancellationToken) where T : AVObject
{
namespace LeanCloud.Storage.Internal {
public class AVQueryController {
public Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query, AVUser user,
CancellationToken cancellationToken) where T : AVObject {
string sessionToken = user != null ? user.SessionToken : null;
return FindAsync(query.Path, query.BuildParameters(), sessionToken, cancellationToken).OnSuccess(t =>
{
return FindAsync(query.Path, query.BuildParameters(), sessionToken, cancellationToken).OnSuccess(t => {
var items = t.Result["results"] as IList<object>;
return (from item in items
@ -33,35 +21,30 @@ namespace LeanCloud.Storage.Internal
public Task<int> CountAsync<T>(AVQuery<T> query,
AVUser user,
CancellationToken cancellationToken) where T : AVObject
{
CancellationToken cancellationToken) where T : AVObject {
string sessionToken = user != null ? user.SessionToken : null;
var parameters = query.BuildParameters();
parameters["limit"] = 0;
parameters["count"] = 1;
return FindAsync(query.Path, parameters, sessionToken, cancellationToken).OnSuccess(t =>
{
return FindAsync(query.Path, parameters, sessionToken, cancellationToken).OnSuccess(t => {
return Convert.ToInt32(t.Result["count"]);
});
}
public Task<IObjectState> FirstAsync<T>(AVQuery<T> query,
AVUser user,
CancellationToken cancellationToken) where T : AVObject
{
CancellationToken cancellationToken) where T : AVObject {
string sessionToken = user?.SessionToken;
var parameters = query.BuildParameters();
parameters["limit"] = 1;
return FindAsync(query.Path, parameters, sessionToken, cancellationToken).OnSuccess(t =>
{
return FindAsync(query.Path, parameters, sessionToken, cancellationToken).OnSuccess(t => {
var items = t.Result["results"] as IList<object>;
var item = items.FirstOrDefault() as IDictionary<string, object>;
// Not found. Return empty state.
if (item == null)
{
if (item == null) {
return (IObjectState)null;
}
@ -72,34 +55,14 @@ namespace LeanCloud.Storage.Internal
private Task<IDictionary<string, object>> FindAsync(string path,
IDictionary<string, object> parameters,
string sessionToken,
CancellationToken cancellationToken)
{
CancellationToken cancellationToken) {
var command = new AVCommand {
Path = $"{path}?{AVClient.BuildQueryString(parameters)}",
Method = HttpMethod.Get
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return t.Result.Item2;
});
}
//private Task<IDictionary<string, object>> FindAsync(string className,
// IDictionary<string, object> parameters,
// string sessionToken,
// CancellationToken cancellationToken)
//{
// var command = new AVCommand(string.Format("classes/{0}?{1}",
// Uri.EscapeDataString(className),
// AVClient.BuildQueryString(parameters)),
// method: "GET",
// sessionToken: sessionToken,
// data: null);
// return commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).OnSuccess(t =>
// {
// return t.Result.Item2;
// });
//}
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
public interface IAVQueryController {
Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query,
AVUser user,
CancellationToken cancellationToken) where T : AVObject;
Task<int> CountAsync<T>(AVQuery<T> query,
AVUser user,
CancellationToken cancellationToken) where T : AVObject;
Task<IObjectState> FirstAsync<T>(AVQuery<T> query,
AVUser user,
CancellationToken cancellationToken) where T : AVObject;
}
}

View File

@ -5,19 +5,13 @@ using System.Threading.Tasks;
using System.Net.Http;
namespace LeanCloud.Storage.Internal {
public class AVSessionController : IAVSessionController {
private readonly IAVCommandRunner commandRunner;
public AVSessionController(IAVCommandRunner commandRunner) {
this.commandRunner = commandRunner;
}
public class AVSessionController {
public Task<IObjectState> GetSessionAsync(string sessionToken, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = "sessions/me",
Method = HttpMethod.Get
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
});
}
@ -27,7 +21,7 @@ namespace LeanCloud.Storage.Internal {
Path = "logout",
Method = HttpMethod.Post
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
}
public Task<IObjectState> UpgradeToRevocableSessionAsync(string sessionToken, CancellationToken cancellationToken) {
@ -35,7 +29,7 @@ namespace LeanCloud.Storage.Internal {
Path = "upgradeToRevocableSession",
Method = HttpMethod.Post,
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
});
}

View File

@ -1,15 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
public interface IAVSessionController {
Task<IObjectState> GetSessionAsync(string sessionToken, CancellationToken cancellationToken);
Task RevokeAsync(string sessionToken, CancellationToken cancellationToken);
Task<IObjectState> UpgradeToRevocableSessionAsync(string sessionToken, CancellationToken cancellationToken);
bool IsRevocableSessionToken(string sessionToken);
}
}

View File

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
/// <summary>
/// An abstraction for accessing persistent storage in the LeanCloud SDK.
/// </summary>
public interface IStorageController {
/// <summary>
/// Load the contents of this storage controller asynchronously.
/// </summary>
/// <returns></returns>
Task<IStorageDictionary<string, object>> LoadAsync();
/// <summary>
/// Overwrites the contents of this storage controller asynchronously.
/// </summary>
/// <param name="contents"></param>
/// <returns></returns>
Task<IStorageDictionary<string, object>> SaveAsync(IDictionary<string, object> contents);
}
/// <summary>
/// An interface for a dictionary that is persisted to disk asynchronously.
/// </summary>
/// <typeparam name="TKey">They key type of the dictionary.</typeparam>
/// <typeparam name="TValue">The value type of the dictionary.</typeparam>
public interface IStorageDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>> {
int Count { get; }
TValue this[TKey key] { get; }
IEnumerable<TKey> Keys { get; }
IEnumerable<TValue> Values { get; }
bool ContainsKey(TKey key);
bool TryGetValue(TKey key, out TValue value);
/// <summary>
/// Adds a key to this dictionary, and saves it asynchronously.
/// </summary>
/// <param name="key">The key to insert.</param>
/// <param name="value">The value to insert.</param>
/// <returns></returns>
Task AddAsync(TKey key, TValue value);
/// <summary>
/// Removes a key from this dictionary, and saves it asynchronously.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
Task RemoveAsync(TKey key);
}
}

View File

@ -6,28 +6,23 @@ using System.Collections.Generic;
using System.Threading;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal
{
namespace LeanCloud.Storage.Internal {
/// <summary>
/// Implements `IStorageController` for PCL targets, based off of PCLStorage.
/// </summary>
public class StorageController : IStorageController
{
private class StorageDictionary : IStorageDictionary<string, object>
{
public class StorageController {
public class StorageDictionary : IEnumerable<KeyValuePair<string, object>> {
private readonly string filePath;
private Dictionary<string, object> dictionary;
private Dictionary<string, object> dictionary;
readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
public StorageDictionary(string filePath)
{
public StorageDictionary(string filePath) {
this.filePath = filePath;
dictionary = new Dictionary<string, object>();
}
internal Task SaveAsync()
{
internal Task SaveAsync() {
string json;
locker.EnterReadLock();
json = JsonConvert.SerializeObject(dictionary);
@ -37,8 +32,7 @@ namespace LeanCloud.Storage.Internal
}
}
internal async Task LoadAsync()
{
internal async Task LoadAsync() {
using (var sr = new StreamReader(filePath)) {
var text = await sr.ReadToEndAsync();
Dictionary<string, object> result = null;
@ -54,31 +48,27 @@ namespace LeanCloud.Storage.Internal
}
}
internal void Update(IDictionary<string, object> contents)
{
internal void Update(IDictionary<string, object> contents) {
locker.EnterWriteLock();
dictionary = contents.ToDictionary(p => p.Key, p => p.Value);
locker.ExitWriteLock();
}
public Task AddAsync(string key, object value)
{
public Task AddAsync(string key, object value) {
locker.EnterWriteLock();
dictionary[key] = value;
locker.ExitWriteLock();
return SaveAsync();
}
public Task RemoveAsync(string key)
{
public Task RemoveAsync(string key) {
locker.EnterWriteLock();
dictionary.Remove(key);
locker.ExitWriteLock();
return SaveAsync();
}
public bool ContainsKey(string key)
{
public bool ContainsKey(string key) {
try {
locker.EnterReadLock();
return dictionary.ContainsKey(key);
@ -87,8 +77,7 @@ namespace LeanCloud.Storage.Internal
}
}
public IEnumerable<string> Keys
{
public IEnumerable<string> Keys {
get {
try {
locker.EnterReadLock();
@ -99,8 +88,7 @@ namespace LeanCloud.Storage.Internal
}
}
public bool TryGetValue(string key, out object value)
{
public bool TryGetValue(string key, out object value) {
try {
locker.EnterReadLock();
return dictionary.TryGetValue(key, out value);
@ -109,8 +97,7 @@ namespace LeanCloud.Storage.Internal
}
}
public IEnumerable<object> Values
{
public IEnumerable<object> Values {
get {
try {
locker.EnterReadLock();
@ -121,8 +108,7 @@ namespace LeanCloud.Storage.Internal
}
}
public object this[string key]
{
public object this[string key] {
get {
try {
locker.EnterReadLock();
@ -133,8 +119,7 @@ namespace LeanCloud.Storage.Internal
}
}
public int Count
{
public int Count {
get {
try {
locker.EnterReadLock();
@ -145,8 +130,7 @@ namespace LeanCloud.Storage.Internal
}
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
try {
locker.EnterReadLock();
return dictionary.GetEnumerator();
@ -155,8 +139,7 @@ namespace LeanCloud.Storage.Internal
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
try {
locker.EnterReadLock();
return dictionary.GetEnumerator();
@ -171,46 +154,38 @@ namespace LeanCloud.Storage.Internal
private readonly Task<string> fileTask;
private StorageDictionary storageDictionary;
public StorageController(string fileNamePrefix)
{
fileTask = taskQueue.Enqueue(t => t.ContinueWith(_ =>
{
public StorageController(string fileNamePrefix) {
fileTask = taskQueue.Enqueue(t => t.ContinueWith(_ => {
string path = $"{fileNamePrefix}_{LeanCloudStorageFileName}";
File.CreateText(path);
return path;
}), CancellationToken.None);
}
public Task<IStorageDictionary<string, object>> LoadAsync()
{
return taskQueue.Enqueue(toAwait =>
{
return toAwait.ContinueWith(_ =>
{
if (storageDictionary != null)
{
return Task.FromResult<IStorageDictionary<string, object>>(storageDictionary);
public Task<StorageDictionary> LoadAsync() {
return taskQueue.Enqueue(toAwait => {
return toAwait.ContinueWith(_ => {
if (storageDictionary != null) {
return Task.FromResult(storageDictionary);
}
storageDictionary = new StorageDictionary(fileTask.Result);
return storageDictionary.LoadAsync().OnSuccess(__ => storageDictionary as IStorageDictionary<string, object>);
return storageDictionary.LoadAsync()
.OnSuccess(__ => storageDictionary);
}).Unwrap();
}, CancellationToken.None);
}
public Task<IStorageDictionary<string, object>> SaveAsync(IDictionary<string, object> contents)
{
return taskQueue.Enqueue(toAwait =>
{
return toAwait.ContinueWith(_ =>
{
if (storageDictionary == null)
{
public Task<StorageDictionary> SaveAsync(IDictionary<string, object> contents) {
return taskQueue.Enqueue(toAwait => {
return toAwait.ContinueWith(_ => {
if (storageDictionary == null) {
storageDictionary = new StorageDictionary(fileTask.Result);
}
storageDictionary.Update(contents);
return storageDictionary.SaveAsync().OnSuccess(__ => storageDictionary as IStorageDictionary<string, object>);
return storageDictionary.SaveAsync()
.OnSuccess(__ => storageDictionary);
}).Unwrap();
}, CancellationToken.None);
}

View File

@ -9,17 +9,9 @@ using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal
{
public class AVCurrentUserController : IAVCurrentUserController
public class AVCurrentUserController
{
private readonly object mutex = new object();
private readonly TaskQueue taskQueue = new TaskQueue();
private IStorageController storageController;
public AVCurrentUserController(IStorageController storageController)
{
this.storageController = storageController;
}
private AVUser currentUser;
public AVUser CurrentUser
@ -45,7 +37,7 @@ namespace LeanCloud.Storage.Internal
Task saveTask = null;
if (user == null)
{
saveTask = storageController
saveTask = AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(t => t.Result.RemoveAsync("CurrentUser"))
.Unwrap();
@ -65,7 +57,7 @@ namespace LeanCloud.Storage.Internal
CultureInfo.InvariantCulture);
}
saveTask = storageController
saveTask = AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(t => t.Result.AddAsync("CurrentUser", JsonConvert.SerializeObject(data)))
.Unwrap();
@ -89,7 +81,7 @@ namespace LeanCloud.Storage.Internal
return Task<AVUser>.FromResult(cachedCurrent);
}
return storageController.LoadAsync().OnSuccess(t =>
return AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(t =>
{
object temp;
t.Result.TryGetValue("CurrentUser", out temp);
@ -114,7 +106,7 @@ namespace LeanCloud.Storage.Internal
return Task<bool>.FromResult(true);
}
return storageController.LoadAsync().OnSuccess(t => t.Result.ContainsKey("CurrentUser"));
return AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(t => t.Result.ContainsKey("CurrentUser"));
}
public bool IsCurrent(AVUser user)
@ -136,7 +128,7 @@ namespace LeanCloud.Storage.Internal
{
ClearFromMemory();
storageController.LoadAsync().OnSuccess(t => t.Result.RemoveAsync("CurrentUser"));
AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(t => t.Result.RemoveAsync("CurrentUser"));
}
}

View File

@ -6,15 +6,8 @@ using System.Net.Http;
namespace LeanCloud.Storage.Internal
{
public class AVUserController : IAVUserController
public class AVUserController
{
private readonly IAVCommandRunner commandRunner;
public AVUserController(IAVCommandRunner commandRunner)
{
this.commandRunner = commandRunner;
}
public Task<IObjectState> SignUpAsync(IObjectState state,
IDictionary<string, IAVFieldOperation> operations,
CancellationToken cancellationToken)
@ -25,7 +18,7 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = objectJSON
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone =>
@ -54,7 +47,7 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = data
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone =>
@ -80,7 +73,7 @@ namespace LeanCloud.Storage.Internal
{ "authData", authData}
}
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone =>
@ -97,7 +90,7 @@ namespace LeanCloud.Storage.Internal
Path = "users/me",
Method = HttpMethod.Get
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
});
@ -112,7 +105,7 @@ namespace LeanCloud.Storage.Internal
{ "email", email}
}
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
}
public Task<IObjectState> LogInWithParametersAsync(string relativeUrl, IDictionary<string, object> data,
@ -123,7 +116,7 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = data
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone =>
@ -144,7 +137,7 @@ namespace LeanCloud.Storage.Internal
{ "new_password", newPassword },
}
};
return commandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
}
public Task<IObjectState> RefreshSessionTokenAsync(string userId, string sessionToken,

View File

@ -1,11 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal {
public interface IAVCurrentUserController : IAVObjectCurrentController<AVUser> {
Task<string> GetCurrentSessionTokenAsync(CancellationToken cancellationToken);
Task LogOutAsync(CancellationToken cancellationToken);
}
}

View File

@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace LeanCloud.Storage.Internal
{
public interface IAVUserController
{
Task<IObjectState> SignUpAsync(IObjectState state,
IDictionary<string, IAVFieldOperation> operations,
CancellationToken cancellationToken);
Task<IObjectState> LogInAsync(string username,
string email,
string password,
CancellationToken cancellationToken);
Task<IObjectState> LogInWithParametersAsync(string relativeUrl,
IDictionary<string, object> data,
CancellationToken cancellationToken);
Task<IObjectState> LogInAsync(string authType,
IDictionary<string, object> data,
bool failOnNotExist,
CancellationToken cancellationToken);
Task<IObjectState> GetUserAsync(string sessionToken,
CancellationToken cancellationToken);
Task RequestPasswordResetAsync(string email,
CancellationToken cancellationToken);
Task UpdatePasswordAsync(string usedId, string sessionToken,
string oldPassword, string newPassword,
CancellationToken cancellationToken);
Task<IObjectState> RefreshSessionTokenAsync(string userId,
string sessionToken,
CancellationToken cancellationToken);
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
namespace LeanCloud.Storage.Internal {
/// <summary>
/// So here's the deal. We have a lot of internal APIs for AVObject, AVUser, etc.
///
/// These cannot be 'internal' anymore if we are fully modularizing things out, because
/// they are no longer a part of the same library, especially as we create things like
/// Installation inside push library.
///
/// So this class contains a bunch of extension methods that can live inside another
/// namespace, which 'wrap' the intenral APIs that already exist.
/// </summary>
public static class AVConfigExtensions {
public static AVConfig Create(IDictionary<string, object> fetchedConfig) {
return new AVConfig(fetchedConfig);
}
}
}

View File

@ -21,12 +21,9 @@ namespace LeanCloud {
/// await AVCloud.CallFunctionAsync&lt;IDictionary&lt;string, object&gt;&gt;("validateGame", parameters);
/// </code>
/// </example>
public static class AVCloud
{
internal static IAVCloudCodeController CloudCodeController
{
get
{
public static class AVCloud {
internal static AVCloudCodeController CloudCodeController {
get {
return AVPlugins.Instance.CloudCodeController;
}
}
@ -44,12 +41,10 @@ namespace LeanCloud {
/// <param name="sesstionToken"></param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The result of the cloud call.</returns>
public static Task<T> CallFunctionAsync<T>(String name, IDictionary<string, object> parameters = null, string sesstionToken = null, CancellationToken cancellationToken = default(CancellationToken))
{
public static Task<T> CallFunctionAsync<T>(String name, IDictionary<string, object> parameters = null, string sesstionToken = null, CancellationToken cancellationToken = default(CancellationToken)) {
var sessionTokenTask = AVUser.TakeSessionToken(sesstionToken);
return sessionTokenTask.OnSuccess(s =>
{
return sessionTokenTask.OnSuccess(s => {
return CloudCodeController.CallFunctionAsync<T>(name,
parameters, s.Result,
cancellationToken);
@ -66,12 +61,10 @@ namespace LeanCloud {
/// <param name="sesstionToken"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task<T> RPCFunctionAsync<T>(String name, IDictionary<string, object> parameters = null, string sesstionToken = null, CancellationToken cancellationToken = default(CancellationToken))
{
public static Task<T> RPCFunctionAsync<T>(String name, IDictionary<string, object> parameters = null, string sesstionToken = null, CancellationToken cancellationToken = default(CancellationToken)) {
var sessionTokenTask = AVUser.TakeSessionToken(sesstionToken);
return sessionTokenTask.OnSuccess(s =>
{
return sessionTokenTask.OnSuccess(s => {
return CloudCodeController.RPCFunction<T>(name,
parameters,
s.Result,
@ -87,8 +80,7 @@ namespace LeanCloud {
/// <param name="op">进行的操作名称。</param>
/// <param name="ttl">验证码失效时间。</param>
/// <returns></returns>
public static Task RequestSMSCodeAsync(string mobilePhoneNumber, string name, string op, int ttl = 10)
{
public static Task RequestSMSCodeAsync(string mobilePhoneNumber, string name, string op, int ttl = 10) {
return RequestSMSCodeAsync(mobilePhoneNumber, name, op, ttl, CancellationToken.None);
}
@ -102,10 +94,8 @@ namespace LeanCloud {
/// <param name="op">进行的操作名称。</param>
/// <param name="ttl">验证码失效时间。</param>
/// <param name="cancellationToken">Cancellation token。</param>
public static Task RequestSMSCodeAsync(string mobilePhoneNumber, string name, string op, int ttl = 10, CancellationToken cancellationToken = default(CancellationToken))
{
if (string.IsNullOrEmpty(mobilePhoneNumber))
{
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);
}
@ -113,16 +103,13 @@ namespace LeanCloud {
{
{ "mobilePhoneNumber", mobilePhoneNumber },
};
if (!string.IsNullOrEmpty(name))
{
if (!string.IsNullOrEmpty(name)) {
strs.Add("name", name);
}
if (!string.IsNullOrEmpty(op))
{
if (!string.IsNullOrEmpty(op)) {
strs.Add("op", op);
}
if (ttl > 0)
{
if (ttl > 0) {
strs.Add("TTL", ttl);
}
var command = new EngineCommand {
@ -138,8 +125,7 @@ namespace LeanCloud {
/// </summary>
/// <returns>是否发送成功。</returns>
/// <param name="mobilePhoneNumber">手机号。</param>
public static Task RequestSMSCodeAsync(string mobilePhoneNumber)
{
public static Task RequestSMSCodeAsync(string mobilePhoneNumber) {
return RequestSMSCodeAsync(mobilePhoneNumber, CancellationToken.None);
}
@ -150,8 +136,7 @@ namespace LeanCloud {
/// <returns>是否发送成功。</returns>
/// <param name="mobilePhoneNumber">手机号。</param>
/// <param name="cancellationToken">Cancellation Token.</param>
public static Task RequestSMSCodeAsync(string mobilePhoneNumber, CancellationToken cancellationToken)
{
public static Task RequestSMSCodeAsync(string mobilePhoneNumber, CancellationToken cancellationToken) {
return RequestSMSCodeAsync(mobilePhoneNumber, null, null, 0, cancellationToken);
}
@ -172,11 +157,9 @@ namespace LeanCloud {
IDictionary<string, object> env,
string sign = "",
string validateToken = "",
CancellationToken cancellationToken = default(CancellationToken))
{
CancellationToken cancellationToken = default(CancellationToken)) {
if (string.IsNullOrEmpty(mobilePhoneNumber))
{
if (string.IsNullOrEmpty(mobilePhoneNumber)) {
throw new AVException(AVException.ErrorCode.MobilePhoneInvalid, "Moblie Phone number is invalid.", null);
}
Dictionary<string, object> strs = new Dictionary<string, object>()
@ -184,16 +167,13 @@ namespace LeanCloud {
{ "mobilePhoneNumber", mobilePhoneNumber },
};
strs.Add("template", template);
if (String.IsNullOrEmpty(sign))
{
if (String.IsNullOrEmpty(sign)) {
strs.Add("sign", sign);
}
if (String.IsNullOrEmpty(validateToken))
{
if (String.IsNullOrEmpty(validateToken)) {
strs.Add("validate_token", validateToken);
}
foreach (var key in env.Keys)
{
foreach (var key in env.Keys) {
strs.Add(key, env[key]);
}
var command = new EngineCommand {
@ -209,10 +189,8 @@ namespace LeanCloud {
/// </summary>
/// <param name="mobilePhoneNumber"></param>
/// <returns></returns>
public static Task RequestVoiceCodeAsync(string mobilePhoneNumber)
{
if (string.IsNullOrEmpty(mobilePhoneNumber))
{
public static Task RequestVoiceCodeAsync(string mobilePhoneNumber) {
if (string.IsNullOrEmpty(mobilePhoneNumber)) {
throw new AVException(AVException.ErrorCode.MobilePhoneInvalid, "Moblie Phone number is invalid.", null);
}
Dictionary<string, object> body = new Dictionary<string, object>()
@ -237,8 +215,7 @@ namespace LeanCloud {
/// <returns>是否验证通过。</returns>
/// <param name="mobilePhoneNumber">手机号</param>
/// <param name="code">验证码。</param>
public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber)
{
public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber) {
return VerifySmsCodeAsync(code, mobilePhoneNumber, CancellationToken.None);
}
@ -249,8 +226,7 @@ namespace LeanCloud {
/// <param name="code">验证码。</param>
/// <param name="mobilePhoneNumber">手机号</param>
/// <param name="cancellationToken">Cancellation token.</param>
public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber, CancellationToken cancellationToken)
{
public static Task VerifySmsCodeAsync(string code, string mobilePhoneNumber, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = $"verifySmsCode/{code.Trim()}?mobilePhoneNumber={mobilePhoneNumber.Trim()}",
};
@ -260,8 +236,7 @@ namespace LeanCloud {
/// <summary>
/// Stands for a captcha result.
/// </summary>
public class Captcha
{
public class Captcha {
/// <summary>
/// Used for captcha verify.
/// </summary>
@ -278,8 +253,7 @@ namespace LeanCloud {
/// <param name="code">User's input of this captcha.</param>
/// <param name="cancellationToken">CancellationToken.</param>
/// <returns></returns>
public Task VerifyAsync(string code, CancellationToken cancellationToken = default(CancellationToken))
{
public Task VerifyAsync(string code, CancellationToken cancellationToken = default(CancellationToken)) {
return AVCloud.VerifyCaptchaAsync(code, Token);
}
}
@ -291,18 +265,15 @@ 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(CancellationToken))
{
public static Task<Captcha> 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 = $"requestCaptcha?width={width}&height={height}",
Method = HttpMethod.Get
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary<string, object>;
return new Captcha()
{
return new Captcha() {
Token = decoded["captcha_token"] as string,
Url = decoded["captcha_url"] as string,
};
@ -316,8 +287,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(CancellationToken))
{
public static Task<string> VerifyCaptchaAsync(string code, string token, CancellationToken cancellationToken = default(CancellationToken)) {
var data = new Dictionary<string, object> {
{ "captcha_token", token },
{ "captcha_code", code },
@ -327,8 +297,7 @@ namespace LeanCloud {
Method = HttpMethod.Post,
Content = data
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).ContinueWith(t =>
{
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(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;
@ -340,38 +309,32 @@ namespace LeanCloud {
/// </summary>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static Task<IDictionary<string, object>> GetCustomParametersAsync(CancellationToken cancellationToken = default(CancellationToken))
{
public static Task<IDictionary<string, object>> GetCustomParametersAsync(CancellationToken cancellationToken = default(CancellationToken)) {
var command = new AVCommand {
Path = $"statistics/apps/{AVClient.CurrentConfiguration.ApplicationId}/sendPolicy",
Method = HttpMethod.Get
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t => {
var settings = t.Result.Item2;
var CloudParameters = settings["parameters"] as IDictionary<string, object>;
return CloudParameters;
});
}
public class RealtimeSignature
{
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<RealtimeSignature> RequestRealtimeSignatureAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return AVUser.GetCurrentUserAsync(cancellationToken).OnSuccess(t =>
{
public static Task<RealtimeSignature> RequestRealtimeSignatureAsync(CancellationToken cancellationToken = default(CancellationToken)) {
return AVUser.GetCurrentUserAsync(cancellationToken).OnSuccess(t => {
return RequestRealtimeSignatureAsync(t.Result, cancellationToken);
}).Unwrap();
}
public static Task<RealtimeSignature> RequestRealtimeSignatureAsync(AVUser user, CancellationToken cancellationToken = default(CancellationToken))
{
public static Task<RealtimeSignature> RequestRealtimeSignatureAsync(AVUser user, CancellationToken cancellationToken = default(CancellationToken)) {
var command = new AVCommand {
Path = "rtm/sign",
Method = HttpMethod.Post,
@ -379,11 +342,9 @@ namespace LeanCloud {
{ "session_token", user.SessionToken }
}
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).ContinueWith(t =>
{
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).ContinueWith(t => {
var body = t.Result.Item2;
return new RealtimeSignature()
{
return new RealtimeSignature() {
Nonce = body["nonce"] as string,
Timestamp = (long)body["timestamp"],
ClientId = body["client_id"] as string,
@ -396,8 +357,7 @@ namespace LeanCloud {
/// Gets the LeanEngine hosting URL for current app async.
/// </summary>
/// <returns>The lean engine hosting URL async.</returns>
public static Task<string> GetLeanEngineHostingUrlAsync()
{
public static Task<string> GetLeanEngineHostingUrlAsync() {
return CallFunctionAsync<string>("_internal_extensions_get_domain");
}
@ -407,8 +367,7 @@ namespace LeanCloud {
/// <summary>
/// AVRPCC loud function base.
/// </summary>
public class AVRPCCloudFunctionBase<P, R>
{
public class AVRPCCloudFunctionBase<P, R> {
/// <summary>
/// AVRPCD eserialize.
/// </summary>
@ -419,17 +378,13 @@ namespace LeanCloud {
public delegate IDictionary<string, object> AVRPCSerialize<P>(P parameters);
public AVRPCCloudFunctionBase()
: this(true)
{
: this(true) {
}
public AVRPCCloudFunctionBase(bool noneParameters)
{
if (noneParameters)
{
this.Encode = n =>
{
public AVRPCCloudFunctionBase(bool noneParameters) {
if (noneParameters) {
this.Encode = n => {
return null;
};
}
@ -438,28 +393,21 @@ namespace LeanCloud {
private AVRPCDeserialize<R> _decode;
public AVRPCDeserialize<R> Decode
{
get
{
public AVRPCDeserialize<R> Decode {
get {
return _decode;
}
set
{
set {
_decode = value;
}
}
private AVRPCSerialize<P> _encode;
public AVRPCSerialize<P> Encode
{
get
{
if (_encode == null)
{
_encode = n =>
{
public AVRPCSerialize<P> Encode {
get {
if (_encode == null) {
_encode = n => {
if (n != null) {
return JsonConvert.DeserializeObject<Dictionary<string, object>>(n.ToString(), new LeanCloudJsonConverter());
}
@ -468,18 +416,15 @@ namespace LeanCloud {
}
return _encode;
}
set
{
set {
_encode = value;
}
}
public string FunctionName { get; set; }
public Task<R> ExecuteAsync(P parameters)
{
return AVUser.GetCurrentAsync().OnSuccess(t =>
{
public Task<R> ExecuteAsync(P parameters) {
return AVUser.GetCurrentAsync().OnSuccess(t => {
var user = t.Result;
var encodedParameters = Encode(parameters);
var command = new EngineCommand {
@ -488,11 +433,9 @@ namespace LeanCloud {
Content = encodedParameters
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
}).Unwrap().OnSuccess(s =>
{
}).Unwrap().OnSuccess(s => {
var responseBody = s.Result.Item2;
if (!responseBody.ContainsKey("result"))
{
if (!responseBody.ContainsKey("result")) {
return default(R);
}
@ -503,31 +446,24 @@ namespace LeanCloud {
}
public class AVObjectRPCCloudFunction : AVObjectRPCCloudFunction<AVObject>
{
public class AVObjectRPCCloudFunction : AVObjectRPCCloudFunction<AVObject> {
}
public class AVObjectListRPCCloudFunction : AVObjectListRPCCloudFunction<AVObject>
{
public class AVObjectListRPCCloudFunction : AVObjectListRPCCloudFunction<AVObject> {
}
public class AVObjectListRPCCloudFunction<R> : AVRPCCloudFunctionBase<object, IList<R>> where R : AVObject
{
public class AVObjectListRPCCloudFunction<R> : AVRPCCloudFunctionBase<object, IList<R>> where R : AVObject {
public AVObjectListRPCCloudFunction()
: base(true)
{
: base(true) {
this.Decode = this.AVObjectListDeserializer();
}
public AVRPCDeserialize<IList<R>> AVObjectListDeserializer()
{
AVRPCDeserialize<IList<R>> del = data =>
{
public AVRPCDeserialize<IList<R>> AVObjectListDeserializer() {
AVRPCDeserialize<IList<R>> del = data => {
var items = data["result"] as IList<object>;
return items.Select(item =>
{
return items.Select(item => {
var state = AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance);
return AVObject.FromState<AVObject>(state, state.ClassName);
}).ToList() as IList<R>;
@ -537,19 +473,15 @@ namespace LeanCloud {
}
}
public class AVObjectRPCCloudFunction<R> : AVRPCCloudFunctionBase<object, R> where R : AVObject
{
public class AVObjectRPCCloudFunction<R> : AVRPCCloudFunctionBase<object, R> where R : AVObject {
public AVObjectRPCCloudFunction()
: base(true)
{
: base(true) {
this.Decode = this.AVObjectDeserializer();
}
public AVRPCDeserialize<R> AVObjectDeserializer()
{
AVRPCDeserialize<R> del = data =>
{
public AVRPCDeserialize<R> AVObjectDeserializer() {
AVRPCDeserialize<R> del = data => {
var item = data["result"] as object;
var state = AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance);

View File

@ -1,143 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using LeanCloud.Storage.Internal;
using LeanCloud.Utilities;
namespace LeanCloud
{
/// <summary>
/// The AVConfig is a representation of the remote configuration object,
/// that enables you to add things like feature gating, a/b testing or simple "Message of the day".
/// </summary>
public class AVConfig : IJsonConvertible
{
private IDictionary<string, object> properties = new Dictionary<string, object>();
/// <summary>
/// Gets the latest fetched AVConfig.
/// </summary>
/// <returns>AVConfig object</returns>
public static AVConfig CurrentConfig
{
get
{
Task<AVConfig> task = ConfigController.CurrentConfigController.GetCurrentConfigAsync();
task.Wait();
return task.Result;
}
}
internal static void ClearCurrentConfig()
{
ConfigController.CurrentConfigController.ClearCurrentConfigAsync().Wait();
}
internal static void ClearCurrentConfigInMemory()
{
ConfigController.CurrentConfigController.ClearCurrentConfigInMemoryAsync().Wait();
}
private static IAVConfigController ConfigController
{
get { return AVPlugins.Instance.ConfigController; }
}
internal AVConfig()
: base()
{
}
internal AVConfig(IDictionary<string, object> fetchedConfig)
{
var props = AVDecoder.Instance.Decode(fetchedConfig["params"]) as IDictionary<string, object>;
properties = props;
}
/// <summary>
/// Retrieves the AVConfig asynchronously from the server.
/// </summary>
/// <returns>AVConfig object that was fetched</returns>
public static Task<AVConfig> GetAsync()
{
return GetAsync(CancellationToken.None);
}
/// <summary>
/// Retrieves the AVConfig asynchronously from the server.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>AVConfig object that was fetched</returns>
public static Task<AVConfig> GetAsync(CancellationToken cancellationToken)
{
return ConfigController.FetchConfigAsync(AVUser.CurrentSessionToken, cancellationToken);
}
/// <summary>
/// Gets a value for the key of a particular type.
/// </summary>
/// <typeparam name="T">The type to convert the value to. Supported types are
/// AVObject and its descendents, LeanCloud types such as AVRelation and AVGeopoint,
/// primitive types,IList&lt;T&gt;, IDictionary&lt;string, T&gt; and strings.</typeparam>
/// <param name="key">The key of the element to get.</param>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">The property is retrieved
/// and <paramref name="key"/> is not found.</exception>
/// <exception cref="System.FormatException">The property under this <paramref name="key"/>
/// key was found, but of a different type.</exception>
public T Get<T>(string key)
{
return Conversion.To<T>(this.properties[key]);
}
/// <summary>
/// Populates result with the value for the key, if possible.
/// </summary>
/// <typeparam name="T">The desired type for the value.</typeparam>
/// <param name="key">The key to retrieve a value for.</param>
/// <param name="result">The value for the given key, converted to the
/// requested type, or null if unsuccessful.</param>
/// <returns>true if the lookup and conversion succeeded, otherwise false.</returns>
public bool TryGetValue<T>(string key, out T result)
{
if (this.properties.ContainsKey(key))
{
try
{
var temp = Conversion.To<T>(this.properties[key]);
result = temp;
return true;
}
catch (Exception)
{
// Could not convert, do nothing
}
}
result = default(T);
return false;
}
/// <summary>
/// Gets a value on the config.
/// </summary>
/// <param name="key">The key for the parameter.</param>
/// <exception cref="System.Collections.Generic.KeyNotFoundException">The property is
/// retrieved and <paramref name="key"/> is not found.</exception>
/// <returns>The value for the key.</returns>
virtual public object this[string key]
{
get
{
return this.properties[key];
}
}
IDictionary<string, object> IJsonConvertible.ToJSON()
{
return new Dictionary<string, object> {
{ "params", NoObjectsEncoder.Instance.Encode(properties) }
};
}
}
}

View File

@ -272,7 +272,7 @@ namespace LeanCloud
}
}
internal static IAVFileController FileController
internal static AVFileController FileController
{
get
{

File diff suppressed because it is too large Load Diff

View File

@ -37,13 +37,13 @@ namespace LeanCloud
internal int? skip;
internal int? limit;
internal static IAVQueryController QueryController {
internal static AVQueryController QueryController {
get {
return AVPlugins.Instance.QueryController;
}
}
internal static IObjectSubclassingController SubclassingController {
internal static ObjectSubclassingController SubclassingController {
get {
return AVPlugins.Instance.SubclassingController;
}

View File

@ -31,7 +31,7 @@ namespace LeanCloud
this.targetClassName = targetClassName;
}
internal static IObjectSubclassingController SubclassingController
internal static ObjectSubclassingController SubclassingController
{
get
{

View File

@ -41,7 +41,7 @@ namespace LeanCloud
}
}
internal static IAVSessionController SessionController
internal static AVSessionController SessionController
{
get
{

View File

@ -20,7 +20,7 @@ namespace LeanCloud
"sessionToken", "isNew"
};
internal static IAVUserController UserController
internal static AVUserController UserController
{
get
{
@ -28,7 +28,7 @@ namespace LeanCloud
}
}
internal static IAVCurrentUserController CurrentUserController
internal static AVCurrentUserController CurrentUserController
{
get
{