Introduce an event loop mode in wayvncctl

Signed-off-by: Jim Ramsay <i.am@jimramsay.com>
pull/183/head
Jim Ramsay 2022-11-09 09:11:21 -05:00 committed by Andri Yngvason
parent debd8a67cb
commit d8239109e5
4 changed files with 149 additions and 8 deletions

View File

@ -52,6 +52,8 @@ struct jsonipc_request* jsonipc_request_parse_new(json_t* root,
struct jsonipc_error* err); struct jsonipc_error* err);
struct jsonipc_request* jsonipc_request_new(const char* method, json_t* params); struct jsonipc_request* jsonipc_request_new(const char* method, json_t* params);
struct jsonipc_request* jsonipc_event_new(const char* method, json_t* params); struct jsonipc_request* jsonipc_event_new(const char* method, json_t* params);
struct jsonipc_request* jsonipc_event_parse_new(json_t* root,
struct jsonipc_error* err);
json_t* jsonipc_request_pack(struct jsonipc_request*, json_error_t* err); json_t* jsonipc_request_pack(struct jsonipc_request*, json_error_t* err);
void jsonipc_request_destroy(struct jsonipc_request*); void jsonipc_request_destroy(struct jsonipc_request*);

View File

@ -200,6 +200,8 @@ static json_t* read_one_object(struct ctl_client* self, int timeout_ms)
while (root == NULL) { while (root == NULL) {
int n = poll(&pfd, 1, timeout_ms); int n = poll(&pfd, 1, timeout_ms);
if (n == -1) { if (n == -1) {
if (errno == EINTR && self->wait_for_events)
continue;
WARN("Error waiting for a response: %m"); WARN("Error waiting for a response: %m");
break; break;
} else if (n == 0) { } else if (n == 0) {
@ -395,17 +397,121 @@ static void setup_signals(struct ctl_client* self)
sigaction(SIGTERM, &sa, NULL); sigaction(SIGTERM, &sa, NULL);
} }
static void ctl_client_event_loop(struct ctl_client* self) static void print_indent(int level)
{
for (int i = 0; i < level; ++i)
printf(" ");
}
static bool json_has_content(json_t* root)
{
if (!root)
return false;
size_t i;
const char* key;
json_t* value;
switch (json_typeof(root)) {
case JSON_NULL:
return false;
case JSON_INTEGER:
case JSON_REAL:
case JSON_TRUE:
case JSON_FALSE:
return true;
case JSON_STRING:
return json_string_value(root)[0] != '\0';
case JSON_OBJECT:
json_object_foreach(root, key, value)
if (json_has_content(value))
return true;
return false;
case JSON_ARRAY:
json_array_foreach(root, i, value)
if (json_has_content(value))
return true;
return false;
}
return false;
}
static void print_as_yaml(json_t* data, int level, bool needs_leading_newline)
{
size_t i;
const char* key;
json_t* value;
bool needs_indent = needs_leading_newline;
switch(json_typeof(data)) {
case JSON_NULL:
printf("<null>\n");
break;
case JSON_OBJECT:
if (json_object_size(data) > 0 && needs_leading_newline)
printf("\n");
json_object_foreach(data, key, value) {
if (!json_has_content(value))
continue;
if (needs_indent)
print_indent(level);
else
needs_indent = true;
printf("%s: ", key);
print_as_yaml(value, level + 1, true);
}
break;
case JSON_ARRAY:
if (json_array_size(data) > 0 && needs_leading_newline)
printf("\n");
json_array_foreach(data, i, value) {
if (!json_has_content(value))
continue;
print_indent(level);
printf("- ");
print_as_yaml(value, level + 1, json_is_array(value));
}
break;
case JSON_STRING:
printf("%s\n", json_string_value(data));
break;
case JSON_INTEGER:
printf("%" JSON_INTEGER_FORMAT "\n", json_integer_value(data));
break;
case JSON_REAL:
printf("%f\n", json_real_value(data));
break;
case JSON_TRUE:
printf("true\n");
break;
case JSON_FALSE:
printf("false\n");
break;
}
}
static void print_event(struct jsonipc_request* event, unsigned flags)
{
if (flags & PRINT_JSON) {
print_compact_json(event->json);
} else {
printf("\n%s:", event->method);
print_as_yaml(event->params, 1, true);
}
fflush(stdout);
}
static void ctl_client_event_loop(struct ctl_client* self, unsigned flags)
{ {
self->wait_for_events = true; self->wait_for_events = true;
setup_signals(self); setup_signals(self);
while (self->wait_for_events) { while (self->wait_for_events) {
DEBUG("Waiting for an event"); DEBUG("Waiting for an event");
json_t* root = read_one_object(self, -1); json_t* root = read_one_object(self, -1);
json_dumpf(root, stdout, 0); if (!root)
printf("\n"); break;
fflush(stdout); struct jsonipc_error err = JSONIPC_ERR_INIT;
struct jsonipc_request* event = jsonipc_event_parse_new(root, &err);
json_decref(root); json_decref(root);
print_event(event, flags);
jsonipc_request_destroy(event);
} }
} }
@ -427,7 +533,7 @@ int ctl_client_run_command(struct ctl_client* self,
result = ctl_client_print_response(self, request, response, flags); result = ctl_client_print_response(self, request, response, flags);
if (result == 0 && strcmp(request->method, "event-receive") == 0) if (result == 0 && strcmp(request->method, "event-receive") == 0)
ctl_client_event_loop(self); ctl_client_event_loop(self, flags);
jsonipc_response_destroy(response); jsonipc_response_destroy(response);
receive_failure: receive_failure:

View File

@ -111,6 +111,12 @@ struct jsonipc_request* jsonipc_event_new(const char* method, json_t* params)
return jsonipc_request__new(method, params, NULL); return jsonipc_request__new(method, params, NULL);
} }
struct jsonipc_request* jsonipc_event_parse_new(json_t* root,
struct jsonipc_error* err)
{
return jsonipc_request_parse_new(root, err);
}
json_t* jsonipc_request_pack(struct jsonipc_request* self, json_error_t* err) json_t* jsonipc_request_pack(struct jsonipc_request* self, json_error_t* err)
{ {
return json_pack_ex(err, 0, "{s:s, s:O*, s:O*}", return json_pack_ex(err, 0, "{s:s, s:O*, s:O*}",

View File

@ -46,9 +46,36 @@ command and its available parameters.
While *wayvncctl* normally terminates after sending one request and receiving While *wayvncctl* normally terminates after sending one request and receiving
the corresponding reply, the *event-receive* command acts differently. Instead the corresponding reply, the *event-receive* command acts differently. Instead
of exiting immediately, *wayvncctl* waits for any events fr the server, printing of exiting immediately, *wayvncctl* waits for any events from the server,
each to stdout as they arrive. This mode of operation will block until either printing each to stdout as they arrive. This mode of operation will block until
it receives a signal to terminate, or until the wayvnc server terminates. either it receives a signal to terminate, or until the wayvnc server terminates.
In _--json_ mode, each event is printed on one line, with a newline character at
the end, for ease in scripting:
```
$ wayvncctl --json event-receive
{"method":"client-connected","params":{"id":"0x10ef670","hostname":null,"username":null,"connection_count":1}}
{"method":"client-disconnected","params":{"id":"0x10ef670","hostname":null,"username":null,"connection_count":0}}
```
The default human-readible output is a multi-line yaml-like format, with two
newline characters between each event:
```
$ wayvncctl event-receive
client-connected:
id: 0x10ef670
hostname: 192.168.1.18
connection_count: 1
client-disconnected:
id: 0x10ef670
hostname: 192.168.1.18
connection_count: 0
```
# EXAMPLES # EXAMPLES