Skip to content

Commit

Permalink
refactor: simplify ipc-server.c
Browse files Browse the repository at this point in the history
  • Loading branch information
werererer committed Jan 7, 2024
1 parent f2b9913 commit 5e60554
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 142 deletions.
270 changes: 128 additions & 142 deletions src/ipc-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,40 +35,24 @@ static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
#define IPC_HEADER_SIZE (sizeof(ipc_magic) + 8)

#define event_mask(ev) (1 << (ev & 0x7F))

enum ipc_command_type {
// i3 command types - see i3's I3_REPLY_TYPE constants
IPC_COMMAND = 0,
IPC_GET_TAGS = 1,
IPC_SUBSCRIBE = 2,
IPC_GET_OUTPUTS = 3,
IPC_GET_TREE = 4,
IPC_GET_MARKS = 5,
IPC_GET_BAR_CONFIG = 6,
IPC_GET_VERSION = 7,
IPC_GET_BINDING_MODES = 8,
IPC_GET_CONFIG = 9,
IPC_SEND_TICK = 10,
IPC_SYNC = 11,
IPC_GET_BINDING_STATE = 12,

// sway-specific command types
IPC_GET_INPUTS = 100,
IPC_GET_SEATS = 101,

// Events sent from sway to clients. Events have the highest bits set.

// Event Types
IPC_EVENT_TAG = ((1<<31) | 0),
IPC_EVENT_OUTPUT = ((1<<31) | 1),
IPC_EVENT_MODE = ((1<<31) | 2),
IPC_EVENT_WINDOW = ((1<<31) | 3),
IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4),
IPC_EVENT_BINDING = ((1<<31) | 5),
IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
IPC_EVENT_TICK = ((1<<31) | 7),

// sway-specific event types
IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
IPC_EVENT_INPUT = ((1<<31) | 21),
};
;

struct ipc_client {
struct wl_event_source *event_source;
Expand Down Expand Up @@ -375,8 +359,118 @@ void ipc_event_window() {
ipc_send_event("", IPC_EVENT_WINDOW);
}

void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_length,
void handle_ipc_command(struct ipc_client *client,
char *buf, uint32_t payload_length,
enum ipc_command_type payload_type) {
// Logic for IPC_COMMAND
char *line = strtok(buf, "\n");
while (line) {
size_t line_length = strlen(line);
if (line + line_length >= buf + payload_length) {
break;
}
line[line_length] = ';';
line = strtok(NULL, "\n");
}

struct cmd_results *results = execute_command(buf, NULL, NULL);
/* transaction_commit_dirty(); */
char *json = cmd_results_to_json(results);
int length = strlen(json);
ipc_send_reply(client, payload_type, json, (uint32_t)length);
free(json);
free(results);
return;
}

void handle_ipc_get_tags(struct ipc_client *client, char *buf,
enum ipc_command_type payload_type) {
json_object *array;

array = ipc_json_describe_tagsets();

const char *json_string = json_object_get_string(array);
ipc_send_reply(client, payload_type, json_string,
strlen(json_string));
json_object_put(array); // free
}

void handle_ipc_subscribe(struct ipc_client *client, char *buf, enum ipc_command_type payload_type) {
// TODO: Check if they're permitted to use these events
// NOTE: this will probably be fixed by sway, if so copy its
// implementation and call it a day
struct json_object *request = json_tokener_parse(buf);

bool is_tick = false;
// parse requested event types
for (size_t i = 0; i < json_object_array_length(request); i++) {
const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
if (strcmp(event_type, "workspace") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_TAG);
} else if (strcmp(event_type, "barconfig_update") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
} else if (strcmp(event_type, "mode") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_MODE);
} else if (strcmp(event_type, "shutdown") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN);
} else if (strcmp(event_type, "window") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_WINDOW);
} else if (strcmp(event_type, "binding") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BINDING);
} else if (strcmp(event_type, "tick") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_TICK);
is_tick = true;
} else {
const char msg[] = "{\"success\": false}";
ipc_send_reply(client, payload_type, msg, strlen(msg));
json_object_put(request);
printf("Unsupported event type in subscribe request\n");
}
}

json_object_put(request);
const char msg[] = "{\"success\": true}";
ipc_send_reply(client, payload_type, msg, strlen(msg));
if (is_tick) {
const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}";
ipc_send_reply(client, IPC_EVENT_TICK, tickmsg,
strlen(tickmsg));
}
}

void handle_ipc_get_tree(struct ipc_client *client, char *buf,
enum ipc_command_type payload_type) {
struct monitor *m = server_get_selected_monitor();
json_object *tree = ipc_json_describe_selected_container(m);
const char *json_string = json_object_to_json_string(tree);

ipc_send_reply(client, payload_type, json_string, strlen(json_string));
json_object_put(tree);
}

void handle_ipc_get_bar_config(struct ipc_client *client, char *buf, enum ipc_command_type payload_type) {
if (!buf[0]) {
// Send list of configured bar IDs
json_object *bars = json_object_new_array();
// for (int i = 0; i < config->bars->length; ++i) {
// struct bar_config *bar = config->bars->items[i];
// json_object_array_add(bars, json_object_new_string(bar->id));
// }
const char *json_string = json_object_to_json_string(bars);
ipc_send_reply(client, payload_type, json_string,
(uint32_t)strlen(json_string));
json_object_put(bars); // free
} else {
// Send particular bar's details
json_object *json = ipc_json_describe_bar_config();
const char *json_string = json_object_to_json_string(json);
ipc_send_reply(client, payload_type, json_string,
(uint32_t)strlen(json_string));
json_object_put(json); // free
}
}

