chore: 清理了 AVUser 及持久化

oneRain 2019-08-09 17:34:08 +08:00
parent 148f51967e
commit 6b52376069
9 changed files with 273 additions and 1104 deletions

View File

@ -18,7 +18,6 @@ namespace LeanCloud.Storage.Internal {
private AppRouterController appRouterController;
private AVCommandRunner commandRunner;
private StorageController storageController;
private AVCloudCodeController cloudCodeController;
private AVFileController fileController;
@ -32,7 +31,6 @@ namespace LeanCloud.Storage.Internal {
#region Current Instance Controller
private AVCurrentUserController currentUserController;
private InstallationIdController installationIdController;
#endregion
@ -41,7 +39,6 @@ namespace LeanCloud.Storage.Internal {
lock (mutex) {
AppRouterController = null;
CommandRunner = null;
StorageController = null;
CloudCodeController = null;
FileController = null;
@ -50,7 +47,6 @@ namespace LeanCloud.Storage.Internal {
UserController = null;
SubclassingController = null;
CurrentUserController = null;
InstallationIdController = null;
}
}
@ -83,36 +79,6 @@ namespace LeanCloud.Storage.Internal {
}
}
#if UNITY
public StorageController StorageController {
get {
lock (mutex) {
storageController = storageController ?? new StorageController(AVInitializeBehaviour.IsWebPlayer, AVClient.CurrentConfiguration.ApplicationId);
return storageController;
}
}
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 AVCloudCodeController CloudCodeController {
get {
lock (mutex) {
@ -212,26 +178,12 @@ namespace LeanCloud.Storage.Internal {
}
}
public AVCurrentUserController CurrentUserController {
get {
lock (mutex) {
currentUserController = currentUserController ?? new AVCurrentUserController();
return currentUserController;
}
}
set {
lock (mutex) {
currentUserController = value;
}
}
}
public ObjectSubclassingController SubclassingController {
get {
lock (mutex) {
if (subclassingController == null) {
subclassingController = new ObjectSubclassingController();
subclassingController.AddRegisterHook(typeof(AVUser), () => CurrentUserController.ClearFromMemory());
//subclassingController.AddRegisterHook(typeof(AVUser), () => CurrentUserController.ClearFromMemory());
}
return subclassingController;
}

View File

@ -1,191 +0,0 @@
using System;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal {
public class StorageController {
public class StorageDictionary : IEnumerable<KeyValuePair<string, object>> {
private readonly string filePath;
private Dictionary<string, object> dictionary;
readonly ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
public StorageDictionary(string filePath) {
this.filePath = filePath;
dictionary = new Dictionary<string, object>();
}
internal async Task SaveAsync() {
string json;
locker.EnterReadLock();
json = await JsonUtils.SerializeObjectAsync(dictionary);
locker.ExitReadLock();
using (var sw = new StreamWriter(filePath)) {
await sw.WriteAsync(json);
}
}
internal async Task LoadAsync() {
using (var sr = new StreamReader(filePath)) {
var text = await sr.ReadToEndAsync();
Dictionary<string, object> result = null;
try {
result = JsonConvert.DeserializeObject<Dictionary<string, object>>(text, new LeanCloudJsonConverter());
} catch (Exception e) {
AVClient.PrintLog(e.Message);
}
locker.EnterWriteLock();
dictionary = result ?? new Dictionary<string, object>();
locker.ExitWriteLock();
}
}
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) {
locker.EnterWriteLock();
dictionary[key] = value;
locker.ExitWriteLock();
return SaveAsync();
}
public Task RemoveAsync(string key) {
locker.EnterWriteLock();
dictionary.Remove(key);
locker.ExitWriteLock();
return SaveAsync();
}
public bool ContainsKey(string key) {
try {
locker.EnterReadLock();
return dictionary.ContainsKey(key);
} finally {
locker.ExitReadLock();
}
}
public IEnumerable<string> Keys {
get {
try {
locker.EnterReadLock();
return dictionary.Keys;
} finally {
locker.ExitReadLock();
}
}
}
public bool TryGetValue(string key, out object value) {
try {
locker.EnterReadLock();
return dictionary.TryGetValue(key, out value);
} finally {
locker.ExitReadLock();
}
}
public IEnumerable<object> Values {
get {
try {
locker.EnterReadLock();
return dictionary.Values;
} finally {
locker.ExitReadLock();
}
}
}
public object this[string key] {
get {
try {
locker.EnterReadLock();
return dictionary[key];
} finally {
locker.ExitReadLock();
}
}
}
public int Count {
get {
try {
locker.EnterReadLock();
return dictionary.Count;
} finally {
locker.ExitReadLock();
}
}
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
try {
locker.EnterReadLock();
return dictionary.GetEnumerator();
} finally {
locker.ExitReadLock();
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
try {
locker.EnterReadLock();
return dictionary.GetEnumerator();
} finally {
locker.ExitReadLock();
}
}
}
private const string LeanCloudStorageFileName = "ApplicationSettings";
private readonly TaskQueue taskQueue = new TaskQueue();
private readonly Task<string> fileTask;
private StorageDictionary storageDictionary;
private IDictionary<string, object> storage;
public StorageController(string fileNamePrefix) {
fileTask = taskQueue.Enqueue(t => t.ContinueWith(_ => {
string path = $"{fileNamePrefix}_{LeanCloudStorageFileName}";
File.CreateText(path);
return path;
}), CancellationToken.None);
}
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);
}).Unwrap();
}, CancellationToken.None);
}
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);
}).Unwrap();
}, CancellationToken.None);
}
}
}

