AuroraRuntime/Source/Console/Commands/Commands.cpp

146 lines
4.2 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
***/
#include <RuntimeInternal.hpp>
#include "Commands.hpp"
namespace Aurora::Console::Commands
{
struct Command;
struct CommandDispatch;
static AuHashMap<AuString, Command> gCommands;
static AuList<Hooks::LineHook_cb> gLineCallbacks;
static AuList<CommandDispatch> gPendingCommands;
static auto gMutex = Threading::Primitives::MutexUnique();
static auto gPendingCommandsMutex = Threading::Primitives::MutexUnique();
static std::optional<Async::DispatchTarget_t> gCommandDispatcher;
2021-06-27 21:25:29 +00:00
struct Command
{
AuString tag;
Parse::ParseObject commandStructure;
const CommandCallback_cb &callback;
Command(AuString tag, Parse::ParseObject commandStructure, const CommandCallback_cb &callback) : tag(tag), commandStructure(commandStructure), callback(callback) {}
};
struct CommandDispatch
{
Parse::ParsedObject arguments;
const CommandCallback_cb &callback;
CommandDispatch(const Parse::ParsedObject &arguments, const CommandCallback_cb &callback) : arguments(arguments), callback(callback) {}
};
static bool Dispatch(const AuString &string)
{
Threading::WaitableLockGuard guard(gPendingCommandsMutex.get());
2021-06-27 21:25:29 +00:00
AuString tag;
AuString cmdParse;
AuMach offset;
Parse::ParseResult res;
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())
{
LogWarn("Command {} does not exist", tag);
return false;
}
auto const &cmdEntry = cmdItr->second;
offset = 0;
auto consumable = Parse::StringToConsumable(cmdParse, offset);
auto status = Parse::Parse(res, cmdEntry.commandStructure, consumable);
if (!status)
{
LogWarn("Couldn't parse command {}", string);
return false;
}
gPendingCommands.push_back(CommandDispatch(res.result, cmdEntry.callback));
return true;
}
void AddCommand(const AuString &tag, const Parse::ParseObject &commandStructure, const CommandCallback_cb &callback)
{
Threading::WaitableLockGuard guard(gPendingCommandsMutex.get());
2021-06-27 21:25:29 +00:00
gCommands.insert(std::make_pair(tag, Command(tag, commandStructure, callback)));
}
bool DispatchCommand(const AuString &string)
{
return Dispatch(string);
}
void UpdateDispatcher(std::optional<Async::DispatchTarget_t> target)
2021-06-27 21:25:29 +00:00
{
gMutex->Lock();
gPendingCommandsMutex->Lock();
if ((!target.has_value()) && (gCommandDispatcher == target))
{
auto commands = std::exchange(gPendingCommands, {});
for (const auto &command : commands)
{
command.callback(command.arguments);
}
}
gCommandDispatcher = target;
gPendingCommandsMutex->Unlock();
2021-06-27 21:25:29 +00:00
gMutex->Unlock();
}
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(command.arguments);
}
}
void PumpCommands()
{
gMutex->Lock();
gPendingCommandsMutex->Lock();
auto commands = std::exchange(gPendingCommands, {});
gPendingCommandsMutex->Unlock();
if (gCommandDispatcher.value_or(Async::DispatchTarget_t{0, 0}) == Async::DispatchTarget_t{0, 0})
{
DispatchCommandsFromThis(commands);
}
else
{
Async::NewWorkItem(gCommandDispatcher.value(),
std::make_shared<Async::BasicWorkStdFunc>([&commands]()
{
DispatchCommandsFromThis(commands);
}),
true)->Dispatch()->BlockUntilComplete();
}
gMutex->Unlock();
}
2021-06-27 21:25:29 +00:00
}