diff --git a/Storage/Storage/Internal/AppRouter/AppRouterController.cs b/Storage/Storage/Internal/AppRouter/AppRouterController.cs index d8ce0e9..3ff229d 100644 --- a/Storage/Storage/Internal/AppRouter/AppRouterController.cs +++ b/Storage/Storage/Internal/AppRouter/AppRouterController.cs @@ -1,9 +1,7 @@ using System; using System.Net; -using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; using System.Net.Http; namespace LeanCloud.Storage.Internal { diff --git a/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs b/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs index 3850752..0777066 100644 --- a/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs +++ b/Storage/Storage/Internal/Cloud/Controller/AVCloudCodeController.cs @@ -5,43 +5,35 @@ using System.Threading.Tasks; using LeanCloud.Utilities; using System.Net.Http; -namespace LeanCloud.Storage.Internal -{ - public class AVCloudCodeController - { +namespace LeanCloud.Storage.Internal { + public class AVCloudCodeController { public Task CallFunctionAsync(String name, IDictionary parameters, string sessionToken, - CancellationToken cancellationToken) - { + CancellationToken cancellationToken) { var command = new EngineCommand { Path = $"functions/{Uri.EscapeUriString(name)}", Method = HttpMethod.Post, Content = parameters }; - return AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken: cancellationToken).OnSuccess(t => - { + return AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary; - if (!decoded.ContainsKey("result")) - { + if (!decoded.ContainsKey("result")) { return default(T); } return Conversion.To(decoded["result"]); }); } - public Task RPCFunction(string name, IDictionary parameters, string sessionToken, CancellationToken cancellationToken) - { + public Task RPCFunction(string name, IDictionary parameters, string sessionToken, CancellationToken cancellationToken) { var command = new EngineCommand { Path = $"call/{Uri.EscapeUriString(name)}", Method = HttpMethod.Post, Content = parameters }; - return AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken: cancellationToken).OnSuccess(t => - { + return AVPlugins.Instance.CommandRunner.RunCommandAsync>(command, cancellationToken: cancellationToken).OnSuccess(t => { var decoded = AVDecoder.Instance.Decode(t.Result.Item2) as IDictionary; - if (!decoded.ContainsKey("result")) - { + if (!decoded.ContainsKey("result")) { return default(T); } return Conversion.To(decoded["result"]); diff --git a/Storage/Storage/Internal/Command/AVCommandRunner.cs b/Storage/Storage/Internal/Command/AVCommandRunner.cs index 00e0cd1..1411ac6 100644 --- a/Storage/Storage/Internal/Command/AVCommandRunner.cs +++ b/Storage/Storage/Internal/Command/AVCommandRunner.cs @@ -36,7 +36,7 @@ namespace LeanCloud.Storage.Internal { Content = new StringContent(JsonConvert.SerializeObject(command.Content)) }; - var headers = await GetHeadersAsync(); + var headers = GetHeadersAsync(); foreach (var header in headers) { if (!string.IsNullOrEmpty(header.Value)) { request.Headers.Add(header.Key, header.Value); @@ -89,10 +89,10 @@ namespace LeanCloud.Storage.Internal { private const string revocableSessionTokenTrueValue = "1"; - async Task> GetHeadersAsync() { + Dictionary GetHeadersAsync() { var headers = new Dictionary(); - var installationId = await AVPlugins.Instance.InstallationIdController.GetAsync(); - headers.Add("X-LC-Installation-Id", installationId.ToString()); + var installationId = AVPlugins.Instance.InstallationIdController.Get(); + headers.Add("X-LC-Installation-Id", installationId); var conf = AVClient.CurrentConfiguration; headers.Add("X-LC-Id", conf.ApplicationId); long timestamp = (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds; diff --git a/Storage/Storage/Internal/InstallationId/Controller/InstallationIdController.cs b/Storage/Storage/Internal/InstallationId/Controller/InstallationIdController.cs index ceb22e7..64c8ad7 100644 --- a/Storage/Storage/Internal/InstallationId/Controller/InstallationIdController.cs +++ b/Storage/Storage/Internal/InstallationId/Controller/InstallationIdController.cs @@ -1,59 +1,39 @@ using System; -using System.Threading.Tasks; +using System.IO; namespace LeanCloud.Storage.Internal { + /// + /// 临时方案,后面将有 Android 和 iOS 提供 device token + /// public class InstallationIdController { - private const string InstallationIdKey = "InstallationId"; + private string installationId; private readonly object mutex = new object(); - private Guid? installationId; - public Task SetAsync(Guid? installationId) { - lock (mutex) { - Task saveTask; - - 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 GetAsync() { - lock (mutex) { - if (installationId != null) { - return Task.FromResult(installationId); + public string Get() { + if (installationId == null) { + lock (mutex) { + if (installationId == null) { + string installationPath = "installation.conf"; + // 文件读取或从 Native 平台读取 + if (File.Exists(installationPath)) { + using (StreamReader reader = new StreamReader(installationPath)) { + installationId = reader.ReadToEnd(); + if (installationId != null) { + return installationId; + } + } + } + // 生成新的 device token + Guid newInstallationId = Guid.NewGuid(); + installationId = newInstallationId.ToString(); + // 写回文件 + using (StreamWriter writer = new StreamWriter(installationPath)) { + writer.Write(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(_ => newInstallationId); - } - }) - .Unwrap(); - } - - public Task ClearAsync() { - return SetAsync(null); + return installationId; } } } diff --git a/Storage/Storage/Internal/Object/Controller/IAVObjectCurrentController.cs b/Storage/Storage/Internal/Object/Controller/IAVObjectCurrentController.cs deleted file mode 100644 index e9b6f40..0000000 --- a/Storage/Storage/Internal/Object/Controller/IAVObjectCurrentController.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace LeanCloud.Storage.Internal { - /// - /// IAVObjectCurrentController controls the single-instance - /// persistence used throughout the code-base. Sample usages are and - /// . - /// - /// Type of object being persisted. - public interface IAVObjectCurrentController where T : AVObject { - /// - /// Persists current . - /// - /// to be persisted. - /// The cancellation token. - Task SetAsync(T obj, CancellationToken cancellationToken); - - /// - /// Gets the persisted current . - /// - /// The cancellation token. - Task GetAsync(CancellationToken cancellationToken); - - /// - /// Returns a that resolves to true if current - /// exists. - /// - /// The cancellation token. - Task ExistsAsync(CancellationToken cancellationToken); - - /// - /// Returns true if the given is the persisted current - /// . - /// - /// The object to check. - /// True if obj is the current persisted . - bool IsCurrent(T obj); - - /// - /// Nullifies the current from memory. - /// - void ClearFromMemory(); - - /// - /// Clears current from disk. - /// - void ClearFromDisk(); - } -} diff --git a/Storage/Storage/Internal/Object/Subclassing/ObjectSubclassingController.cs b/Storage/Storage/Internal/Object/Subclassing/ObjectSubclassingController.cs index 442e246..4c9fdd5 100644 --- a/Storage/Storage/Internal/Object/Subclassing/ObjectSubclassingController.cs +++ b/Storage/Storage/Internal/Object/Subclassing/ObjectSubclassingController.cs @@ -30,14 +30,11 @@ namespace LeanCloud.Storage.Internal { } public Type GetType(string className) { - ObjectSubclassInfo info = null; mutex.EnterReadLock(); - registeredSubclasses.TryGetValue(className, out info); + registeredSubclasses.TryGetValue(className, out ObjectSubclassInfo info); mutex.ExitReadLock(); - return info != null - ? info.TypeInfo.AsType() - : null; + return info?.TypeInfo.AsType(); } public bool IsTypeValid(string className, Type type) { diff --git a/Storage/Storage/Internal/Storage/StorageController.cs b/Storage/Storage/Internal/Storage/StorageController.cs index 6dd4d60..9950f6f 100644 --- a/Storage/Storage/Internal/Storage/StorageController.cs +++ b/Storage/Storage/Internal/Storage/StorageController.cs @@ -19,13 +19,13 @@ namespace LeanCloud.Storage.Internal { dictionary = new Dictionary(); } - internal Task SaveAsync() { + internal async Task SaveAsync() { string json; locker.EnterReadLock(); - json = JsonConvert.SerializeObject(dictionary); + json = await JsonUtils.SerializeObjectAsync(dictionary); locker.ExitReadLock(); using (var sw = new StreamWriter(filePath)) { - return sw.WriteAsync(json); + await sw.WriteAsync(json); } } @@ -150,6 +150,7 @@ namespace LeanCloud.Storage.Internal { private readonly TaskQueue taskQueue = new TaskQueue(); private readonly Task fileTask; private StorageDictionary storageDictionary; + private IDictionary storage; public StorageController(string fileNamePrefix) { fileTask = taskQueue.Enqueue(t => t.ContinueWith(_ => { diff --git a/Storage/Storage/Internal/Utilities/JsonExtensions.cs b/Storage/Storage/Internal/Utilities/JsonExtensions.cs index af58f27..1860133 100644 --- a/Storage/Storage/Internal/Utilities/JsonExtensions.cs +++ b/Storage/Storage/Internal/Utilities/JsonExtensions.cs @@ -3,17 +3,24 @@ using Newtonsoft.Json; using System.Threading.Tasks; namespace LeanCloud.Storage.Internal { + /// + /// 为 Json 解析提供异步接口 + /// public static class JsonUtils { - public static Task DeserializeObjectAsync(string str) { - var tcs = new TaskCompletionSource(); - Task.Run(() => { - try { - tcs.SetResult(JsonConvert.DeserializeObject(str)); - } catch (Exception e) { - tcs.SetException(e); - } + public static async Task SerializeObjectAsync(object obj) { + string str = null; + await Task.Run(() => { + str = JsonConvert.SerializeObject(obj); }); - return tcs.Task; + return str; + } + + public static async Task DeserializeObjectAsync(string str, params JsonConverter[] converters) { + T obj = default; + await Task.Run(() => { + obj = JsonConvert.DeserializeObject(str, converters); + }); + return obj; } } }