1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +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,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)

View File

@ -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.