commit 20dff2d28b240611ed334328b1279305169e5821 from: Omar Polo date: Thu Aug 31 17:48:21 2023 UTC amused-web: centralize the imsg handling Keep a copy of the playing queue, status etc. to render the UI without doing imsg in the render path. commit - ff37a2708a65b27b7dcab2da6b0187a4ba6b1a42 commit + 20dff2d28b240611ed334328b1279305169e5821 blob - e17cee4e7199a7dd9a5b7866d57d3b1b90aa14ff blob + ec36716ea606e9472b85231a39ad1fe4d66bff6d --- web/web.c +++ web/web.c @@ -59,6 +59,9 @@ #define ICON_PLAY "⏵" static struct imsgbuf ibuf; +static struct playlist playlist_tmp; +static struct player_status player_status; +static uint64_t position, duration; static const char *prefix = ""; static size_t prefixlen; @@ -184,7 +187,6 @@ dial(const char *sock) return s; } - /* * Adapted from usr.sbin/httpd/httpd.c' url_decode. */ @@ -233,22 +235,120 @@ url_decode(char *url) } static void -unexpected_imsg(struct imsg *imsg, const char *expected) +imsg_dispatch(int fd, int ev, void *d) { - const char *msg; - size_t datalen; + static ssize_t off; + static int off_found; + struct imsg imsg; + struct player_status ps; + struct player_event event; + const char *msg; + ssize_t n; + size_t datalen; - if (imsg->hdr.type != IMSG_CTL_ERR) { - log_warnx("got event %d while expecting %s", - imsg->hdr.type, expected); - return; + if (ev & (POLLIN|POLLHUP)) { + if ((n = imsg_read(&ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read"); + if (n == 0) + fatalx("pipe closed"); } + if (ev & POLLOUT) { + if ((n = msgbuf_write(&ibuf.w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) + fatalx("pipe closed"); + } - datalen = IMSG_DATA_SIZE(*imsg); - msg = imsg->data; - if (datalen == 0 || msg[datalen - 1] != '\0') - fatalx("malformed error message"); - log_warnx("failure: %s", msg); + for (;;) { + if ((n = imsg_get(&ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (n == 0) + break; + + datalen = IMSG_DATA_SIZE(imsg); + + switch (imsg.hdr.type) { + case IMSG_CTL_ERR: + msg = imsg.data; + if (datalen == 0 || msg[datalen - 1] != '\0') + fatalx("malformed error message"); + log_warnx("error: %s", msg); + break; + + case IMSG_CTL_ADD: + playlist_free(&playlist_tmp); + imsg_compose(&ibuf, IMSG_CTL_SHOW, 0, 0, -1, NULL, 0); + break; + + case IMSG_CTL_MONITOR: + if (datalen != sizeof(event)) + fatalx("corrupted IMSG_CTL_MONITOR"); + memcpy(&event, imsg.data, sizeof(event)); + switch (event.event) { + case IMSG_CTL_PLAY: + case IMSG_CTL_PAUSE: + case IMSG_CTL_STOP: + case IMSG_CTL_MODE: + imsg_compose(&ibuf, IMSG_CTL_STATUS, 0, 0, -1, + NULL, 0); + break; + + case IMSG_CTL_NEXT: + case IMSG_CTL_PREV: + case IMSG_CTL_JUMP: + case IMSG_CTL_COMMIT: + imsg_compose(&ibuf, IMSG_CTL_SHOW, 0, 0, -1, + NULL, 0); + imsg_compose(&ibuf, IMSG_CTL_STATUS, 0, 0, -1, + NULL, 0); + break; + + case IMSG_CTL_SEEK: + position = event.position; + duration = event.duration; + break; + + default: + log_debug("ignoring event %d", event.event); + break; + } + break; + + case IMSG_CTL_SHOW: + if (datalen == 0) { + playlist_swap(&playlist_tmp, off); + memset(&playlist_tmp, 0, sizeof(playlist_tmp)); + off = 0; + off_found = 0; + break; + } + if (datalen != sizeof(ps)) + fatalx("corrupted IMSG_CTL_SHOW"); + memcpy(&ps, imsg.data, sizeof(ps)); + if (ps.path[sizeof(ps.path) - 1] != '\0') + fatalx("corrupted IMSG_CTL_SHOW"); + playlist_push(&playlist_tmp, ps.path); + if (ps.status == STATE_PLAYING) + off_found = 1; + if (!off_found) + off++; + break; + + case IMSG_CTL_STATUS: + if (datalen != sizeof(player_status)) + fatalx("corrupted IMSG_CTL_STATUS"); + memcpy(&player_status, imsg.data, datalen); + if (player_status.path[sizeof(player_status.path) - 1] + != '\0') + fatalx("corrupted IMSG_CTL_STATUS"); + break; + } + } + + ev = POLLIN; + if (ibuf.w.queued) + ev |= POLLOUT; + ev_add(fd, ev, imsg_dispatch, NULL); } static void @@ -262,67 +362,28 @@ route_notfound(struct client *clt) static void render_playlist(struct client *clt) { - struct imsg imsg; - struct player_status ps; - ssize_t n; - const char *p; - int current, done; + ssize_t i; + const char *path, *p; + int current; - imsg_compose(&ibuf, IMSG_CTL_SHOW, 0, 0, -1, NULL, 0); - imsg_flush(&ibuf); - http_writes(clt, "
"); http_writes(clt, "
"); http_writes(clt, "
    "); - done = 0; - while (!done) { - if ((n = imsg_read(&ibuf)) == -1) - fatal("imsg_read"); - if (n == 0) - fatalx("pipe closed"); + for (i = 0; i < playlist.len; ++i) { + current = play_off == i; - for (;;) { - if ((n = imsg_get(&ibuf, &imsg)) == -1) - fatal("imsg_get"); - if (n == 0) - break; + p = path = playlist.songs[i]; + if (!strncmp(p, prefix, prefixlen)) + p += prefixlen; - if (imsg.hdr.type != IMSG_CTL_SHOW) { - unexpected_imsg(&imsg, "IMSG_CTL_SHOW"); - imsg_free(&imsg); - continue; - } - - if (IMSG_DATA_SIZE(imsg) == 0) { - done = 1; - break; - } - - if (IMSG_DATA_SIZE(imsg) != sizeof(ps)) - fatalx("wrong size for seek ctl"); - memcpy(&ps, imsg.data, sizeof(ps)); - if (ps.path[sizeof(ps.path) - 1] != '\0') - fatalx("received corrupted data"); - - current = ps.status == STATE_PLAYING; - - p = ps.path; - if (!strncmp(p, prefix, prefixlen)) - p += prefixlen; - - http_fmt(clt, "", - current ? " id=current" : ""); - http_writes(clt, - ""); - - imsg_free(&imsg); - } + http_fmt(clt, "", current ? " id=current" : ""); + http_writes(clt, ""); } http_writes(clt, "