View File

@ -1,152 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using LeanCloud.Storage.Internal;
using Newtonsoft.Json;
namespace LeanCloud.Storage.Internal
{
public class AVCurrentUserController
{
private readonly object mutex = new object();
private AVUser currentUser;
public AVUser CurrentUser
{
get
{
lock (mutex)
{
return currentUser;
}
}
set
{
lock (mutex)
{
currentUser = value;
}
}
}
public Task SetAsync(AVUser user, CancellationToken cancellationToken)
{
Task saveTask = null;
if (user == null)
{
saveTask = AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(t => t.Result.RemoveAsync("CurrentUser"))
.Unwrap();
}
else
{
var data = user.ServerDataToJSONObjectForSerialization();
data["objectId"] = user.ObjectId;
if (user.CreatedAt != null)
{
data["createdAt"] = user.CreatedAt.Value.ToString(AVClient.DateFormatStrings.First(),
CultureInfo.InvariantCulture);
}
if (user.UpdatedAt != null)
{
data["updatedAt"] = user.UpdatedAt.Value.ToString(AVClient.DateFormatStrings.First(),
CultureInfo.InvariantCulture);
}
saveTask = AVPlugins.Instance.StorageController
.LoadAsync()
.OnSuccess(t => t.Result.AddAsync("CurrentUser", JsonConvert.SerializeObject(data)))
.Unwrap();
}
CurrentUser = user;
return saveTask;
}
public Task<AVUser> GetAsync(CancellationToken cancellationToken)
{
AVUser cachedCurrent;
lock (mutex)
{
cachedCurrent = CurrentUser;
}
if (cachedCurrent != null)
{
return Task<AVUser>.FromResult(cachedCurrent);
}
return AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(t =>
{
object temp;
t.Result.TryGetValue("CurrentUser", out temp);
var userDataString = temp as string;
AVUser user = null;
if (userDataString != null)
{
var userData = JsonConvert.DeserializeObject<Dictionary<string, object>>(userDataString, new LeanCloudJsonConverter());
var state = AVObjectCoder.Instance.Decode(userData, AVDecoder.Instance);
user = AVObject.FromState<AVUser>(state, "_User");
}
CurrentUser = user;
return user;
});
}
public Task<bool> ExistsAsync(CancellationToken cancellationToken)
{
if (CurrentUser != null)
{
return Task<bool>.FromResult(true);
}
return AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(t => t.Result.ContainsKey("CurrentUser"));
}
public bool IsCurrent(AVUser user)
{
lock (mutex)
{
return CurrentUser == user;
}
}
public void ClearFromMemory()
{
CurrentUser = null;
}
public void ClearFromDisk()
{
lock (mutex)
{
ClearFromMemory();
AVPlugins.Instance.StorageController.LoadAsync().OnSuccess(t => t.Result.RemoveAsync("CurrentUser"));
}
}
public Task<string> GetCurrentSessionTokenAsync(CancellationToken cancellationToken)
{
return GetAsync(cancellationToken).OnSuccess(t =>
{
var user = t.Result;
return user == null ? null : user.SessionToken;
});
}
public Task LogOutAsync(CancellationToken cancellationToken)
{
return GetAsync(cancellationToken).OnSuccess(t =>
{
ClearFromDisk();
});
}
}
}

View File

