From de83d2253492214132f996061272773083dc0594 Mon Sep 17 00:00:00 2001 From: oneRain Date: Wed, 7 Apr 2021 18:07:00 +0800 Subject: [PATCH] feat: support user persistence --- Storage/Storage.Standard/LCApplication.cs | 16 ++++ Storage/Storage.Standard/StandardStorage.cs | 9 ++ .../Storage.Standard/Storage.Standard.csproj | 14 +++ Storage/Storage.Unity/LCApplication.cs | 16 ++++ Storage/Storage.Unity/Storage.Unity.csproj | 18 ++++ Storage/Storage.Unity/UnityStorage.cs | 9 ++ Storage/Storage/Internal/Http/LCHttpClient.cs | 10 +-- Storage/Storage/Internal/Storage/IStorage.cs | 7 ++ .../Internal/Storage/StorageController.cs | 69 +++++++++++++++ Storage/Storage/LCCaptchaClient.cs | 4 +- Storage/Storage/LCCloud.cs | 4 +- Storage/Storage/LCFile.cs | 8 +- Storage/Storage/LCFriendship.cs | 6 +- ...pplication.cs => LCInternalApplication.cs} | 7 +- Storage/Storage/LCObject.cs | 20 ++--- Storage/Storage/LCQuery.cs | 6 +- Storage/Storage/LCSMSClient.cs | 6 +- Storage/Storage/LCStatus.cs | 10 +-- Storage/Storage/LCStatusQuery.cs | 2 +- Storage/Storage/LCUser.cs | 87 +++++++++++++------ Storage/Storage/Leaderboard/LCLeaderboard.cs | 22 ++--- Storage/Storage/Storage.csproj | 7 +- 22 files changed, 276 insertions(+), 81 deletions(-) create mode 100644 Storage/Storage.Standard/LCApplication.cs create mode 100644 Storage/Storage.Standard/StandardStorage.cs create mode 100644 Storage/Storage.Standard/Storage.Standard.csproj create mode 100644 Storage/Storage.Unity/LCApplication.cs create mode 100644 Storage/Storage.Unity/Storage.Unity.csproj create mode 100644 Storage/Storage.Unity/UnityStorage.cs create mode 100644 Storage/Storage/Internal/Storage/IStorage.cs create mode 100644 Storage/Storage/Internal/Storage/StorageController.cs rename Storage/Storage/{LCApplication.cs => LCInternalApplication.cs} (93%) diff --git a/Storage/Storage.Standard/LCApplication.cs b/Storage/Storage.Standard/LCApplication.cs new file mode 100644 index 0000000..714e264 --- /dev/null +++ b/Storage/Storage.Standard/LCApplication.cs @@ -0,0 +1,16 @@ +using LeanCloud.Storage.Internal.Storage; + +namespace LeanCloud { + public class LCApplication { + public static void Initialize(string appId, + string appKey, + string server = null, + string masterKey = null) { + LCLogger.Debug("Application Initializes on Standard."); + + LCInternalApplication.Initialize(appId, appKey, server, masterKey); + + LCInternalApplication.StorageController = new StorageController(null); + } + } +} diff --git a/Storage/Storage.Standard/StandardStorage.cs b/Storage/Storage.Standard/StandardStorage.cs new file mode 100644 index 0000000..4941ea9 --- /dev/null +++ b/Storage/Storage.Standard/StandardStorage.cs @@ -0,0 +1,9 @@ +using System; + +namespace LeanCloud.Storage.Internal.Storage { + public class StandardStorage : IStorage { + public string GetStoragePath() { + throw new NotImplementedException(); + } + } +} diff --git a/Storage/Storage.Standard/Storage.Standard.csproj b/Storage/Storage.Standard/Storage.Standard.csproj new file mode 100644 index 0000000..5b6caa2 --- /dev/null +++ b/Storage/Storage.Standard/Storage.Standard.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + 0.7.2 + Storage.Standard + true + + + + + + + diff --git a/Storage/Storage.Unity/LCApplication.cs b/Storage/Storage.Unity/LCApplication.cs new file mode 100644 index 0000000..ae6aff7 --- /dev/null +++ b/Storage/Storage.Unity/LCApplication.cs @@ -0,0 +1,16 @@ +using LeanCloud.Storage.Internal.Storage; + +namespace LeanCloud { + public class LCApplication { + public static void Initialize(string appId, + string appKey, + string server = null, + string masterKey = null) { + LCLogger.Debug("Application Initializes on Unity."); + + LCInternalApplication.Initialize(appId, appKey, server, masterKey); + + LCInternalApplication.StorageController = new StorageController(new UnityStorage()); + } + } +} diff --git a/Storage/Storage.Unity/Storage.Unity.csproj b/Storage/Storage.Unity/Storage.Unity.csproj new file mode 100644 index 0000000..c0699e9 --- /dev/null +++ b/Storage/Storage.Unity/Storage.Unity.csproj @@ -0,0 +1,18 @@ + + + + netstandard2.0 + 0.7.2 + Storage.Unity + true + + + + + + + + ..\..\Unity\UnityEngine.dll + + + diff --git a/Storage/Storage.Unity/UnityStorage.cs b/Storage/Storage.Unity/UnityStorage.cs new file mode 100644 index 0000000..039b744 --- /dev/null +++ b/Storage/Storage.Unity/UnityStorage.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace LeanCloud.Storage.Internal.Storage { + public class UnityStorage : IStorage { + public string GetStoragePath() { + return Application.persistentDataPath; + } + } +} diff --git a/Storage/Storage/Internal/Http/LCHttpClient.cs b/Storage/Storage/Internal/Http/LCHttpClient.cs index 4fd4a2e..7a4b0e9 100644 --- a/Storage/Storage/Internal/Http/LCHttpClient.cs +++ b/Storage/Storage/Internal/Http/LCHttpClient.cs @@ -120,7 +120,7 @@ namespace LeanCloud.Storage.Internal.Http { } async Task BuildUrl(string path, Dictionary queryParams = null) { - string apiServer = await LCApplication.AppRouter.GetApiServer(); + string apiServer = await LCInternalApplication.AppRouter.GetApiServer(); string url = $"{apiServer}/{apiVersion}/{path}"; if (queryParams != null) { IEnumerable queryPairs = queryParams.Select(kv => $"{kv.Key}={kv.Value}"); @@ -137,9 +137,9 @@ namespace LeanCloud.Storage.Internal.Http { headers.Add(kv.Key, kv.Value.ToString()); } } - if (LCApplication.UseMasterKey && !string.IsNullOrEmpty(LCApplication.MasterKey)) { + if (LCInternalApplication.UseMasterKey && !string.IsNullOrEmpty(LCInternalApplication.MasterKey)) { // Master Key - headers.Add("X-LC-Key", $"{LCApplication.MasterKey},master"); + headers.Add("X-LC-Key", $"{LCInternalApplication.MasterKey},master"); } else { // 签名 long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); @@ -148,8 +148,8 @@ namespace LeanCloud.Storage.Internal.Http { string sign = $"{hash},{timestamp}"; headers.Add("X-LC-Sign", sign); } - if (LCApplication.AdditionalHeaders.Count > 0) { - foreach (KeyValuePair kv in LCApplication.AdditionalHeaders) { + if (LCInternalApplication.AdditionalHeaders.Count > 0) { + foreach (KeyValuePair kv in LCInternalApplication.AdditionalHeaders) { headers.Add(kv.Key, kv.Value); } } diff --git a/Storage/Storage/Internal/Storage/IStorage.cs b/Storage/Storage/Internal/Storage/IStorage.cs new file mode 100644 index 0000000..4f0cf1e --- /dev/null +++ b/Storage/Storage/Internal/Storage/IStorage.cs @@ -0,0 +1,7 @@ +using System; + +namespace LeanCloud.Storage.Internal.Storage { + public interface IStorage { + string GetStoragePath(); + } +} diff --git a/Storage/Storage/Internal/Storage/StorageController.cs b/Storage/Storage/Internal/Storage/StorageController.cs new file mode 100644 index 0000000..3a79c50 --- /dev/null +++ b/Storage/Storage/Internal/Storage/StorageController.cs @@ -0,0 +1,69 @@ +using System; +using System.Reflection; +using System.Linq; +using System.Threading.Tasks; +using System.IO; +using System.Text; +using System.Collections.Generic; + +using IOFile = System.IO.File; + +namespace LeanCloud.Storage.Internal.Storage { + public class StorageController { + private readonly IStorage storage; + + public StorageController(IStorage storage) { + this.storage = storage; + } + + public async Task WriteText(string filename, string text) { + if (storage == null) { + return; + } + + string path = GetFileFullPath(filename); + LCLogger.Debug($"WRITE: {path}"); + LCLogger.Debug($"WRITE: {text}"); + using (FileStream fs = IOFile.OpenWrite(path)) { + byte[] buffer = Encoding.UTF8.GetBytes(text); + await fs.WriteAsync(buffer, 0, buffer.Length); + } + } + + public async Task ReadText(string filename) { + if (storage == null) { + return null; + } + + string path = GetFileFullPath(filename); + LCLogger.Debug($"READ: {path}"); + if (IOFile.Exists(path)) { + string text; + using (FileStream fs = IOFile.OpenRead(path)) { + byte[] buffer = new byte[fs.Length]; + await fs.ReadAsync(buffer, 0, (int)fs.Length); + text = Encoding.UTF8.GetString(buffer); + } + LCLogger.Debug($"READ: {text}"); + return text; + } + return null; + } + + public void Delete(string filename) { + if (storage == null) { + return; + } + + string path = GetFileFullPath(filename); + IOFile.Delete(path); + } + + private string GetFileFullPath(string filename) { + if (storage == null) { + throw new Exception("no IStrorage."); + } + return Path.Combine(storage.GetStoragePath(), filename); + } + } +} diff --git a/Storage/Storage/LCCaptchaClient.cs b/Storage/Storage/LCCaptchaClient.cs index f18d040..386e645 100644 --- a/Storage/Storage/LCCaptchaClient.cs +++ b/Storage/Storage/LCCaptchaClient.cs @@ -33,7 +33,7 @@ namespace LeanCloud.Storage { { "width", width }, { "height", height } }; - Dictionary response = await LCApplication.HttpClient.Get>(path, queryParams: queryParams); + Dictionary response = await LCInternalApplication.HttpClient.Get>(path, queryParams: queryParams); return new LCCapture { Url = response["captcha_url"] as string, Token = response["captcha_token"] as string @@ -60,7 +60,7 @@ namespace LeanCloud.Storage { { "captcha_code", code }, { "captcha_token", token } }; - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } } } diff --git a/Storage/Storage/LCCloud.cs b/Storage/Storage/LCCloud.cs index 99fcdda..188ee3a 100644 --- a/Storage/Storage/LCCloud.cs +++ b/Storage/Storage/LCCloud.cs @@ -30,7 +30,7 @@ namespace LeanCloud.Storage { { PRODUCTION_KEY, IsProduction ? 1 : 0 } }; object encodeParams = LCEncoder.Encode(parameters); - Dictionary response = await LCApplication.HttpClient.Post>(path, + Dictionary response = await LCInternalApplication.HttpClient.Post>(path, headers: headers, data: encodeParams); return response; @@ -57,7 +57,7 @@ namespace LeanCloud.Storage { { PRODUCTION_KEY, IsProduction ? 1 : 0 } }; object encodeParams = Encode(parameters); - Dictionary response = await LCApplication.HttpClient.Post>(path, + Dictionary response = await LCInternalApplication.HttpClient.Post>(path, headers: headers, data: encodeParams); return LCDecoder.Decode(response["result"]); diff --git a/Storage/Storage/LCFile.cs b/Storage/Storage/LCFile.cs index a27db7b..cb7c892 100644 --- a/Storage/Storage/LCFile.cs +++ b/Storage/Storage/LCFile.cs @@ -92,12 +92,12 @@ namespace LeanCloud.Storage { } LCObjectData objectData = LCObjectData.Decode(uploadToken); Merge(objectData); - _ = LCApplication.HttpClient.Post>("fileCallback", data: new Dictionary { + _ = LCInternalApplication.HttpClient.Post>("fileCallback", data: new Dictionary { { "result", true }, { "token", token } }); } catch (Exception e) { - _ = LCApplication.HttpClient.Post>("fileCallback", data: new Dictionary { + _ = LCInternalApplication.HttpClient.Post>("fileCallback", data: new Dictionary { { "result", false }, { "token", token } }); @@ -112,7 +112,7 @@ namespace LeanCloud.Storage { return; } string path = $"files/{ObjectId}"; - await LCApplication.HttpClient.Delete(path); + await LCInternalApplication.HttpClient.Delete(path); } public string GetThumbnailUrl(int width, int height, int quality = 100, bool scaleToFit = true, string format = "png") { @@ -128,7 +128,7 @@ namespace LeanCloud.Storage { { "mime_type", MimeType }, { "metaData", MetaData } }; - return await LCApplication.HttpClient.Post>("fileTokens", data: data); + return await LCInternalApplication.HttpClient.Post>("fileTokens", data: data); } public static LCQuery GetQuery() { diff --git a/Storage/Storage/LCFriendship.cs b/Storage/Storage/LCFriendship.cs index 40c0d13..4f91ab1 100644 --- a/Storage/Storage/LCFriendship.cs +++ b/Storage/Storage/LCFriendship.cs @@ -19,7 +19,7 @@ namespace LeanCloud.Storage { if (attributes != null) { data["friendship"] = attributes; } - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } public static async Task AcceptRequest(LCFriendshipRequest request, Dictionary attributes = null) { @@ -33,7 +33,7 @@ namespace LeanCloud.Storage { { "friendship", attributes } }; } - await LCApplication.HttpClient.Put>(path, data: data); + await LCInternalApplication.HttpClient.Put>(path, data: data); } public static async Task DeclineRequest(LCFriendshipRequest request) { @@ -41,7 +41,7 @@ namespace LeanCloud.Storage { throw new ArgumentNullException(nameof(request)); } string path = $"users/friendshipRequests/{request.ObjectId}/decline"; - await LCApplication.HttpClient.Put>(path); + await LCInternalApplication.HttpClient.Put>(path); } } } diff --git a/Storage/Storage/LCApplication.cs b/Storage/Storage/LCInternalApplication.cs similarity index 93% rename from Storage/Storage/LCApplication.cs rename to Storage/Storage/LCInternalApplication.cs index 8c00ce3..08dc6d0 100644 --- a/Storage/Storage/LCApplication.cs +++ b/Storage/Storage/LCInternalApplication.cs @@ -3,12 +3,13 @@ using System.Collections.Generic; using LeanCloud.Common; using LeanCloud.Storage; using LeanCloud.Storage.Internal.Http; +using LeanCloud.Storage.Internal.Storage; namespace LeanCloud { /// /// LeanCloud Application /// - public class LCApplication { + public class LCInternalApplication { // SDK 版本号,用于 User-Agent 统计 public const string SDKVersion = "0.7.2"; @@ -43,6 +44,10 @@ namespace LeanCloud { get; set; } + public static StorageController StorageController { + get; set; + } + internal static Dictionary AdditionalHeaders { get; } = new Dictionary(); diff --git a/Storage/Storage/LCObject.cs b/Storage/Storage/LCObject.cs index d50523a..980c1e5 100644 --- a/Storage/Storage/LCObject.cs +++ b/Storage/Storage/LCObject.cs @@ -304,7 +304,7 @@ namespace LeanCloud.Storage { { "requests", LCEncoder.Encode(requestList) } }; - List> results = await LCApplication.HttpClient.Post>>("batch", data: data); + List> results = await LCInternalApplication.HttpClient.Post>>("batch", data: data); List resultList = results.Select(item => { if (item.TryGetValue("error", out object error)) { Dictionary err = error as Dictionary; @@ -342,8 +342,8 @@ namespace LeanCloud.Storage { queryParams["where"] = query.BuildWhere(); } Dictionary response = ObjectId == null ? - await LCApplication.HttpClient.Post>(path, data: LCEncoder.Encode(operationDict) as Dictionary, queryParams: queryParams) : - await LCApplication.HttpClient.Put>(path, data: LCEncoder.Encode(operationDict) as Dictionary, queryParams: queryParams); + await LCInternalApplication.HttpClient.Post>(path, data: LCEncoder.Encode(operationDict) as Dictionary, queryParams: queryParams) : + await LCInternalApplication.HttpClient.Put>(path, data: LCEncoder.Encode(operationDict) as Dictionary, queryParams: queryParams); LCObjectData data = LCObjectData.Decode(response); Merge(data); return this; @@ -368,7 +368,7 @@ namespace LeanCloud.Storage { return; } string path = $"classes/{ClassName}/{ObjectId}"; - await LCApplication.HttpClient.Delete(path); + await LCInternalApplication.HttpClient.Delete(path); } public static async Task DeleteAll(IEnumerable objects) { @@ -377,7 +377,7 @@ namespace LeanCloud.Storage { } HashSet objectSet = new HashSet(objects.Where(item => item.ObjectId != null)); List> requestList = objectSet.Select(item => { - string path = $"/{LCApplication.APIVersion}/classes/{item.ClassName}/{item.ObjectId}"; + string path = $"/{LCInternalApplication.APIVersion}/classes/{item.ClassName}/{item.ObjectId}"; return new Dictionary { { "path", path }, { "method", "DELETE" } @@ -386,7 +386,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "requests", LCEncoder.Encode(requestList) } }; - await LCApplication.HttpClient.Post>("batch", data: data); + await LCInternalApplication.HttpClient.Post>("batch", data: data); } public async Task Fetch(IEnumerable keys = null, IEnumerable includes = null) { @@ -398,7 +398,7 @@ namespace LeanCloud.Storage { queryParams["include"] = string.Join(",", includes); } string path = $"classes/{ClassName}/{ObjectId}"; - Dictionary response = await LCApplication.HttpClient.Get>(path, queryParams: queryParams); + Dictionary response = await LCInternalApplication.HttpClient.Get>(path, queryParams: queryParams); LCObjectData objectData = LCObjectData.Decode(response); Merge(objectData); return this; @@ -411,7 +411,7 @@ namespace LeanCloud.Storage { IEnumerable uniqueObjects = objects.Where(item => item.ObjectId != null); List> requestList = uniqueObjects.Select(item => { - string path = $"/{LCApplication.APIVersion}/classes/{item.ClassName}/{item.ObjectId}"; + string path = $"/{LCInternalApplication.APIVersion}/classes/{item.ClassName}/{item.ObjectId}"; return new Dictionary { { "path", path }, { "method", "GET" } @@ -421,7 +421,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "requests", LCEncoder.Encode(requestList) } }; - List> results = await LCApplication.HttpClient.Post>>("batch", + List> results = await LCInternalApplication.HttpClient.Post>>("batch", data: data); Dictionary dict = new Dictionary(); foreach (Dictionary item in results) { @@ -455,7 +455,7 @@ namespace LeanCloud.Storage { public override string ToString() { Dictionary originalData = LCObjectData.Encode(data); Dictionary currentData = estimatedData.Union(originalData.Where(kv => !estimatedData.ContainsKey(kv.Key))) - .ToDictionary(k => k.Key, v => v.Value); + .ToDictionary(k => k.Key, v => LCEncoder.Encode(v.Value)); return JsonConvert.SerializeObject(currentData); } diff --git a/Storage/Storage/LCQuery.cs b/Storage/Storage/LCQuery.cs index b04d457..52b417f 100644 --- a/Storage/Storage/LCQuery.cs +++ b/Storage/Storage/LCQuery.cs @@ -342,7 +342,7 @@ namespace LeanCloud.Storage { Dictionary parameters = BuildParams(); parameters["limit"] = 0; parameters["count"] = 1; - Dictionary ret = await LCApplication.HttpClient.Get>(path, queryParams: parameters); + Dictionary ret = await LCInternalApplication.HttpClient.Get>(path, queryParams: parameters); return (int)ret["count"]; } @@ -358,14 +358,14 @@ namespace LeanCloud.Storage { { "include", includes } }; } - Dictionary response = await LCApplication.HttpClient.Get>(path, queryParams: queryParams); + Dictionary response = await LCInternalApplication.HttpClient.Get>(path, queryParams: queryParams); return DecodeLCObject(response); } public async Task> Find() { string path = $"classes/{ClassName}"; Dictionary parameters = BuildParams(); - Dictionary response = await LCApplication.HttpClient.Get>(path, queryParams: parameters); + Dictionary response = await LCInternalApplication.HttpClient.Get>(path, queryParams: parameters); List results = response["results"] as List; List list = new List(); foreach (object item in results) { diff --git a/Storage/Storage/LCSMSClient.cs b/Storage/Storage/LCSMSClient.cs index 187fbaf..d23947d 100644 --- a/Storage/Storage/LCSMSClient.cs +++ b/Storage/Storage/LCSMSClient.cs @@ -43,7 +43,7 @@ namespace LeanCloud.Storage { data[kv.Key] = kv.Value; } } - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } /// @@ -57,7 +57,7 @@ namespace LeanCloud.Storage { { "mobilePhoneNumber", mobile }, { "smsType", "voice" } }; - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } public static async Task VerifyMobilePhone(string mobile, string code) { @@ -65,7 +65,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "mobilePhoneNumber", mobile } }; - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } } } diff --git a/Storage/Storage/LCStatus.cs b/Storage/Storage/LCStatus.cs index fa2f103..33fe383 100644 --- a/Storage/Storage/LCStatus.cs +++ b/Storage/Storage/LCStatus.cs @@ -109,7 +109,7 @@ namespace LeanCloud.Storage { } formData["query"] = queryData; } - Dictionary response = await LCApplication.HttpClient.Post>("statuses", + Dictionary response = await LCInternalApplication.HttpClient.Post>("statuses", data: formData); LCObjectData objectData = LCObjectData.Decode(response); Merge(objectData); @@ -125,14 +125,14 @@ namespace LeanCloud.Storage { LCUser source = (Data[SourceKey] ?? this[SourceKey]) as LCUser; if (source != null && source.ObjectId == user.ObjectId) { - await LCApplication.HttpClient.Delete($"statuses/{ObjectId}"); + await LCInternalApplication.HttpClient.Delete($"statuses/{ObjectId}"); } else { Dictionary data = new Dictionary { { OwnerKey, JsonConvert.SerializeObject(LCEncoder.Encode(user)) }, { InboxTypeKey, InboxType }, { MessageIdKey, MessageId } }; - await LCApplication.HttpClient.Delete("subscribe/statuses/inbox", queryParams: data); + await LCInternalApplication.HttpClient.Delete("subscribe/statuses/inbox", queryParams: data); } } @@ -148,7 +148,7 @@ namespace LeanCloud.Storage { if (!string.IsNullOrEmpty(inboxType)) { queryParams[InboxTypeKey] = inboxType; } - Dictionary response = await LCApplication.HttpClient.Get>("subscribe/statuses/count", + Dictionary response = await LCInternalApplication.HttpClient.Get>("subscribe/statuses/count", queryParams: queryParams); LCStatusCount statusCount = new LCStatusCount { Total = (int)response["total"], @@ -169,7 +169,7 @@ namespace LeanCloud.Storage { if (!string.IsNullOrEmpty(inboxType)) { queryParams[InboxTypeKey] = inboxType; } - await LCApplication.HttpClient.Post>("subscribe/statuses/resetUnreadCount", + await LCInternalApplication.HttpClient.Post>("subscribe/statuses/resetUnreadCount", queryParams:queryParams); } } diff --git a/Storage/Storage/LCStatusQuery.cs b/Storage/Storage/LCStatusQuery.cs index f43a871..f035982 100644 --- a/Storage/Storage/LCStatusQuery.cs +++ b/Storage/Storage/LCStatusQuery.cs @@ -41,7 +41,7 @@ namespace LeanCloud.Storage { { "maxId", MaxId }, { "limit", Condition.Limit } }; - Dictionary response = await LCApplication.HttpClient.Get>("subscribe/statuses", + Dictionary response = await LCInternalApplication.HttpClient.Get>("subscribe/statuses", queryParams: queryParams); List results = response["results"] as List; List statuses = new List(); diff --git a/Storage/Storage/LCUser.cs b/Storage/Storage/LCUser.cs index 7a5b1dd..abca204 100644 --- a/Storage/Storage/LCUser.cs +++ b/Storage/Storage/LCUser.cs @@ -8,6 +8,8 @@ namespace LeanCloud.Storage { public class LCUser : LCObject { public const string CLASS_NAME = "_User"; + private const string USER_DATA = ".userdata"; + public string Username { get { return this["username"] as string; @@ -76,10 +78,21 @@ namespace LeanCloud.Storage { static LCUser currentUser; - public static Task GetCurrent() { - // TODO 加载持久化数据 + public static async Task GetCurrent() { + if (currentUser != null) { + return currentUser; + } - return Task.FromResult(currentUser); + string data = await LCInternalApplication.StorageController.ReadText(USER_DATA); + if (!string.IsNullOrEmpty(data)) { + try { + currentUser = ParseObject(data) as LCUser; + } catch (Exception e) { + LCLogger.Error(e); + LCInternalApplication.StorageController.Delete(USER_DATA); + } + } + return currentUser; } public LCUser() : base(CLASS_NAME) { @@ -106,7 +119,8 @@ namespace LeanCloud.Storage { } await Save(); currentUser = this; - // TODO Persistence + + await SaveToLocal(); return this; } @@ -123,7 +137,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "mobilePhoneNumber", mobile } }; - await LCApplication.HttpClient.Post>("requestLoginSmsCode", data: data); + await LCInternalApplication.HttpClient.Post>("requestLoginSmsCode", data: data); } /// @@ -143,9 +157,12 @@ namespace LeanCloud.Storage { { "mobilePhoneNumber", mobile }, { "smsCode", code } }; - Dictionary response = await LCApplication.HttpClient.Post>("usersByMobilePhone", data: data); + Dictionary response = await LCInternalApplication.HttpClient.Post>("usersByMobilePhone", data: data); LCObjectData objectData = LCObjectData.Decode(response); currentUser = new LCUser(objectData); + + await SaveToLocal(); + return currentUser; } @@ -353,7 +370,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "email", email } }; - await LCApplication.HttpClient.Post>("requestEmailVerify", data: data); + await LCInternalApplication.HttpClient.Post>("requestEmailVerify", data: data); } /// @@ -368,7 +385,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "mobilePhoneNumber", mobile } }; - await LCApplication.HttpClient.Post>("requestMobilePhoneVerify", data: data); + await LCInternalApplication.HttpClient.Post>("requestMobilePhoneVerify", data: data); } /// @@ -388,7 +405,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "mobilePhoneNumber", mobile } }; - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } /// @@ -403,7 +420,7 @@ namespace LeanCloud.Storage { Dictionary headers = new Dictionary { { "X-LC-Session", sessionToken } }; - Dictionary response = await LCApplication.HttpClient.Get>("users/me", + Dictionary response = await LCInternalApplication.HttpClient.Get>("users/me", headers: headers); LCObjectData objectData = LCObjectData.Decode(response); currentUser = new LCUser(objectData); @@ -422,7 +439,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "email", email } }; - await LCApplication.HttpClient.Post>("requestPasswordReset", + await LCInternalApplication.HttpClient.Post>("requestPasswordReset", data: data); } @@ -438,7 +455,7 @@ namespace LeanCloud.Storage { Dictionary data = new Dictionary { { "mobilePhoneNumber", mobile } }; - await LCApplication.HttpClient.Post>("requestPasswordResetBySmsCode", + await LCInternalApplication.HttpClient.Post>("requestPasswordResetBySmsCode", data: data); } @@ -463,7 +480,7 @@ namespace LeanCloud.Storage { { "mobilePhoneNumber", mobile }, { "password", newPassword } }; - await LCApplication.HttpClient.Put>($"resetPasswordBySmsCode/{code}", + await LCInternalApplication.HttpClient.Put>($"resetPasswordBySmsCode/{code}", data: data); } @@ -484,7 +501,7 @@ namespace LeanCloud.Storage { { "old_password", oldPassword }, { "new_password", newPassword } }; - Dictionary response = await LCApplication.HttpClient.Put>( + Dictionary response = await LCInternalApplication.HttpClient.Put>( $"users/{ObjectId}/updatePassword", data:data); LCObjectData objectData = LCObjectData.Decode(response); Merge(objectData); @@ -495,8 +512,8 @@ namespace LeanCloud.Storage { /// public static Task Logout() { currentUser = null; - // TODO 清理持久化数据 - + // 清理持久化数据 + LCInternalApplication.StorageController.Delete(USER_DATA); return Task.FromResult(null); } @@ -509,7 +526,7 @@ namespace LeanCloud.Storage { return false; } try { - await LCApplication.HttpClient.Get>("users/me"); + await LCInternalApplication.HttpClient.Get>("users/me"); return true; } catch (Exception) { return false; @@ -532,7 +549,7 @@ namespace LeanCloud.Storage { try { await Save(); oriAuthData[authType] = data; - UpdateAuthData(oriAuthData); + await UpdateAuthData(oriAuthData); } catch (Exception e) { AuthData = oriAuthData; throw e; @@ -547,23 +564,27 @@ namespace LeanCloud.Storage { try { await Save(); oriAuthData.Remove(authType); - UpdateAuthData(oriAuthData); + await UpdateAuthData(oriAuthData); } catch (Exception e) { AuthData = oriAuthData; throw e; } } - private void UpdateAuthData(Dictionary authData) { + private async Task UpdateAuthData(Dictionary authData) { LCObjectData objData = new LCObjectData(); objData.CustomPropertyDict["authData"] = authData; Merge(objData); + await SaveToLocal(); } static async Task Login(Dictionary data) { - Dictionary response = await LCApplication.HttpClient.Post>("login", data: data); + Dictionary response = await LCInternalApplication.HttpClient.Post>("login", data: data); LCObjectData objectData = LCObjectData.Decode(response); currentUser = new LCUser(objectData); + + await SaveToLocal(); + return currentUser; } @@ -572,11 +593,14 @@ namespace LeanCloud.Storage { { authType, data } }; string path = failOnNotExist ? "users?failOnNotExist=true" : "users"; - Dictionary response = await LCApplication.HttpClient.Post>(path, data: new Dictionary { + Dictionary response = await LCInternalApplication.HttpClient.Post>(path, data: new Dictionary { { "authData", authData } }); LCObjectData objectData = LCObjectData.Decode(response); currentUser = new LCUser(objectData); + + await SaveToLocal(); + return currentUser; } @@ -586,6 +610,15 @@ namespace LeanCloud.Storage { authData["unionid"] = unionId; } + private static async Task SaveToLocal() { + try { + string json = currentUser.ToString(); + await LCInternalApplication.StorageController.WriteText(USER_DATA, json); + } catch (Exception e) { + LCLogger.Error(e.Message); + } + } + /// /// Requests an SMS code for updating phone number. /// @@ -602,7 +635,7 @@ namespace LeanCloud.Storage { if (!string.IsNullOrEmpty(captchaToken)) { data["validate_token"] = captchaToken; } - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } /// @@ -617,7 +650,7 @@ namespace LeanCloud.Storage { { "mobilePhoneNumber", mobile }, { "code", code } }; - await LCApplication.HttpClient.Post>(path, data: data); + await LCInternalApplication.HttpClient.Post>(path, data: data); } /// @@ -631,7 +664,7 @@ namespace LeanCloud.Storage { throw new ArgumentNullException(nameof(targetId)); } string path = $"users/self/friendship/{targetId}"; - await LCApplication.HttpClient.Post>(path, data: attrs); + await LCInternalApplication.HttpClient.Post>(path, data: attrs); } /// @@ -644,7 +677,7 @@ namespace LeanCloud.Storage { throw new ArgumentNullException(nameof(targetId)); } string path = $"users/self/friendship/{targetId}"; - await LCApplication.HttpClient.Delete(path); + await LCInternalApplication.HttpClient.Delete(path); } /// @@ -684,7 +717,7 @@ namespace LeanCloud.Storage { queryParams["include"] = string.Join(",", includes); } string path = $"users/{ObjectId}/followersAndFollowees"; - Dictionary response = await LCApplication.HttpClient.Get>(path, + Dictionary response = await LCInternalApplication.HttpClient.Get>(path, queryParams: queryParams); LCFollowersAndFollowees result = new LCFollowersAndFollowees(); if (response.TryGetValue("followers", out object followersObj) && diff --git a/Storage/Storage/Leaderboard/LCLeaderboard.cs b/Storage/Storage/Leaderboard/LCLeaderboard.cs index 29b39b7..a6d3e31 100644 --- a/Storage/Storage/Leaderboard/LCLeaderboard.cs +++ b/Storage/Storage/Leaderboard/LCLeaderboard.cs @@ -68,7 +68,7 @@ namespace LeanCloud.Storage { { "updateStrategy", updateStrategy.ToString().ToLower() }, }; string path = "leaderboard/leaderboards"; - Dictionary result = await LCApplication.HttpClient.Post>(path, + Dictionary result = await LCInternalApplication.HttpClient.Post>(path, data:data); LCLeaderboard leaderboard = new LCLeaderboard(); leaderboard.Merge(result); @@ -112,7 +112,7 @@ namespace LeanCloud.Storage { if (overwrite) { path = $"{path}?overwrite=1"; } - Dictionary result = await LCApplication.HttpClient.Post>(path, + Dictionary result = await LCInternalApplication.HttpClient.Post>(path, data: data); if (result.TryGetValue("results", out object results) && results is List list) { @@ -137,7 +137,7 @@ namespace LeanCloud.Storage { string names = string.Join(",", statisticNames); path = $"{path}?statistics={names}"; } - Dictionary result = await LCApplication.HttpClient.Get>(path); + Dictionary result = await LCInternalApplication.HttpClient.Get>(path); if (result.TryGetValue("results", out object results) && results is List list) { List statistics = new List(); @@ -161,7 +161,7 @@ namespace LeanCloud.Storage { } string names = string.Join(",", statisticNames); string path = $"leaderboard/users/{user.ObjectId}/statistics?statistics={names}"; - await LCApplication.HttpClient.Delete(path); + await LCInternalApplication.HttpClient.Delete(path); } /// @@ -179,7 +179,7 @@ namespace LeanCloud.Storage { throw new ArgumentOutOfRangeException(nameof(limit)); } string path = $"leaderboard/leaderboards/{StatisticName}/archives?skip={skip}&limit={limit}"; - Dictionary result = await LCApplication.HttpClient.Get>(path); + Dictionary result = await LCInternalApplication.HttpClient.Get>(path); if (result.TryGetValue("results", out object results) && results is List list) { List archives = new List(); @@ -235,7 +235,7 @@ namespace LeanCloud.Storage { string statistics = string.Join(",", includeStatistics); path = $"{path}&includeStatistics={statistics}"; } - Dictionary result = await LCApplication.HttpClient.Get>(path); + Dictionary result = await LCInternalApplication.HttpClient.Get>(path); if (result.TryGetValue("results", out object results) && results is List list) { List rankings = new List(); @@ -254,7 +254,7 @@ namespace LeanCloud.Storage { { "updateStrategy", updateStrategy.ToString().ToLower() } }; string path = $"leaderboard/leaderboards/{StatisticName}"; - Dictionary result = await LCApplication.HttpClient.Put>(path, + Dictionary result = await LCInternalApplication.HttpClient.Put>(path, data: data); if (result.TryGetValue("updateStrategy", out object strategy) && Enum.TryParse(strategy as string, true, out LCLeaderboardUpdateStrategy s)) { @@ -269,7 +269,7 @@ namespace LeanCloud.Storage { { "versionChangeInterval", versionChangeInterval.ToString().ToLower() } }; string path = $"leaderboard/leaderboards/{StatisticName}"; - Dictionary result = await LCApplication.HttpClient.Put>(path, + Dictionary result = await LCInternalApplication.HttpClient.Put>(path, data: data); if (result.TryGetValue("versionChangeInterval", out object interval) && Enum.TryParse(interval as string, true, out LCLeaderboardVersionChangeInterval i)) { @@ -284,7 +284,7 @@ namespace LeanCloud.Storage { /// public async Task Fetch() { string path = $"leaderboard/leaderboards/{StatisticName}"; - Dictionary result = await LCApplication.HttpClient.Get>(path); + Dictionary result = await LCInternalApplication.HttpClient.Get>(path); Merge(result); return this; } @@ -295,7 +295,7 @@ namespace LeanCloud.Storage { /// public async Task Reset() { string path = $"leaderboard/leaderboards/{StatisticName}/incrementVersion"; - Dictionary result = await LCApplication.HttpClient.Put>(path); + Dictionary result = await LCInternalApplication.HttpClient.Put>(path); Merge(result); return this; } @@ -306,7 +306,7 @@ namespace LeanCloud.Storage { /// public async Task Destroy() { string path = $"leaderboard/leaderboards/{StatisticName}"; - await LCApplication.HttpClient.Delete(path); + await LCInternalApplication.HttpClient.Delete(path); } private void Merge(Dictionary data) { diff --git a/Storage/Storage/Storage.csproj b/Storage/Storage/Storage.csproj index f18515b..f052102 100644 --- a/Storage/Storage/Storage.csproj +++ b/Storage/Storage/Storage.csproj @@ -7,9 +7,6 @@ true - - - @@ -19,8 +16,10 @@ + - + +