"); @@ -333,43 +394,17 @@ render_playlist(struct client *clt) static void render_controls(struct client *clt) { - struct imsg imsg; - struct player_status ps; - ssize_t n; const char *oc, *ac, *p; int playing; - imsg_compose(&ibuf, IMSG_CTL_STATUS, 0, 0, -1, NULL, 0); - imsg_flush(&ibuf); - - if ((n = imsg_read(&ibuf)) == -1) - fatal("imsg_read"); - if (n == 0) - fatalx("pipe closed"); - - if ((n = imsg_get(&ibuf, &imsg)) == -1) - fatal("imsg_get"); - if (n == 0) - return; - - if (imsg.hdr.type != IMSG_CTL_STATUS) { - unexpected_imsg(&imsg, "IMSG_CTL_STATUS"); - goto done; - } - if (IMSG_DATA_SIZE(imsg) != sizeof(ps)) - fatalx("wrong size for IMSG_CTL_STATUS"); - memcpy(&ps, imsg.data, sizeof(ps)); - if (ps.path[sizeof(ps.path) - 1] != '\0') - fatalx("received corrupted data"); - - ac = ps.mode.repeat_all ? " class='mode-active'" : ""; - oc = ps.mode.repeat_one ? " class='mode-active'" : ""; - playing = ps.status == STATE_PLAYING; + ac = player_status.mode.repeat_all ? " class='mode-active'" : ""; + oc = player_status.mode.repeat_one ? " class='mode-active'" : ""; + playing = player_status.status == STATE_PLAYING; - if ((p = strrchr(ps.path, '/')) != NULL) + if ((p = strrchr(player_status.path, '/')) != NULL) p++; else - p = ps.path; + p = player_status.path; if (http_writes(clt, "
") == -1 || http_writes(clt, "

