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 ClassHooks => LCEngine.ClassHooks; [HttpPost("functions/{className}/{hookName}")] public async Task 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 data = LCEngine.Decode(body); LCObjectData objectData = LCObjectData.Decode(data["object"] as Dictionary); objectData.ClassName = className; LCObject obj = LCObject.Create(className); obj.Merge(objectData); // 避免死循环 if (hookName.StartsWith("before")) { obj.DisableBeforeHook(); } else { obj.DisableAfterHook(); } LCEngine.InitRequestContext(Request); LCUser user = null; if (data.TryGetValue("user", out object userObj) && userObj != null) { user = new LCUser(); user.Merge(LCObjectData.Decode(userObj as Dictionary)); LCEngineRequestContext.CurrentUser = user; } LCObject result = await LCEngine.Invoke(mi, new object[] { obj }) as LCObject; if (result != null) { return LCCloud.Encode(result); } } return body; } 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}"); } } } }