chore: 简化
parent
905cc943bf
commit
81b2ea993f
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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"))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
// });
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,12 +21,9 @@ namespace LeanCloud {
|
|||
/// await AVCloud.CallFunctionAsync<IDictionary<string, object>>("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);
|
||||
|
||||
|
|
|
@ -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<T>, IDictionary<string, T> 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) }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace LeanCloud
|
|||
this.targetClassName = targetClassName;
|
||||
}
|
||||
|
||||
internal static IObjectSubclassingController SubclassingController
|
||||
internal static ObjectSubclassingController SubclassingController
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace LeanCloud
|
|||
}
|
||||
}
|
||||
|
||||
internal static IAVSessionController SessionController
|
||||
internal static AVSessionController SessionController
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue