Skip to content

Commit

Permalink
Introduce an event loop mode in wayvncctl
Browse files Browse the repository at this point in the history
Signed-off-by: Jim Ramsay <[email protected]>
  • Loading branch information
lack committed Nov 12, 2022
1 parent 8076d62 commit bbba6d9
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 8 deletions.
2 changes: 2 additions & 0 deletions include/json-ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ struct jsonipc_request* jsonipc_request_parse_new(json_t* root,
struct jsonipc_error* err);
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_parse_new(json_t* root,
struct jsonipc_error* err);
json_t* jsonipc_request_pack(struct jsonipc_request*, json_error_t* err);
void jsonipc_request_destroy(struct jsonipc_request*);

Expand Down
116 changes: 111 additions & 5 deletions src/ctl-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ static json_t* read_one_object(struct ctl_client* self, int timeout_ms)
while (root == NULL) {
int n = poll(&pfd, 1, timeout_ms);
if (n == -1) {
if (errno == EINTR && self->wait_for_events)
continue;
WARN("Error waiting for a response: %m");
break;
} else if (n == 0) {
Expand Down Expand Up @@ -395,17 +397,121 @@ static void setup_signals(struct ctl_client* self)
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;
setup_signals(self);
while (self->wait_for_events) {
DEBUG("Waiting for an event");
json_t* root = read_one_object(self, -1);
json_dumpf(root, stdout, 0);
printf("\n");
fflush(stdout);
if (!root)
break;
struct jsonipc_error err = JSONIPC_ERR_INIT;
struct jsonipc_request* event = jsonipc_event_parse_new(root, &err);
json_decref(root);
print_event(event, flags);
jsonipc_request_destroy(event);
}
}

Expand All @@ -427,7 +533,7 @@ int ctl_client_run_command(struct ctl_client* self,
result = ctl_client_print_response(self, request, response, flags);

if (result == 0 && strcmp(request->method, "event-receive") == 0)
ctl_client_event_loop(self);
ctl_client_event_loop(self, flags);

jsonipc_response_destroy(response);
receive_failure:
Expand Down
6 changes: 6 additions & 0 deletions src/json-ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ struct jsonipc_request* jsonipc_event_new(const char* method, json_t* params)
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)
{
return json_pack_ex(err, 0, "{s:s, s:O*, s:O*}",
Expand Down
33 changes: 30 additions & 3 deletions wayvncctl.scd
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,36 @@ command and its available parameters.

While *wayvncctl* normally terminates after sending one request and receiving
the corresponding reply, the *event-receive* command acts differently. Instead
of exiting immediately, *wayvncctl* waits for any events fr the server, printing
each to stdout as they arrive. This mode of operation will block until either
it receives a signal to terminate, or until the wayvnc server terminates.
of exiting immediately, *wayvncctl* waits for any events from the server,
printing each to stdout as they arrive. This mode of operation will block until
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

Expand Down

0 comments on commit bbba6d9

Please sign in to comment.