@ -1,38 +1,26 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http;
namespace LeanCloud.Storage.Internal
{
public class AVUserController
{
public Task<IObjectState> SignUpAsync(IObjectState state,
IDictionary<string, IAVFieldOperation> operations,
CancellationToken cancellationToken)
{
namespace LeanCloud.Storage.Internal {
public class AVUserController {
public async Task<IObjectState> SignUpAsync(IObjectState state, IDictionary<string, IAVFieldOperation> operations, CancellationToken cancellationToken) {
var objectJSON = AVObject.ToJSONObjectForSaving(operations);
var command = new AVCommand {
Path = "classes/_User",
Method = HttpMethod.Post,
Content = objectJSON
};
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 =>
{
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = true;
});
return serverState;
});
}
public Task<IObjectState> LogInAsync(string username, string email,
string password,
CancellationToken cancellationToken)
{
public async Task<IObjectState> LogInAsync(string username, string email, string password, CancellationToken cancellationToken) {
var data = new Dictionary<string, object>{
{ "password", password}
};
@ -47,24 +35,18 @@ namespace LeanCloud.Storage.Internal
Method = HttpMethod.Post,
Content = data
};
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;
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created;
});
return serverState;
});
}
public Task<IObjectState> LogInAsync(string authType,
IDictionary<string, object> data,
bool failOnNotExist,
CancellationToken cancellationToken)
{
var authData = new Dictionary<string, object>();
authData[authType] = data;
public async Task<IObjectState> LogInAsync(string authType, IDictionary<string, object> data, bool failOnNotExist, CancellationToken cancellationToken) {
var authData = new Dictionary<string, object> {
[authType] = data
};
var path = failOnNotExist ? "users?failOnNotExist=true" : "users";
var command = new AVCommand {
Path = path,
@ -73,31 +55,24 @@ namespace LeanCloud.Storage.Internal
{ "authData", authData}
}
};
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;
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created;
});
return serverState;
});
}
public Task<IObjectState> GetUserAsync(string sessionToken, CancellationToken cancellationToken)
{
public async Task<IObjectState> GetUserAsync(string sessionToken, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = "users/me",
Method = HttpMethod.Get
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken).OnSuccess(t =>
{
return AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
});
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
return AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
}
public Task RequestPasswordResetAsync(string email, CancellationToken cancellationToken)
{
public async Task RequestPasswordResetAsync(string email, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = "requestPasswordReset",
Method = HttpMethod.Post,
@ -105,30 +80,24 @@ namespace LeanCloud.Storage.Internal
{ "email", email}
}
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
}
public Task<IObjectState> LogInWithParametersAsync(string relativeUrl, IDictionary<string, object> data,
CancellationToken cancellationToken)
{
public async Task<IObjectState> LogInWithParametersAsync(string relativeUrl, IDictionary<string, object> data, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = relativeUrl,
Method = HttpMethod.Post,
Content = data
};
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;
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
serverState = serverState.MutatedClone(mutableClone => {
mutableClone.IsNew = ret.Item1 == System.Net.HttpStatusCode.Created;
});
return serverState;
});
}
public Task UpdatePasswordAsync(string userId, string sessionToken, string oldPassword, string newPassword, CancellationToken cancellationToken)
{
public async Task UpdatePasswordAsync(string userId, string sessionToken, string oldPassword, string newPassword, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = $"users/{userId}/updatePassword",
Method = HttpMethod.Put,
@ -137,21 +106,17 @@ namespace LeanCloud.Storage.Internal
{ "new_password", newPassword },
}
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken: cancellationToken);
await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command, cancellationToken);
}
public Task<IObjectState> RefreshSessionTokenAsync(string userId, string sessionToken,
CancellationToken cancellationToken)
{
public async Task<IObjectState> RefreshSessionTokenAsync(string userId, string sessionToken, CancellationToken cancellationToken) {
var command = new AVCommand {
Path = $"users/{userId}/refreshSessionToken",
Method = HttpMethod.Put
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(t =>
{
var serverState = AVObjectCoder.Instance.Decode(t.Result.Item2, AVDecoder.Instance);
var ret = await AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
var serverState = AVObjectCoder.Instance.Decode(ret.Item2, AVDecoder.Instance);
return serverState;
});
}
}
}

View File

@ -270,7 +270,6 @@ namespace LeanCloud {
internal static void Clear() {
AVPlugins.Instance.AppRouterController.Clear();
AVPlugins.Instance.Reset();
AVUser.ClearInMemoryUser();
}
/// <summary>

View File

@ -42,14 +42,9 @@ namespace LeanCloud {
/// <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)) {
var sessionTokenTask = AVUser.TakeSessionToken(sesstionToken);
return sessionTokenTask.OnSuccess(s => {
return CloudCodeController.CallFunctionAsync<T>(name,
parameters, s.Result,
parameters, AVUser.CurrentUser.SessionToken,
cancellationToken);
}).Unwrap();
}
/// <summary>
@ -62,14 +57,9 @@ namespace LeanCloud {
/// <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)) {
var sessionTokenTask = AVUser.TakeSessionToken(sesstionToken);
return sessionTokenTask.OnSuccess(s => {
return CloudCodeController.RPCFunction<T>(name,
parameters,
s.Result,
parameters, AVUser.CurrentUser.SessionToken,
cancellationToken);
}).Unwrap();
}
/// <summary>
@ -329,9 +319,7 @@ namespace LeanCloud {
}
public static Task<RealtimeSignature> RequestRealtimeSignatureAsync(CancellationToken cancellationToken = default(CancellationToken)) {
return AVUser.GetCurrentUserAsync(cancellationToken).OnSuccess(t => {
return RequestRealtimeSignatureAsync(t.Result, cancellationToken);
}).Unwrap();
return RequestRealtimeSignatureAsync(AVUser.CurrentUser, cancellationToken);
}
public static Task<RealtimeSignature> RequestRealtimeSignatureAsync(AVUser user, CancellationToken cancellationToken = default(CancellationToken)) {
@ -424,16 +412,13 @@ namespace LeanCloud {
public string FunctionName { get; set; }
public Task<R> ExecuteAsync(P parameters) {
return AVUser.GetCurrentAsync().OnSuccess(t => {
var user = t.Result;
var encodedParameters = Encode(parameters);
var command = new EngineCommand {
Path = $"call/{Uri.EscapeUriString(FunctionName)}",
Method = HttpMethod.Post,
Content = encodedParameters
};
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command);
}).Unwrap().OnSuccess(s => {
return AVPlugins.Instance.CommandRunner.RunCommandAsync<IDictionary<string, object>>(command).OnSuccess(s => {
var responseBody = s.Result.Item2;
if (!responseBody.ContainsKey("result")) {
return default(R);
@ -441,7 +426,6 @@ namespace LeanCloud {
return Decode(responseBody);
});
}
}

View File

@ -204,11 +204,7 @@ namespace LeanCloud
public Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default)
{
return AVUser.GetCurrentUserAsync().OnSuccess(t =>
{
return QueryController.FindAsync<T>(this, t.Result, cancellationToken);
}).Unwrap().OnSuccess(t =>
{
return QueryController.FindAsync<T>(this, AVUser.CurrentUser, cancellationToken).OnSuccess(t => {
IEnumerable<IObjectState> states = t.Result;
return (from state in states
select AVObject.FromState<T>(state, ClassName));
@ -217,11 +213,7 @@ namespace LeanCloud
public Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default)
{
return AVUser.GetCurrentUserAsync().OnSuccess(t =>
{
return QueryController.FirstAsync<T>(this, t.Result, cancellationToken);
}).Unwrap().OnSuccess(t =>
{
return QueryController.FirstAsync<T>(this, AVUser.CurrentUser, cancellationToken).OnSuccess(t => {
IObjectState state = t.Result;
return state == null ? default : AVObject.FromState<T>(state, ClassName);
});
@ -242,9 +234,7 @@ namespace LeanCloud
public Task<int> CountAsync(CancellationToken cancellationToken = default)
{
return AVUser.GetCurrentUserAsync().OnSuccess(t => {
return QueryController.CountAsync<T>(this, t.Result, cancellationToken);
}).Unwrap();
return QueryController.CountAsync(this, AVUser.CurrentUser, cancellationToken);
}
public Task<T> GetAsync(string objectId, CancellationToken cancellationToken)

View File

@ -63,17 +63,13 @@ namespace LeanCloud
/// <param name="cancellationToken">The cancellation token</param>
public static Task<AVSession> GetCurrentSessionAsync(CancellationToken cancellationToken)
{
return AVUser.GetCurrentUserAsync().OnSuccess(t1 =>
{
AVUser user = t1.Result;
if (user == null)
{
AVUser user = AVUser.CurrentUser;
if (user == null) {
return Task<AVSession>.FromResult((AVSession)null);
}
string sessionToken = user.SessionToken;
if (sessionToken == null)
{
if (sessionToken == null) {
return Task<AVSession>.FromResult((AVSession)null);
}
@ -82,7 +78,6 @@ namespace LeanCloud
AVSession session = AVObject.FromState<AVSession>(t.Result, "_Session");
return session;
});
}).Unwrap();
}
internal static Task RevokeAsync(string sessionToken, CancellationToken cancellationToken)

File diff suppressed because it is too large Load Diff