void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_length, enum ipc_command_type payload_type) {
if (client == NULL) {
return;
}
Expand All @@ -387,11 +481,10 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
ipc_client_disconnect(client);
return;
}

if (payload_length > 0) {
// Payload should be fully available
ssize_t received = recv(client->fd, buf, payload_length, 0);
if (received == -1)
{
if (received == -1) {
printf("Unable to receive payload from IPC client\n");
ipc_client_disconnect(client);
free(buf);
Expand All @@ -402,133 +495,26 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt

switch (payload_type) {
case IPC_COMMAND:
{
char *line = strtok(buf, "\n");
while (line) {
size_t line_length = strlen(line);
if (line + line_length >= buf + payload_length) {
break;
}
line[line_length] = ';';
line = strtok(NULL, "\n");
}

struct cmd_results *results = execute_command(buf, NULL, NULL);
/* transaction_commit_dirty(); */
char *json = cmd_results_to_json(results);
int length = strlen(json);
ipc_send_reply(client, payload_type, json, (uint32_t)length);
free(json);
free(results);
goto exit_cleanup;
}
handle_ipc_command(client, buf, payload_length, payload_type);
break;
case IPC_GET_TAGS:
{
json_object *array;

array = ipc_json_describe_tagsets(NULL);

const char *json_string = json_object_get_string(array);
ipc_send_reply(client, payload_type, json_string,
strlen(json_string));
json_object_put(array); // free
goto exit_cleanup;
}

handle_ipc_get_tags(client, buf, payload_type);
break;
case IPC_SUBSCRIBE:
{
// TODO: Check if they're permitted to use these events
// NOTE: this will probably be fixed by sway, if so copy its
// implementation and call it a day
struct json_object *request = json_tokener_parse(buf);

bool is_tick = false;
// parse requested event types
for (size_t i = 0; i < json_object_array_length(request); i++) {
const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
if (strcmp(event_type, "workspace") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_TAG);
} else if (strcmp(event_type, "barconfig_update") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
} else if (strcmp(event_type, "bar_state_update") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BAR_STATE_UPDATE);
} else if (strcmp(event_type, "mode") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_MODE);
} else if (strcmp(event_type, "shutdown") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN);
} else if (strcmp(event_type, "window") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_WINDOW);
} else if (strcmp(event_type, "binding") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BINDING);
} else if (strcmp(event_type, "tick") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_TICK);
is_tick = true;
} else if (strcmp(event_type, "input") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_INPUT);
} else {
const char msg[] = "{\"success\": false}";
ipc_send_reply(client, payload_type, msg, strlen(msg));
json_object_put(request);
printf("Unsupported event type in subscribe request\n");
goto exit_cleanup;
}
}

json_object_put(request);
const char msg[] = "{\"success\": true}";
ipc_send_reply(client, payload_type, msg, strlen(msg));
if (is_tick) {
const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}";
ipc_send_reply(client, IPC_EVENT_TICK, tickmsg,
strlen(tickmsg));
}
goto exit_cleanup;
}

handle_ipc_subscribe(client, buf, payload_type);
break;
case IPC_GET_TREE:
{
struct monitor *m = server_get_selected_monitor();
json_object *tree = ipc_json_describe_selected_container(m);
const char *json_string = json_object_to_json_string(tree);

ipc_send_reply(client, payload_type, json_string, strlen(json_string));
json_object_put(tree);
goto exit_cleanup;
}

handle_ipc_get_tree(client, buf, payload_type);
break;
case IPC_GET_BAR_CONFIG:
{
if (!buf[0]) {
// Send list of configured bar IDs
json_object *bars = json_object_new_array();
// for (int i = 0; i < config->bars->length; ++i) {
// struct bar_config *bar = config->bars->items[i];
// json_object_array_add(bars, json_object_new_string(bar->id));
// }
const char *json_string = json_object_to_json_string(bars);
ipc_send_reply(client, payload_type, json_string,
(uint32_t)strlen(json_string));
json_object_put(bars); // free
} else {
// Send particular bar's details
json_object *json = ipc_json_describe_bar_config();
const char *json_string = json_object_to_json_string(json);
ipc_send_reply(client, payload_type, json_string,
(uint32_t)strlen(json_string));
json_object_put(json); // free
}
goto exit_cleanup;
}


handle_ipc_get_bar_config(client, buf, payload_type);
break;
default:
printf("Unknown IPC command type %x\n", payload_type);
goto exit_cleanup;
break;
}

exit_cleanup:
free(buf);
return;
}

bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_type,
Expand Down
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ srcs = files(
'utils/parseConfigUtils.c',
'utils/stringUtils.c',
'utils/writeFile.c',
'ipc/ipc_server_sway_adapter.c',
)

libName = 'japokwm_lib'
Expand Down

0 comments on commit 5e60554

Please sign in to comment.