1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 08:47:17 +01:00

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.
This commit is contained in:
Sandu Liviu Catalin 2021-05-01 22:58:59 +03:00
parent d5bfeced1c
commit 47ff628a46
2 changed files with 66 additions and 30 deletions

View File

@ -363,29 +363,46 @@ int32_t Controller::Exec(Context & ctx)
ctx.mBuffer.At(0) = '\0'; ctx.mBuffer.At(0) = '\0';
// Whether the command execution failed // Whether the command execution failed
bool failed = false; bool failed = false;
// Object with the command arguments
LightObj args;
// Do we have to call the command with an associative container? // Do we have to call the command with an associative container?
if (ctx.mInstance->m_Associate) if (ctx.mInstance->m_Associate)
{ {
// Create the associative container // Create the associative container
Table args(SqVM()); Table tbl(SqVM());
// Copy the arguments into the table // Copy the arguments into the table
for (uint32_t arg = 0; arg < ctx.mArgc; ++arg) for (uint32_t arg = 0; arg < ctx.mArgc; ++arg)
{ {
// Do we have use the argument index as the key? // Do we have use the argument index as the key?
if (ctx.mInstance->m_ArgTags[arg].empty()) 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! // Nope, we have a name for this argument!
else 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 // Store the table object into an abstract script object
args = LightObj(tbl.GetObj());
}
else
{
// Reserve an array for the extracted arguments
Array arr(SqVM(), ctx.mArgc);
// Copy the arguments into the array
for (uint32_t arg = 0; arg < ctx.mArgc; ++arg)
{
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 try
{ {
result = ctx.mInstance->Execute(ctx.mInvoker, args); result = ctx.mInstance->Audit(ctx.mInvoker, args);
} }
catch (const std::exception & e) catch (const std::exception & e)
{ {
@ -394,16 +411,9 @@ int32_t Controller::Exec(Context & ctx)
// Specify that the command execution failed // Specify that the command execution failed
failed = true; failed = true;
} }
} // Did parameter audit succeeded?
else if (result && !failed)
{ {
// Reserve an array for the extracted arguments
Array args(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);
}
// Attempt to execute the command with the specified arguments // Attempt to execute the command with the specified arguments
try try
{ {
@ -447,15 +457,13 @@ int32_t Controller::Exec(Context & ctx)
// Was the command aborted explicitly? // Was the command aborted explicitly?
else if (!result) 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? // Is there a script callback that handles failures?
if (!ctx.mInstance->m_OnFail.IsNull()) if (!ctx.mInstance->m_OnFail.IsNull())
{ {
// Then attempt to relay the result to that function // Then attempt to relay the result to that function
try try
{ {
ctx.mInstance->m_OnFail.Execute(ctx.mInvoker, result); ctx.mInstance->m_OnFail.Execute(ctx.mInvoker, args, result);
} }
catch (const Poco::Exception& e) 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()); 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? // Is there a callback that must be executed after a successful execution?
else if (!ctx.mInstance->m_OnPost.IsNull()) 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 // Then attempt to relay the result to that function
try try
{ {
ctx.mInstance->m_OnPost.Execute(ctx.mInvoker, result); ctx.mInstance->m_OnPost.Execute(ctx.mInvoker, args, result);
} }
catch (const Poco::Exception& e) catch (const Poco::Exception& e)
{ {
@ -1118,6 +1131,7 @@ void Register(HSQUIRRELVM vm)
.Prop(_SC("MaxArgs"), &Listener::GetMaxArgC, &Listener::SetMaxArgC) .Prop(_SC("MaxArgs"), &Listener::GetMaxArgC, &Listener::SetMaxArgC)
.Prop(_SC("OnExec"), &Listener::GetOnExec) .Prop(_SC("OnExec"), &Listener::GetOnExec)
.Prop(_SC("OnAuth"), &Listener::GetOnAuth) .Prop(_SC("OnAuth"), &Listener::GetOnAuth)
.Prop(_SC("OnAudit"), &Listener::GetOnAudit)
.Prop(_SC("OnPost"), &Listener::GetOnPost) .Prop(_SC("OnPost"), &Listener::GetOnPost)
.Prop(_SC("OnFail"), &Listener::GetOnFail) .Prop(_SC("OnFail"), &Listener::GetOnFail)
// Member Methods // Member Methods
@ -1129,6 +1143,7 @@ void Register(HSQUIRRELVM vm)
.FmtFunc(_SC("SetInfo"), &Listener::SetInfo) .FmtFunc(_SC("SetInfo"), &Listener::SetInfo)
.CbFunc(_SC("BindExec"), &Listener::SetOnExec) .CbFunc(_SC("BindExec"), &Listener::SetOnExec)
.CbFunc(_SC("BindAuth"), &Listener::SetOnAuth) .CbFunc(_SC("BindAuth"), &Listener::SetOnAuth)
.CbFunc(_SC("BindAudit"), &Listener::SetOnAudit)
.CbFunc(_SC("BindPost"), &Listener::SetOnPost) .CbFunc(_SC("BindPost"), &Listener::SetOnPost)
.CbFunc(_SC("BindFail"), &Listener::SetOnFail) .CbFunc(_SC("BindFail"), &Listener::SetOnFail)
.Func(_SC("GetArgTag"), &Listener::GetArgTag) .Func(_SC("GetArgTag"), &Listener::GetArgTag)

View File

@ -1109,6 +1109,7 @@ public:
node->m_Data.Release(); node->m_Data.Release();
node->m_OnExec.Release(); node->m_OnExec.Release();
node->m_OnAuth.Release(); node->m_OnAuth.Release();
node->m_OnAudit.Release();
node->m_OnPost.Release(); node->m_OnPost.Release();
node->m_OnFail.Release(); node->m_OnFail.Release();
} }
@ -1118,6 +1119,7 @@ public:
node->m_Data.Release(); node->m_Data.Release();
node->m_OnExec.Release(); node->m_OnExec.Release();
node->m_OnAuth.Release(); node->m_OnAuth.Release();
node->m_OnAudit.Release();
node->m_OnPost.Release(); node->m_OnPost.Release();
node->m_OnFail.Release(); node->m_OnFail.Release();
} }
@ -1203,6 +1205,7 @@ public:
, m_Info() , m_Info()
, m_OnExec() , m_OnExec()
, m_OnAuth() , m_OnAuth()
, m_OnAudit()
, m_OnPost() , m_OnPost()
, m_OnFail() , m_OnFail()
, m_Authority(ConvTo< int32_t >::From(auth)) , m_Authority(ConvTo< int32_t >::From(auth))
@ -1274,6 +1277,7 @@ public:
// Release callbacks // Release callbacks
m_OnExec.Release(); m_OnExec.Release();
m_OnAuth.Release(); m_OnAuth.Release();
m_OnAudit.Release();
m_OnPost.Release(); m_OnPost.Release();
m_OnFail.Release(); m_OnFail.Release();
// Is there an element behind us? // Is there an element behind us?
@ -1744,6 +1748,22 @@ public:
m_OnAuth = std::move(func); 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. * 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]; 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 // 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 // See if the executer succeeded and return the result or default to failed
return (!ret ? 0 : *ret); 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 // 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 // See if the executer succeeded and return the result or default to failed
return (!ret ? 0 : *ret); return (!ret ? 0 : *ret);
} }
@ -1941,6 +1961,7 @@ private:
// -------------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------
Function m_OnExec; // Function to call when the command is executed. 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_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_OnPost; // Function to call after the command was successfully executed.
Function m_OnFail; // Function to call after the command execution failed. Function m_OnFail; // Function to call after the command execution failed.