mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-06-16 00:05:40 +02:00
module/script: add poll-interval option
When set to a non-negative value, the script module will call the configured script every <poll-interval> second. In this mode, the script is expected to write one tag set and then exit. This is intended to simplify the implementation of scripts that would otherwise just do a loop + sleep. Closes #67
This commit is contained in:
parent
e4a0b375e5
commit
cf41d008f8
3 changed files with 101 additions and 17 deletions
|
@ -25,6 +25,8 @@ struct private {
|
|||
char *path;
|
||||
size_t argc;
|
||||
char **argv;
|
||||
int poll_interval;
|
||||
bool aborted;
|
||||
|
||||
struct particle *content;
|
||||
|
||||
|
@ -331,7 +333,7 @@ data_received(struct module *mod, const char *data, size_t len)
|
|||
static int
|
||||
run_loop(struct module *mod, pid_t pid, int comm_fd)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = 1;
|
||||
|
||||
while (true) {
|
||||
struct pollfd fds[] = {
|
||||
|
@ -360,19 +362,18 @@ run_loop(struct module *mod, pid_t pid, int comm_fd)
|
|||
data_received(mod, data, amount);
|
||||
}
|
||||
|
||||
if (fds[0].revents & POLLHUP) {
|
||||
if (fds[0].revents & (POLLHUP | POLLIN)) {
|
||||
/* Aborted */
|
||||
struct private *m = mod->private;
|
||||
m->aborted = true;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fds[1].revents & POLLHUP) {
|
||||
/* Child's stdout closed */
|
||||
LOG_DBG("script pipe closed (script terminated?)");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fds[0].revents & POLLIN) {
|
||||
/* Aborted */
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +382,7 @@ run_loop(struct module *mod, pid_t pid, int comm_fd)
|
|||
}
|
||||
|
||||
static int
|
||||
run(struct module *mod)
|
||||
execute_script(struct module *mod)
|
||||
{
|
||||
struct private *m = mod->private;
|
||||
|
||||
|
@ -565,9 +566,75 @@ run(struct module *mod)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
run(struct module *mod)
|
||||
{
|
||||
struct private *m = mod->private;
|
||||
|
||||
int ret = 1;
|
||||
bool keep_going = true;
|
||||
|
||||
while (keep_going && !m->aborted) {
|
||||
ret = execute_script(mod);
|
||||
|
||||
if (ret != 0)
|
||||
break;
|
||||
if (m->aborted)
|
||||
break;
|
||||
if (m->poll_interval < 0)
|
||||
break;
|
||||
|
||||
struct timeval now;
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
LOG_ERRNO("failed to get current time");
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval poll_interval = {.tv_sec = m->poll_interval};
|
||||
|
||||
struct timeval timeout;
|
||||
timeradd(&now, &poll_interval, &timeout);
|
||||
|
||||
while (true) {
|
||||
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}};
|
||||
|
||||
struct timeval now;
|
||||
if (gettimeofday(&now, NULL) < 0) {
|
||||
LOG_ERRNO("failed to get current time");
|
||||
keep_going = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!timercmp(&now, &timeout, <)) {
|
||||
/* We’ve reached the timeout, it’s time to execute the script again */
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval time_left;
|
||||
timersub(&timeout, &now, &time_left);
|
||||
|
||||
int r = poll(fds, 1, time_left.tv_sec * 1000 + time_left.tv_usec / 1000);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
LOG_ERRNO("failed to poll");
|
||||
keep_going = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
m->aborted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct module *
|
||||
script_new(const char *path, size_t argc, const char *const argv[static argc],
|
||||
struct particle *_content)
|
||||
int poll_interval, struct particle *_content)
|
||||
{
|
||||
struct private *m = calloc(1, sizeof(*m));
|
||||
m->path = strdup(path);
|
||||
|
@ -576,6 +643,7 @@ script_new(const char *path, size_t argc, const char *const argv[static argc],
|
|||
m->argv = malloc(argc * sizeof(m->argv[0]));
|
||||
for (size_t i = 0; i < argc; i++)
|
||||
m->argv[i] = strdup(argv[i]);
|
||||
m->poll_interval = poll_interval;
|
||||
|
||||
struct module *mod = module_common_new();
|
||||
mod->private = m;
|
||||
|
@ -592,6 +660,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
|
|||
const struct yml_node *path = yml_get_value(node, "path");
|
||||
const struct yml_node *args = yml_get_value(node, "args");
|
||||
const struct yml_node *c = yml_get_value(node, "content");
|
||||
const struct yml_node *poll_interval = yml_get_value(node, "poll-interval");
|
||||
|
||||
size_t argc = args != NULL ? yml_list_length(args) : 0;
|
||||
const char *argv[argc];
|
||||
|
@ -607,7 +676,9 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited)
|
|||
}
|
||||
|
||||
return script_new(
|
||||
yml_value_as_string(path), argc, argv, conf_to_particle(c, inherited));
|
||||
yml_value_as_string(path), argc, argv,
|
||||
poll_interval != NULL ? yml_value_as_int(poll_interval) : -1,
|
||||
conf_to_particle(c, inherited));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -637,6 +708,7 @@ verify_conf(keychain_t *chain, const struct yml_node *node)
|
|||
static const struct attr_info attrs[] = {
|
||||
{"path", true, &conf_verify_path},
|
||||
{"args", false, &conf_verify_args},
|
||||
{"poll-interval", false, &conf_verify_int},
|
||||
MODULE_COMMON_ATTRS,
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue