fix: Use module name in action string

Action strings now have the form '#MODULE#ACTION'

For example to trigger the action 'toggle' in the 'module/date' module
one would now use '%{A1:#date#toggle:}'

With this action strings can now be uniquely assigned to one module.

Fixes #1172
This commit is contained in:
patrick96 2020-05-31 00:09:44 +02:00 committed by Patrick Ziegler
parent 22d0f0a38c
commit a287fb5e8c
5 changed files with 76 additions and 25 deletions

View File

@ -117,9 +117,12 @@ class controller
modulemap_t m_blocks;
/**
* \brief Module input handlers
* \brief Input handlers modules
*
* Maps the name of the input handler (module name) to the corresponding input
* handler
*/
vector<modules::input_handler*> m_inputhandlers;
std::map<string, shared_ptr<modules::input_handler>> m_inputhandlers;
/**
* \brief Maximum number of subsequent events to swallow

View File

@ -101,6 +101,10 @@ namespace modules {
public:
virtual ~module_interface() {}
/**
* Module name w/o 'module/' prefix
*/
virtual string name_raw() const = 0;
virtual string name() const = 0;
virtual bool running() const = 0;
@ -119,6 +123,7 @@ namespace modules {
module(const bar_settings bar, string name);
~module() noexcept;
string name_raw() const;
string name() const;
bool running() const;
void stop();
@ -148,6 +153,7 @@ namespace modules {
std::condition_variable m_sleephandler;
string m_name;
string m_name_raw;
unique_ptr<builder> m_builder;
unique_ptr<module_formatter> m_formatter;
vector<thread> m_threads;

View File

@ -17,6 +17,7 @@ namespace modules {
, m_log(logger::make())
, m_conf(config::make())
, m_name("module/" + name)
, m_name_raw(name)
, m_builder(make_unique<builder>(bar))
, m_formatter(make_unique<module_formatter>(m_conf, m_name))
, m_handle_events(m_conf.get(m_name, "handle-events", true)) {}
@ -40,6 +41,11 @@ namespace modules {
return m_name;
}
template <typename Impl>
string module<Impl>::name_raw() const {
return m_name_raw;
}
template <typename Impl>
bool module<Impl>::running() const {
return static_cast<bool>(m_enabled);

View File

@ -8,6 +8,11 @@ namespace modules {
class input_handler {
public:
virtual ~input_handler() {}
/**
* Handle command
*
* \returns true if the command is supported and false otherwise
*/
virtual bool input(string&& cmd) = 0;
};
}

View File

@ -143,11 +143,12 @@ bool controller::run(bool writeback, string snapshot_dst) {
size_t started_modules{0};
for (const auto& module : m_modules) {
auto inp_handler = dynamic_cast<input_handler*>(&*module);
auto inp_handler = std::dynamic_pointer_cast<input_handler>(module);
auto evt_handler = dynamic_cast<event_handler_interface*>(&*module);
if (inp_handler != nullptr) {
m_inputhandlers.emplace_back(inp_handler);
if (inp_handler) {
m_log.trace("Registering module %s as input handler", module->name_raw());
m_inputhandlers.emplace(module->name_raw(), inp_handler);
}
if (evt_handler != nullptr) {
@ -390,32 +391,62 @@ void controller::process_eventqueue() {
* Process stored input data
*/
void controller::process_inputdata() {
if (!m_inputdata.empty()) {
string cmd = m_inputdata;
m_inputdata.clear();
if (m_inputdata.empty()) {
return;
}
for (auto&& handler : m_inputhandlers) {
if (handler->input(string{cmd})) {
return;
}
const string cmd = m_inputdata;
m_inputdata.clear();
/*
* Module inputs have the following form (w/o the quotes): "#NAME#INPUT"
* where 'NAME' is the name of the module (for which '#' is a forbidden
* character) and 'INPUT' is the input that is sent to the module
*/
if (cmd.front() == '#') {
// Find the second delimiter '#'
auto end_pos = cmd.find('#', 1);
if (end_pos == string::npos) {
m_log.err("Invalid action string (input: %s)", cmd);
return;
}
try {
m_log.info("Uncaught input event, forwarding to shell... (input: %s)", cmd);
auto handler_name = cmd.substr(1, end_pos - 1);
auto action = cmd.substr(end_pos + 1);
if (m_command) {
m_log.warn("Terminating previous shell command");
m_command->terminate();
}
m_log.info("Forwarding data to input handler (name: %s, action: %s) ", handler_name, action);
m_log.info("Executing shell command: %s", cmd);
m_command = command_util::make_command<output_policy::IGNORED>(move(cmd));
m_command->exec();
m_command.reset();
process_update(true);
} catch (const application_error& err) {
m_log.err("controller: Error while forwarding input to shell -> %s", err.what());
auto handler = m_inputhandlers.find(handler_name);
if (handler == m_inputhandlers.end()) {
m_log.err("The input handler with name '%s' doesn't exist (input: %s)", handler_name, cmd);
return;
}
if(!handler->second->input(string{action})) {
m_log.warn("The '%s' module does not support the '%s' action.", handler_name, action);
}
return;
}
try {
// Run input as command if it's not an input for a module
m_log.info("Forwarding command to shell... (input: %s)", cmd);
if (m_command) {
m_log.warn("Terminating previous shell command");
m_command->terminate();
}
m_log.info("Executing shell command: %s", cmd);
m_command = command_util::make_command<output_policy::IGNORED>(move(cmd));
m_command->exec();
m_command.reset();
process_update(true);
} catch (const application_error& err) {
m_log.err("controller: Error while forwarding input to shell -> %s", err.what());
}
}