") == -1 || @@ -394,9 +429,6 @@ render_controls(struct client *clt) http_writes(clt, "") == -1 || http_writes(clt, "

") == -1) return; - - done: - imsg_free(&imsg); } static void @@ -429,9 +461,6 @@ route_home(struct client *clt) static void route_jump(struct client *clt) { - struct imsg imsg; - struct player_status ps; - ssize_t n; char path[PATH_MAX]; char *form, *field; int found = 0; @@ -453,33 +482,7 @@ route_jump(struct client *clt) log_warnx("path is %s", path); imsg_compose(&ibuf, IMSG_CTL_JUMP, 0, 0, -1, path, sizeof(path)); - imsg_flush(&ibuf); - - if ((n = imsg_read(&ibuf)) == -1) - fatal("imsg_read"); - if (n == 0) - fatalx("pipe closed"); - - for (;;) { - if ((n = imsg_get(&ibuf, &imsg)) == -1) - fatal("imsg_get"); - if (n == 0) - break; - - if (imsg.hdr.type != IMSG_CTL_STATUS) { - unexpected_imsg(&imsg, "IMSG_CTL_STATUS"); - imsg_free(&imsg); - continue; - } - - if (IMSG_DATA_SIZE(imsg) != sizeof(ps)) - fatalx("data size mismatch"); - memcpy(&ps, imsg.data, sizeof(ps)); - if (ps.path[sizeof(ps.path) - 1] != '\0') - fatalx("received corrupted data"); - log_debug("jumped to %s", ps.path); - } - + ev_add(ibuf.w.fd, POLLIN|POLLOUT, imsg_dispatch, NULL); break; } @@ -542,10 +545,7 @@ route_mode(struct client *clt) { char *form, *field; int found = 0; - ssize_t n; - struct player_status ps; struct player_mode pm; - struct imsg imsg; pm.repeat_one = pm.repeat_all = pm.consume = MODE_UNDEF; @@ -567,32 +567,7 @@ route_mode(struct client *clt) goto badreq; imsg_compose(&ibuf, IMSG_CTL_MODE, 0, 0, -1, &pm, sizeof(pm)); - imsg_flush(&ibuf); - - if ((n = imsg_read(&ibuf)) == -1) - fatal("imsg_read"); - if (n == 0) - fatalx("pipe closed"); - - for (;;) { - if ((n = imsg_get(&ibuf, &imsg)) == -1) - fatal("imsg_get"); - if (n == 0) - break; - - if (imsg.hdr.type != IMSG_CTL_STATUS) { - unexpected_imsg(&imsg, "IMSG_CTL_STATUS"); - imsg_free(&imsg); - continue; - } - - if (IMSG_DATA_SIZE(imsg) != sizeof(ps)) - fatalx("data size mismatch"); - memcpy(&ps, imsg.data, sizeof(ps)); - if (ps.path[sizeof(ps.path) - 1] != '\0') - fatalx("received corrupted data"); - } - + ev_add(ibuf.w.fd, POLLIN|POLLOUT, imsg_dispatch, NULL); break; } @@ -811,6 +786,10 @@ main(int argc, char **argv) amused_sock = dial(sock); imsg_init(&ibuf, amused_sock); + imsg_compose(&ibuf, IMSG_CTL_SHOW, 0, 0, -1, NULL, 0); + imsg_compose(&ibuf, IMSG_CTL_STATUS, 0, 0, -1, NULL, 0); + imsg_compose(&ibuf, IMSG_CTL_MONITOR, 0, 0, -1, NULL, 0); + ev_add(amused_sock, POLLIN|POLLOUT, imsg_dispatch, NULL); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC;