Add wayvnctl help command

Signed-off-by: Jim Ramsay <i.am@jimramsay.com>
pull/178/head
Jim Ramsay 2022-10-30 12:59:01 -04:00 committed by Andri Yngvason
parent 01851dc339
commit 73fd2e386f
1 changed files with 100 additions and 12 deletions

View File

@ -36,18 +36,49 @@
nvnc_log(NVNC_LOG_WARNING, "Failed to " action ": %m"); nvnc_log(NVNC_LOG_WARNING, "Failed to " action ": %m");
enum cmd_type { enum cmd_type {
CMD_HELP,
CMD_SET_OUTPUT, CMD_SET_OUTPUT,
CMD_UNKNOWN, CMD_UNKNOWN,
}; };
static char* cmd_name[] = { struct cmd_param_info {
[CMD_SET_OUTPUT] = "set-output", char* name;
char* description;
};
struct cmd_info {
char* name;
char* description;
struct cmd_param_info params[5];
};
static struct cmd_info cmd_list[] = {
[CMD_HELP] = { "help",
"List all commands, or show usage of a specific command",
{
{"command", "The command to show (optional)"},
{NULL, NULL},
}
},
[CMD_SET_OUTPUT] = { "set-output",
"Switch the actively captured output",
{
{"switch-to", "The specific output name to capture"},
{"cycle", "Either \"next\" or \"prev\""},
{NULL, NULL},
}
},
}; };
struct cmd { struct cmd {
enum cmd_type type; enum cmd_type type;
}; };
struct cmd_help {
struct cmd cmd;
char command[64];
};
struct cmd_set_output { struct cmd_set_output {
struct cmd cmd; struct cmd cmd;
char target[64]; char target[64];
@ -97,14 +128,32 @@ static void cmd_response_destroy(struct cmd_response* self)
static enum cmd_type parse_command_name(const char* name) static enum cmd_type parse_command_name(const char* name)
{ {
if (!name || name[0] == '\0')
return CMD_UNKNOWN;
for (int i = 0; i < CMD_UNKNOWN; ++i) { for (int i = 0; i < CMD_UNKNOWN; ++i) {
if (strcmp(name, cmd_name[i]) == 0) { if (strcmp(name, cmd_list[i].name) == 0) {
return i; return i;
} }
} }
return CMD_UNKNOWN; return CMD_UNKNOWN;
} }
static struct cmd_help* cmd_help_new(json_t* args,
struct jsonipc_error* err)
{
const char* command = NULL;
if (args && json_unpack(args, "{s?s}", "command", &command) == -1) {
jsonipc_error_printf(err, EINVAL,
"expecting \"command\" (optional)");
return NULL;
}
struct cmd_help* cmd = calloc(1, sizeof(*cmd));
cmd->cmd.type = CMD_HELP;
if (command)
strlcpy(cmd->command, command, sizeof(cmd->command));
return cmd;
}
static struct cmd_set_output* cmd_set_output_new(json_t* args, static struct cmd_set_output* cmd_set_output_new(json_t* args,
struct jsonipc_error* err) struct jsonipc_error* err)
{ {
@ -141,6 +190,14 @@ static struct cmd_set_output* cmd_set_output_new(json_t* args,
return cmd; return cmd;
} }
static json_t* list_allowed_commands()
{
json_t* allowed = json_array();
for (int i = 0; i < CMD_UNKNOWN; ++i)
json_array_append_new(allowed, json_string(cmd_list[i].name));
return allowed;
}
static struct cmd* parse_command(struct jsonipc_request* ipc, static struct cmd* parse_command(struct jsonipc_request* ipc,
struct jsonipc_error* err) struct jsonipc_error* err)
{ {
@ -148,20 +205,19 @@ static struct cmd* parse_command(struct jsonipc_request* ipc,
enum cmd_type cmd_type = parse_command_name(ipc->method); enum cmd_type cmd_type = parse_command_name(ipc->method);
struct cmd* cmd = NULL; struct cmd* cmd = NULL;
switch (cmd_type) { switch (cmd_type) {
case CMD_HELP:
cmd = (struct cmd*)cmd_help_new(ipc->params, err);
break;
case CMD_SET_OUTPUT: case CMD_SET_OUTPUT:
cmd = (struct cmd*)cmd_set_output_new(ipc->params, err); cmd = (struct cmd*)cmd_set_output_new(ipc->params, err);
break; break;
default: { case CMD_UNKNOWN:
json_t* allowed = json_array();
for (int i = 0; i < CMD_UNKNOWN; ++i)
json_array_append_new(allowed, json_string(cmd_name[i]));
jsonipc_error_set_new(err, ENOENT, jsonipc_error_set_new(err, ENOENT,
json_pack("{s:o, s:o}", json_pack("{s:o, s:o}",
"error", "error",
jprintf("Unknown command \"%s\"", jprintf("Unknown command \"%s\"",
ipc->method), ipc->method),
"commands", allowed)); "commands", list_allowed_commands()));
}
} }
return cmd; return cmd;
} }
@ -238,19 +294,51 @@ static json_t* client_next_object(struct ctl_client* self, struct cmd_response**
return root; return root;
} }
static struct cmd_response* generate_help_object(const char* cmd)
{
enum cmd_type ctype = parse_command_name(cmd);
json_t* data;
if (ctype == CMD_UNKNOWN) {
data = json_pack("{s:o}", "commands", list_allowed_commands());
} else {
struct cmd_info* info = &cmd_list[ctype];
json_t* param_list = NULL;
if (info->params[0].name) {
param_list = json_object();
for (struct cmd_param_info* param = info->params;
param->name; ++param)
json_object_set_new(param_list, param->name,
json_string(param->description));
}
data = json_pack("{s:{s:s, s:o*}}",
info->name,
"description", info->description,
"params", param_list);
}
struct cmd_response* response = cmd_ok();
response->data = data;
return response;
}
static struct cmd_response* ctl_server_dispatch_cmd(struct ctl* self, struct cmd* cmd) static struct cmd_response* ctl_server_dispatch_cmd(struct ctl* self, struct cmd* cmd)
{ {
assert(cmd->type != CMD_UNKNOWN); assert(cmd->type != CMD_UNKNOWN);
const char* name = cmd_name[cmd->type]; const struct cmd_info* info = &cmd_list[cmd->type];
nvnc_log(NVNC_LOG_INFO, "Dispatching control client command '%s'", name); nvnc_log(NVNC_LOG_INFO, "Dispatching control client command '%s'", info->name);
struct cmd_response* response = NULL; struct cmd_response* response = NULL;
switch (cmd->type) { switch (cmd->type) {
case CMD_HELP:{
struct cmd_help* c = (struct cmd_help*)cmd;
response = generate_help_object(c->command);
break;
}
case CMD_SET_OUTPUT: { case CMD_SET_OUTPUT: {
struct cmd_set_output* c = (struct cmd_set_output*)cmd; struct cmd_set_output* c = (struct cmd_set_output*)cmd;
if (c->target[0] != '\0') if (c->target[0] != '\0')
response = self->actions.on_output_switch(self, c->target); response = self->actions.on_output_switch(self, c->target);
else else
response = self->actions.on_output_cycle(self, c->cycle); response = self->actions.on_output_cycle(self, c->cycle);
break;
} }
case CMD_UNKNOWN: case CMD_UNKNOWN:
break; break;