AuroraRuntime/Source/Console/Commands/Commands.cpp

202 lines
5.8 KiB
C++
Raw Normal View History

2021-06-27 21:25:29 +00:00
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: Commands.cpp
Date: 2021-6-12
Author: Reece
***/
2021-09-30 14:57:41 +00:00
#include <Source/RuntimeInternal.hpp>
2021-06-27 21:25:29 +00:00
#include "Commands.hpp"
namespace Aurora::Console::Commands
{
struct Command;
struct CommandDispatch
{
Parse::ParsedObject arguments;
AuSPtr<ICommandSubscriber> callback;
CommandDispatch(const Parse::ParsedObject &arguments, const AuSPtr<ICommandSubscriber> &callback) : arguments(arguments), callback(callback) {}
};
2021-06-27 21:25:29 +00:00
static AuHashMap<AuString, Command> gCommands;
static AuList<Hooks::LineHook_cb> gLineCallbacks;
static AuList<CommandDispatch> gPendingCommands;
static AuMutex gMutex;
static AuMutex gPendingCommandsMutex;
static AuOptionalEx<AuWorkerPId_t> gCommandDispatcher;
2021-06-27 21:25:29 +00:00
struct Command
{
AuString tag;
Parse::ParseObject commandStructure;
AuSPtr<ICommandSubscriber> callback;
2021-06-27 21:25:29 +00:00
Command(AuString tag, Parse::ParseObject commandStructure, const AuSPtr<ICommandSubscriber> &callback) : tag(tag), commandStructure(commandStructure), callback(callback) {}
2022-01-19 18:18:13 +00:00
Command(AuString tag, Parse::ParseObject commandStructure, AuSPtr<ICommandSubscriber> &&callback) : tag(tag), commandStructure(commandStructure), callback(AuMove(callback)) {}
2021-06-27 21:25:29 +00:00
};
enum class EDispatchType
{
eNow,
eSys,
eAsync
};
static bool Dispatch(const AuString &string, EDispatchType type, AuOptionalEx<AuWorkerPId_t> workerId)
2021-06-27 21:25:29 +00:00
{
Parse::ParseResult res;
AuSPtr<ICommandSubscriber> callback;
2021-06-27 21:25:29 +00:00
{
AU_LOCK_GUARD(gPendingCommandsMutex);
2021-06-27 21:25:29 +00:00
{
AuString tag;
AuString cmdParse;
AuMach offset;
auto commandSplit = string.find(" ");
if (commandSplit != AuString::npos)
{
tag = string.substr(0, commandSplit);
cmdParse = string.substr(commandSplit + 1);
}
else
{
tag = string;
}
auto cmdItr = gCommands.find(tag);
if (cmdItr == gCommands.end())
{
AuLogWarn("Command {} does not exist", tag);
return false;
}
2021-06-27 21:25:29 +00:00
auto const &cmdEntry = cmdItr->second;
2021-06-27 21:25:29 +00:00
offset = 0;
2022-03-13 16:48:05 +00:00
Parse::ParseState consumable(AuIO::Character::ProviderFromStringShared(cmdParse, offset));
auto status = Parse::Parse(consumable, cmdEntry.commandStructure, res);
2021-06-27 21:25:29 +00:00
if (!status)
{
AuLogWarn("Couldn't parse command {}", string);
return false;
}
if (type == EDispatchType::eSys)
{
return AuTryInsert(gPendingCommands, CommandDispatch(res.result, cmdEntry.callback));
}
else
{
callback = cmdEntry.callback;
}
}
}
if (type == EDispatchType::eNow)
{
callback->OnCommand(res.result);
}
else if (workerId)
2021-06-27 21:25:29 +00:00
{
2023-09-15 17:21:47 +00:00
Async::DispatchOn(workerId.value(), [=]() -> void
{
callback->OnCommand(res.result);
});
2021-06-27 21:25:29 +00:00
}
return true;
}
AUKN_SYM void RemoveCommand(const AuString &tag)
{
AU_LOCK_GUARD(gPendingCommandsMutex);
AuTryRemove(gCommands, tag);
}
AUKN_SYM void AddCommand(const AuString &tag, const Parse::ParseObject &commandStructure, const AuSPtr<ICommandSubscriber> &callback)
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
AU_LOCK_GUARD(gPendingCommandsMutex);
SysAssert(callback);
2021-09-06 10:58:08 +00:00
gCommands.insert(AuMakePair(tag, Command(tag, commandStructure, callback)));
2021-06-27 21:25:29 +00:00
}
2021-09-06 10:58:08 +00:00
AUKN_SYM bool DispatchCommand(const AuString &string)
2021-06-27 21:25:29 +00:00
{
return Dispatch(string, EDispatchType::eSys, gCommandDispatcher);
}
AUKN_SYM bool DispatchCommandThisThread(const AuString &string)
{
return Dispatch(string, EDispatchType::eNow, {});
}
AUKN_SYM bool DispatchCommandToAsyncRunner(const AuString &string, Async::WorkerPId_t id)
{
return Dispatch(string, EDispatchType::eAsync, id);
2021-06-27 21:25:29 +00:00
}
void UpdateDispatcher(AuOptionalEx<AuWorkerPId_t> target)
2021-06-27 21:25:29 +00:00
{
2021-09-06 10:58:08 +00:00
AU_LOCK_GUARD(gMutex);
AU_LOCK_GUARD(gPendingCommandsMutex);
// process commands before async app termination
if ((!target.has_value()))
{
2022-01-19 17:08:13 +00:00
auto commands = AuExchange(gPendingCommands, {});
for (const auto &command : commands)
{
command.callback->OnCommand(command.arguments);
}
}
gCommandDispatcher = target;
}
2021-06-27 21:25:29 +00:00
static void DispatchCommandsFromThis(const AuList<CommandDispatch> &commands)
{
2021-06-27 21:25:29 +00:00
for (const auto &command : commands)
{
command.callback->OnCommand(command.arguments);
2021-06-27 21:25:29 +00:00
}
}
void RunCommandFunction(const AuFunction<void()> &func)
{
if (!gCommandDispatcher)
{
func();
}
else
{
NewWorkItem(gCommandDispatcher.value(), AuMakeShared<Async::BasicWorkStdFunc>(func))->Dispatch()->BlockUntilComplete();
}
}
void PumpCommands()
{
2022-02-19 09:05:58 +00:00
AU_LOCK_GUARD(gMutex);
AuList<CommandDispatch> commands;
2022-02-19 09:05:58 +00:00
{
AU_LOCK_GUARD(gPendingCommandsMutex);
commands = AuExchange(gPendingCommands, {});
if (commands.empty())
{
return;
}
2022-02-19 09:05:58 +00:00
}
RunCommandFunction([&commands]()
{
DispatchCommandsFromThis(commands);
});
}
2021-06-27 21:25:29 +00:00
}