From 47ff628a46aefc448e996b39dc7687dde2725209 Mon Sep 17 00:00:00 2001 From: Sandu Liviu Catalin Date: Sat, 1 May 2021 22:58:59 +0300 Subject: [PATCH] Changes to command manager. Add a new callback to audit command parameters. Include extra arguments to fail and post callbacks. Refactor code to simplify some cases. --- module/Core/Command.cpp | 57 ++++++++++++++++++++++++++--------------- module/Core/Command.hpp | 39 +++++++++++++++++++++------- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/module/Core/Command.cpp b/module/Core/Command.cpp index 53ccf6b5..0c9db63b 100644 --- a/module/Core/Command.cpp +++ b/module/Core/Command.cpp @@ -363,47 +363,57 @@ int32_t Controller::Exec(Context & ctx) ctx.mBuffer.At(0) = '\0'; // Whether the command execution failed bool failed = false; + // Object with the command arguments + LightObj args; // Do we have to call the command with an associative container? if (ctx.mInstance->m_Associate) { // Create the associative container - Table args(SqVM()); + Table tbl(SqVM()); // Copy the arguments into the table for (uint32_t arg = 0; arg < ctx.mArgc; ++arg) { // Do we have use the argument index as the key? if (ctx.mInstance->m_ArgTags[arg].empty()) { - args.SetValue(SQInteger(arg), ctx.mArgv[arg].second); + tbl.SetValue(SQInteger(arg), ctx.mArgv[arg].second); } // Nope, we have a name for this argument! else { - args.SetValue(ctx.mInstance->m_ArgTags[arg].c_str(), ctx.mArgv[arg].second); + tbl.SetValue(ctx.mInstance->m_ArgTags[arg].c_str(), ctx.mArgv[arg].second); } } - // Attempt to execute the command with the specified arguments - try - { - result = ctx.mInstance->Execute(ctx.mInvoker, args); - } - catch (const std::exception & e) - { - // Let's store the exception message - ctx.mBuffer.WriteS(0, e.what()); - // Specify that the command execution failed - failed = true; - } + // Store the table object into an abstract script object + args = LightObj(tbl.GetObj()); } else { // Reserve an array for the extracted arguments - Array args(SqVM(), ctx.mArgc); + Array arr(SqVM(), ctx.mArgc); // Copy the arguments into the array for (uint32_t arg = 0; arg < ctx.mArgc; ++arg) { - args.Bind(SQInteger(arg), ctx.mArgv[arg].second); + arr.Bind(SQInteger(arg), ctx.mArgv[arg].second); } + // Store the table object into an abstract script object + args = LightObj(arr.GetObj()); + } + // Allow the user to audit the command parameters + try + { + result = ctx.mInstance->Audit(ctx.mInvoker, args); + } + catch (const std::exception & e) + { + // Let's store the exception message + ctx.mBuffer.WriteS(0, e.what()); + // Specify that the command execution failed + failed = true; + } + // Did parameter audit succeeded? + if (result && !failed) + { // Attempt to execute the command with the specified arguments try { @@ -447,15 +457,13 @@ int32_t Controller::Exec(Context & ctx) // Was the command aborted explicitly? else if (!result) { - // Tell the script callback to deal with the error - SqError(CMDERR_EXECUTION_ABORTED, _SC("Command execution aborted"), result); // Is there a script callback that handles failures? if (!ctx.mInstance->m_OnFail.IsNull()) { // Then attempt to relay the result to that function try { - ctx.mInstance->m_OnFail.Execute(ctx.mInvoker, result); + ctx.mInstance->m_OnFail.Execute(ctx.mInvoker, args, result); } catch (const Poco::Exception& e) { @@ -468,6 +476,11 @@ int32_t Controller::Exec(Context & ctx) SqError(CMDERR_UNRESOLVED_FAILURE, _SC("Unable to resolve command failure"), e.what()); } } + else + { + // Tell the script callback to deal with the error + SqError(CMDERR_EXECUTION_ABORTED, _SC("Command execution aborted"), result); + } } // Is there a callback that must be executed after a successful execution? else if (!ctx.mInstance->m_OnPost.IsNull()) @@ -475,7 +488,7 @@ int32_t Controller::Exec(Context & ctx) // Then attempt to relay the result to that function try { - ctx.mInstance->m_OnPost.Execute(ctx.mInvoker, result); + ctx.mInstance->m_OnPost.Execute(ctx.mInvoker, args, result); } catch (const Poco::Exception& e) { @@ -1118,6 +1131,7 @@ void Register(HSQUIRRELVM vm) .Prop(_SC("MaxArgs"), &Listener::GetMaxArgC, &Listener::SetMaxArgC) .Prop(_SC("OnExec"), &Listener::GetOnExec) .Prop(_SC("OnAuth"), &Listener::GetOnAuth) + .Prop(_SC("OnAudit"), &Listener::GetOnAudit) .Prop(_SC("OnPost"), &Listener::GetOnPost) .Prop(_SC("OnFail"), &Listener::GetOnFail) // Member Methods @@ -1129,6 +1143,7 @@ void Register(HSQUIRRELVM vm) .FmtFunc(_SC("SetInfo"), &Listener::SetInfo) .CbFunc(_SC("BindExec"), &Listener::SetOnExec) .CbFunc(_SC("BindAuth"), &Listener::SetOnAuth) + .CbFunc(_SC("BindAudit"), &Listener::SetOnAudit) .CbFunc(_SC("BindPost"), &Listener::SetOnPost) .CbFunc(_SC("BindFail"), &Listener::SetOnFail) .Func(_SC("GetArgTag"), &Listener::GetArgTag) diff --git a/module/Core/Command.hpp b/module/Core/Command.hpp index 9df479da..422eb3de 100644 --- a/module/Core/Command.hpp +++ b/module/Core/Command.hpp @@ -1109,6 +1109,7 @@ public: node->m_Data.Release(); node->m_OnExec.Release(); node->m_OnAuth.Release(); + node->m_OnAudit.Release(); node->m_OnPost.Release(); node->m_OnFail.Release(); } @@ -1118,6 +1119,7 @@ public: node->m_Data.Release(); node->m_OnExec.Release(); node->m_OnAuth.Release(); + node->m_OnAudit.Release(); node->m_OnPost.Release(); node->m_OnFail.Release(); } @@ -1203,6 +1205,7 @@ public: , m_Info() , m_OnExec() , m_OnAuth() + , m_OnAudit() , m_OnPost() , m_OnFail() , m_Authority(ConvTo< int32_t >::From(auth)) @@ -1274,6 +1277,7 @@ public: // Release callbacks m_OnExec.Release(); m_OnAuth.Release(); + m_OnAudit.Release(); m_OnPost.Release(); m_OnFail.Release(); // Is there an element behind us? @@ -1744,6 +1748,22 @@ public: m_OnAuth = std::move(func); } + /* -------------------------------------------------------------------------------------------- + * Retrieve the function that must be called when this command listener needs to validate invocation. + */ + Function & GetOnAudit() + { + return m_OnAudit; + } + + /* -------------------------------------------------------------------------------------------- + * Modify the function that must be called when this command listener needs to validate invocation. + */ + void SetOnAudit(Function & func) + { + m_OnAudit = std::move(func); + } + /* -------------------------------------------------------------------------------------------- * Retrieve the function that must be called when this command listener finished execution. */ @@ -1890,23 +1910,23 @@ protected: typedef String ArgTags[SQMOD_MAX_CMD_ARGS]; /* -------------------------------------------------------------------------------------------- - * Execute the designated callback by passing the arguments in their specified order. + * Execute the designated audit callback by passing the arguments in their specified order. */ - SQInteger Execute(const Object & invoker, const Array & args) + SQInteger Audit(const Object & invoker, const LightObj & args) { // Attempt to evaluate the specified executer knowing the manager did the validations - SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, const Object &, const Array & >(invoker, args); + SharedPtr< SQInteger > ret = m_OnAudit.Evaluate< SQInteger, const Object &, const LightObj & >(invoker, args); // See if the executer succeeded and return the result or default to failed return (!ret ? 0 : *ret); } /* -------------------------------------------------------------------------------------------- - * Execute the designated callback by passing the arguments using an associative container. + * Execute the designated callback by passing the arguments in their specified order. */ - SQInteger Execute(const Object & invoker, const Table & args) + SQInteger Execute(const Object & invoker, const LightObj & args) { // Attempt to evaluate the specified executer knowing the manager did the validations - SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, const Object &, const Table & >(invoker, args); + SharedPtr< SQInteger > ret = m_OnExec.Evaluate< SQInteger, const Object &, const LightObj & >(invoker, args); // See if the executer succeeded and return the result or default to failed return (!ret ? 0 : *ret); } @@ -1930,8 +1950,8 @@ private: ArgTags m_ArgTags; // List of argument tags/names. // -------------------------------------------------------------------------------------------- - uint8_t m_MinArgc; // Minimum number of arguments supported by this listener. - uint8_t m_MaxArgc; // Maximum number of arguments supported by this listener. + uint8_t m_MinArgc; // Minimum number of arguments supported by this listener. + uint8_t m_MaxArgc; // Maximum number of arguments supported by this listener. // -------------------------------------------------------------------------------------------- String m_Spec; // String used to generate the argument type specification list. @@ -1941,11 +1961,12 @@ private: // -------------------------------------------------------------------------------------------- Function m_OnExec; // Function to call when the command is executed. Function m_OnAuth; // Function to call when the invoker must be authenticated. + Function m_OnAudit; // Function to call when the parameters must be validated. Function m_OnPost; // Function to call after the command was successfully executed. Function m_OnFail; // Function to call after the command execution failed. // -------------------------------------------------------------------------------------------- - int32_t m_Authority; // Built-in authority level required to execute this command. + int32_t m_Authority; // Built-in authority level required to execute this command. // -------------------------------------------------------------------------------------------- bool m_Protected; // Whether explicit authentication of the invoker is required.