X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/e836b1aa5fb2d0c035e7390a726a0cd0529bd906..6d1302f09d1a6958f3cddfd3c6564ee2c0b4813a:/lib/eclient.c diff --git a/lib/eclient.c b/lib/eclient.c index 6bbb530..8efefb6 100644 --- a/lib/eclient.c +++ b/lib/eclient.c @@ -127,7 +127,7 @@ struct disorder_eclient { struct vector vec; /**< @brief body */ const disorder_eclient_log_callbacks *log_callbacks; /**< @brief log callbacks */ void *log_v; /**< @brief user data */ - unsigned long statebits; /**< @brief current state */ + unsigned long statebits; /**< @brief latest state */ }; /* Forward declarations ******************************************************/ @@ -240,6 +240,7 @@ void disorder_eclient_close(disorder_eclient *c) { xclose(c->fd); c->fd = -1; c->state = state_disconnected; + c->statebits = 0; } c->output.nvec = 0; c->input.nvec = 0; @@ -248,27 +249,14 @@ void disorder_eclient_close(disorder_eclient *c) { /* We'll need to resend all operations */ for(op = c->ops; op; op = op->next) op->sent = 0; + /* Drop our use a hint that we're disconnected */ + if(c->log_callbacks && c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits); } -/** @brief Return true if @c c is connected - * - * By connected it is meant that commands have a reasonable chance of being - * processed soon, not merely that a TCP connection exists - for instance if - * the client is still authenticating then that does not count as connected. - */ -int disorder_eclient_connected(const disorder_eclient *c) { - switch(c->state) { - case state_disconnected: - case state_connecting: - case state_connected: - return 0; - case state_idle: - case state_cmdresponse: - case state_body: - case state_log: - return 1; - } - assert(!"reached"); +/** @brief Return current state */ +unsigned long disorder_eclient_state(const disorder_eclient *c) { + return c->statebits | (c->state > state_connected ? DISORDER_CONNECTED : 0); } /* Error reporting ***********************************************************/ @@ -503,6 +491,8 @@ static void maybe_connected(disorder_eclient *c) { c->state = state_connected; byte_xasprintf(&r, "connected to %s", c->ident); c->callbacks->report(c->u, r); + /* If this is a log client we expect to get a bunch of updates from the + * server straight away */ } } @@ -1161,6 +1151,9 @@ int disorder_eclient_nop(disorder_eclient *c, * Once a client is being used for logging it cannot be used for anything else. * There is magic in authuser_opcallback() to re-submit the @c log command * after reconnection. + * + * NB that the @c state callback may be called from within this function, + * i.e. not solely later on from the event loop callback. */ int disorder_eclient_log(disorder_eclient *c, const disorder_eclient_log_callbacks *callbacks, @@ -1168,6 +1161,9 @@ int disorder_eclient_log(disorder_eclient *c, if(c->log_callbacks) return -1; c->log_callbacks = callbacks; c->log_v = v; + /* Repoort initial state */ + if(c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits); stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, v, "log", (char *)0); return 0; @@ -1215,13 +1211,19 @@ static void logline(disorder_eclient *c, const char *line) { static void logentry_completed(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { if(!c->log_callbacks->completed) return; + c->statebits &= ~DISORDER_PLAYING; c->log_callbacks->completed(c->log_v, vec[0]); + if(c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_failed(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { if(!c->log_callbacks->failed)return; + c->statebits &= ~DISORDER_PLAYING; c->log_callbacks->failed(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_moved(disorder_eclient *c, @@ -1233,7 +1235,10 @@ static void logentry_moved(disorder_eclient *c, static void logentry_playing(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { if(!c->log_callbacks->playing) return; + c->statebits |= DISORDER_PLAYING; c->log_callbacks->playing(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_queue(disorder_eclient *c, @@ -1273,7 +1278,10 @@ static void logentry_removed(disorder_eclient *c, static void logentry_scratched(disorder_eclient *c, int attribute((unused)) nvec, char **vec) { if(!c->log_callbacks->scratched) return; + c->statebits &= ~DISORDER_PLAYING; c->log_callbacks->scratched(c->log_v, vec[0], vec[1]); + if(c->log_callbacks->state) + c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static const struct { @@ -1300,7 +1308,7 @@ static void logentry_state(disorder_eclient *c, break; } if(!c->log_callbacks->state) return; - c->log_callbacks->state(c->log_v, c->statebits); + c->log_callbacks->state(c->log_v, c->statebits | DISORDER_CONNECTED); } static void logentry_volume(disorder_eclient *c, @@ -1316,6 +1324,45 @@ static void logentry_volume(disorder_eclient *c, c->log_callbacks->volume(c->log_v, (int)l, (int)r); } +/** @brief Convert @p statebits to a string */ +char *disorder_eclient_interpret_state(unsigned long statebits) { + struct dynstr d[1]; + size_t n; + + static const struct { + unsigned long bit; + const char *name; + } bits[] = { + { DISORDER_PLAYING_ENABLED, "playing_enabled" }, + { DISORDER_RANDOM_ENABLED, "random_enabled" }, + { DISORDER_TRACK_PAUSED, "track_paused" }, + { DISORDER_PLAYING, "playing" }, + { DISORDER_CONNECTED, "connected" }, + }; +#define NBITS (sizeof bits / sizeof *bits) + + dynstr_init(d); + if(!statebits) + dynstr_append(d, '0'); + for(n = 0; n < NBITS; ++n) + if(statebits & bits[n].bit) { + if(d->nvec) + dynstr_append(d, '|'); + dynstr_append_string(d, bits[n].name); + statebits ^= bits[n].bit; + } + if(statebits) { + char s[20]; + + if(d->nvec) + dynstr_append(d, '|'); + sprintf(s, "%#lx", statebits); + dynstr_append_string(d, s); + } + dynstr_terminate(d); + return d->vec; +} + /* Local Variables: c-basic-offset:2