chore: refactor controller

oneRain 2021-03-19 17:02:57 +08:00
parent b8de05e867
commit d3ad99e0f6
9 changed files with 317 additions and 230 deletions

View File

@ -0,0 +1,84 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Cors;
using LeanCloud.Storage.Internal.Object;
using LeanCloud.Storage;
namespace LeanCloud.Engine {
[ApiController]
[Route("{1,1.1}")]
[EnableCors(LCEngine.LCEngineCORS)]
public class LCClassHookController : ControllerBase {
private Dictionary<string, MethodInfo> ClassHooks => LCEngine.ClassHooks;
[HttpPost("functions/{className}/{hookName}")]
public async Task<object> Hook(string className, string hookName, JsonElement body) {
try {
LCLogger.Debug($"Hook: {className}#{hookName}");
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(Request);
string classHookName = GetClassHookName(className, hookName);
if (ClassHooks.TryGetValue(classHookName, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
objectData.ClassName = className;
LCObject obj = LCObject.Create(className);
obj.Merge(objectData);
// 避免死循环
if (hookName.StartsWith("before")) {
obj.DisableBeforeHook();
} else {
obj.DisableAfterHook();
}
LCUser user = null;
if (dict.TryGetValue("user", out object userObj) &&
userObj != null) {
user = new LCUser();
user.Merge(LCObjectData.Decode(userObj as Dictionary<string, object>));
}
LCClassHookRequest req = new LCClassHookRequest {
Object = obj,
CurrentUser = user
};
LCObject result = await LCEngine.Invoke(mi, req) as LCObject;
if (result != null) {
return LCCloud.Encode(result);
}
}
return default;
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
private static string GetClassHookName(string className, string hookName) {
switch (hookName) {
case "beforeSave":
return $"__before_save_for_{className}";
case "afterSave":
return $"__after_save_for_{className}";
case "beforeUpdate":
return $"__before_update_for_{className}";
case "afterUpdate":
return $"__after_update_for_{className}";
case "beforeDelete":
return $"__before_delete_for_{className}";
case "afterDelete":
return $"__after_delete_for_{className}";
default:
throw new Exception($"Error hook name: {hookName}");
}
}
}
}

View File

@ -0,0 +1,92 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNetCore.Cors;
using LeanCloud.Storage.Internal.Codec;
using LeanCloud.Storage;
namespace LeanCloud.Engine {
[ApiController]
[Route("{1,1.1}")]
[EnableCors(LCEngine.LCEngineCORS)]
public class LCFunctionController : ControllerBase {
private Dictionary<string, MethodInfo> Functions => LCEngine.Functions;
[HttpGet("functions/_ops/metadatas")]
public object GetFunctions() {
try {
return LCEngine.GetFunctions(Request);
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
[HttpPost("functions/{funcName}")]
public async Task<object> Run(string funcName, JsonElement body) {
try {
LCLogger.Debug($"Run: {funcName}");
LCLogger.Debug(body.ToString());
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
LCUser currentUser = null;
if (Request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
currentUser = await LCUser.BecomeWithSessionToken(session);
}
LCCloudFunctionRequest req = new LCCloudFunctionRequest {
Meta = new LCCloudFunctionRequestMeta {
RemoteAddress = LCEngine.GetIP(Request)
},
Params = LCEngine.Decode(body),
SessionToken = session.ToString(),
User = currentUser
};
object result = await LCEngine.Invoke(mi, req);
if (result != null) {
return new Dictionary<string, object> {
{ "result", result }
};
}
}
return default;
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
[HttpPost("call/{funcName}")]
public async Task<object> RPC(string funcName, JsonElement body) {
try {
LCLogger.Debug($"RPC: {funcName}");
LCLogger.Debug(body.ToString());
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
LCUser currentUser = null;
if (Request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
currentUser = await LCUser.BecomeWithSessionToken(session);
}
LCCloudRPCRequest req = new LCCloudRPCRequest {
Meta = new LCCloudFunctionRequestMeta {
RemoteAddress = LCEngine.GetIP(Request)
},
Params = LCDecoder.Decode(LCEngine.Decode(body)),
SessionToken = session.ToString(),
User = currentUser
};
object result = await LCEngine.Invoke(mi, req);
if (result != null) {
return new Dictionary<string, object> {
{ "result", LCCloud.Encode(result) }
};
}
}
return default;
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
}
}

View File

@ -1,10 +1,17 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Cors;
namespace LeanCloud.Engine {
public class LCPingHandler {
public static object HandlePing() {
[ApiController]
[Route("__engine/{1,1.1}")]
[EnableCors(LCEngine.LCEngineCORS)]
public class LCPingController : ControllerBase {
[HttpGet("ping")]
public object Get() {
LCLogger.Debug("Ping ~~~");
return new Dictionary<string, string> {
{ "runtime", $"dotnet-{Environment.Version}" },
{ "version", LCApplication.SDKVersion }

View File

@ -0,0 +1,86 @@
using System;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Cors;
using LeanCloud.Storage.Internal.Object;
using LeanCloud.Storage;
namespace LeanCloud.Engine {
[ApiController]
[Route("{1,1.1}/functions")]
[EnableCors(LCEngine.LCEngineCORS)]
public class LCUserHookController : ControllerBase {
private Dictionary<string, MethodInfo> UserHooks => LCEngine.UserHooks;
[HttpPost("onVerified/sms")]
public async Task<object> HookSMSVerification(JsonElement body) {
try {
LCLogger.Debug(LCEngine.OnSMSVerified);
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(Request);
if (UserHooks.TryGetValue(LCEngine.OnSMSVerified, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
return await Invoke(mi, dict);
}
return default;
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
[HttpPost("onVerified/email")]
public async Task<object> HookEmailVerification(JsonElement body) {
try {
LCLogger.Debug(LCEngine.OnEmailVerified);
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(Request);
if (UserHooks.TryGetValue(LCEngine.OnEmailVerified, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
return await Invoke(mi, dict);
}
return default;
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
[HttpPost("_User/onLogin")]
public async Task<object> HookLogin(JsonElement body) {
try {
LCLogger.Debug(LCEngine.OnLogin);
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(Request);
if (UserHooks.TryGetValue(LCEngine.OnLogin, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
return await Invoke(mi, dict);
}
return default;
} catch (Exception e) {
return StatusCode(500, e.Message);
}
}
private static async Task<object> Invoke(MethodInfo mi, Dictionary<string, object> dict) {
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
objectData.ClassName = "_User";
LCObject obj = LCObject.Create("_User");
obj.Merge(objectData);
LCUserHookRequest req = new LCUserHookRequest {
CurrentUser = obj as LCUser
};
return await LCEngine.Invoke(mi, req) as LCObject;
}
}
}

View File

@ -14,4 +14,7 @@
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers\" />
</ItemGroup>
</Project>

View File

@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using LeanCloud.Storage.Internal.Object;
using LeanCloud.Storage;
namespace LeanCloud.Engine {
public class LCClassHookHandler {
private static Dictionary<string, MethodInfo> ClassHooks => LCEngine.ClassHooks;
public static void Hello() {
}
public static async Task<object> HandleClassHook(string className, string hookName, HttpRequest request, JsonElement body) {
LCLogger.Debug($"Hook: {className}#{hookName}");
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(request);
string classHookName = GetClassHookName(className, hookName);
if (ClassHooks.TryGetValue(classHookName, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
objectData.ClassName = className;
LCObject obj = LCObject.Create(className);
obj.Merge(objectData);
// 避免死循环
if (hookName.StartsWith("before")) {
obj.DisableBeforeHook();
} else {
obj.DisableAfterHook();
}
LCUser user = null;
if (dict.TryGetValue("user", out object userObj) &&
userObj != null) {
user = new LCUser();
user.Merge(LCObjectData.Decode(userObj as Dictionary<string, object>));
}
LCClassHookRequest req = new LCClassHookRequest {
Object = obj,
CurrentUser = user
};
LCObject result = await LCEngine.Invoke(mi, req) as LCObject;
if (result != null) {
return LCCloud.Encode(result);
}
}
return default;
}
private static string GetClassHookName(string className, string hookName) {
switch (hookName) {
case "beforeSave":
return $"__before_save_for_{className}";
case "afterSave":
return $"__after_save_for_{className}";
case "beforeUpdate":
return $"__before_update_for_{className}";
case "afterUpdate":
return $"__after_update_for_{className}";
case "beforeDelete":
return $"__before_delete_for_{className}";
case "afterDelete":
return $"__after_delete_for_{className}";
default:
throw new Exception($"Error hook name: {hookName}");
}
}
}
}

View File

@ -1,82 +0,0 @@
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using LeanCloud.Storage.Internal.Codec;
using LeanCloud.Storage;
namespace LeanCloud.Engine {
public class LCFunctionHandler {
private static Dictionary<string, MethodInfo> Functions => LCEngine.Functions;
/// <summary>
/// 云函数
/// </summary>
/// <param name="funcName"></param>
/// <param name="request"></param>
/// <param name="body"></param>
/// <returns></returns>
public static async Task<object> HandleRun(string funcName, HttpRequest request, JsonElement body) {
LCLogger.Debug($"Run: {funcName}");
LCLogger.Debug(body.ToString());
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
LCUser currentUser = null;
if (request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
currentUser = await LCUser.BecomeWithSessionToken(session);
}
LCCloudFunctionRequest req = new LCCloudFunctionRequest {
Meta = new LCCloudFunctionRequestMeta {
RemoteAddress = LCEngine.GetIP(request)
},
Params = LCEngine.Decode(body),
SessionToken = session.ToString(),
User = currentUser
};
object result = await LCEngine.Invoke(mi, req);
if (result != null) {
return new Dictionary<string, object> {
{ "result", result }
};
}
}
return default;
}
/// <summary>
/// RPC
/// </summary>
/// <param name="funcName"></param>
/// <param name="request"></param>
/// <param name="body"></param>
/// <returns></returns>
public static async Task<object> HandleRPC(string funcName, HttpRequest request, JsonElement body) {
LCLogger.Debug($"RPC: {funcName}");
LCLogger.Debug(body.ToString());
if (Functions.TryGetValue(funcName, out MethodInfo mi)) {
LCUser currentUser = null;
if (request.Headers.TryGetValue("x-lc-session", out StringValues session)) {
currentUser = await LCUser.BecomeWithSessionToken(session);
}
LCCloudRPCRequest req = new LCCloudRPCRequest {
Meta = new LCCloudFunctionRequestMeta {
RemoteAddress = LCEngine.GetIP(request)
},
Params = LCDecoder.Decode(LCEngine.Decode(body)),
SessionToken = session.ToString(),
User = currentUser
};
object result = await LCEngine.Invoke(mi, req);
if (result != null) {
return new Dictionary<string, object> {
{ "result", LCCloud.Encode(result) }
};
}
}
return default;
}
}
}

View File

@ -1,66 +0,0 @@
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using LeanCloud.Storage.Internal.Object;
using LeanCloud.Storage;
namespace LeanCloud.Engine {
public class LCUserHookHandler {
private static Dictionary<string, MethodInfo> UserHooks => LCEngine.UserHooks;
public static async Task<object> HandleVerifiedSMS(HttpRequest request, JsonElement body) {
LCLogger.Debug(LCEngine.OnSMSVerified);
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(request);
if (UserHooks.TryGetValue(LCEngine.OnSMSVerified, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
return await Invoke(mi, dict);
}
return default;
}
public static async Task<object> HandleVerifiedEmail(HttpRequest request, JsonElement body) {
LCLogger.Debug(LCEngine.OnEmailVerified);
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(request);
if (UserHooks.TryGetValue(LCEngine.OnEmailVerified, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
return await Invoke(mi, dict);
}
return default;
}
public static async Task<object> HandleLogin(HttpRequest request, JsonElement body) {
LCLogger.Debug(LCEngine.OnLogin);
LCLogger.Debug(body.ToString());
LCEngine.CheckHookKey(request);
if (UserHooks.TryGetValue(LCEngine.OnLogin, out MethodInfo mi)) {
Dictionary<string, object> dict = LCEngine.Decode(body);
return await Invoke(mi, dict);
}
return default;
}
private static async Task<object> Invoke(MethodInfo mi, Dictionary<string, object> dict) {
LCObjectData objectData = LCObjectData.Decode(dict["object"] as Dictionary<string, object>);
objectData.ClassName = "_User";
LCObject obj = LCObject.Create("_User");
obj.Merge(objectData);
LCUserHookRequest req = new LCUserHookRequest {
CurrentUser = obj as LCUser
};
return await LCEngine.Invoke(mi, req) as LCObject;
}
}
}

View File

@ -8,9 +8,12 @@ using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Microsoft.Extensions.Primitives;
using LeanCloud.Common;
using Microsoft.Extensions.DependencyInjection;
namespace LeanCloud.Engine {
public class LCEngine {
public const string LCEngineCORS = "LCEngineCORS";
const string LCMasterKeyName = "x-avoscloud-master-key";
const string LCHookKeyName = "x-lc-hook-key";
@ -41,11 +44,42 @@ namespace LeanCloud.Engine {
const string ConversationRemoved = "_conversationRemoved";
const string ConversationUpdate = "_conversationUpdate";
static readonly string[] LCEngineCORSMethods = new string[] {
"PUT",
"GET",
"POST",
"DELETE",
"OPTIONS"
};
static readonly string[] LCEngineCORSHeaders = new string[] {
"Content-Type",
"X-AVOSCloud-Application-Id",
"X-AVOSCloud-Application-Key",
"X-AVOSCloud-Application-Production",
"X-AVOSCloud-Client-Version",
"X-AVOSCloud-Request-Sign",
"X-AVOSCloud-Session-Token",
"X-AVOSCloud-Super-Key",
"X-LC-Hook-Key",
"X-LC-Id",
"X-LC-Key",
"X-LC-Prod",
"X-LC-Session",
"X-LC-Sign",
"X-LC-UA",
"X-Requested-With",
"X-Uluru-Application-Id",
"X-Uluru-Application-Key",
"X-Uluru-Application-Production",
"X-Uluru-Client-Version",
"X-Uluru-Session-Token"
};
public static Dictionary<string, MethodInfo> Functions = new Dictionary<string, MethodInfo>();
public static Dictionary<string, MethodInfo> ClassHooks = new Dictionary<string, MethodInfo>();
public static Dictionary<string, MethodInfo> UserHooks = new Dictionary<string, MethodInfo>();
public static void Initialize() {
public static void Initialize(IServiceCollection services) {
// 获取环境变量
LCLogger.Debug("-------------------------------------------------");
PrintEnvironmentVar("LEANCLOUD_APP_ID");
@ -153,6 +187,14 @@ namespace LeanCloud.Engine {
.ForEach(item => {
Functions.TryAdd(item.Key, item.Value);
});
services.AddCors(options => {
options.AddPolicy(LCEngineCORS, builder => {
builder.AllowAnyOrigin()
.WithMethods(LCEngineCORSMethods)
.WithHeaders(LCEngineCORSHeaders);
});
});
}
public static void PrintEnvironmentVar(string key) {