chiark / gitweb /
remove debugging guff, sorry
[disorder] / lib / eclient.c
index 43fafac7a219c1c40ef57f7d374b3e7a18d7c30d..d12cf2b9ffc2336d1458888245edd5482d4a8222 100644 (file)
@@ -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;
@@ -250,25 +251,9 @@ void disorder_eclient_close(disorder_eclient *c) {
     op->sent = 0;
 }
 
-/** @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 ***********************************************************/
@@ -497,8 +482,12 @@ static void maybe_connected(disorder_eclient *c) {
     comms_error(c, "connecting to %s: %s", c->ident, strerror(err));
     /* sets state_disconnected */
   } else {
+    char *r;
+    
     /* The connection succeeded */
     c->state = state_connected;
+    byte_xasprintf(&r, "connected to %s", c->ident);
+    c->callbacks->report(c->u, r);
   }
 }
 
@@ -526,6 +515,8 @@ static void authbanner_opcallback(disorder_eclient *c,
 
 static void authuser_opcallback(disorder_eclient *c,
                                 struct operation *op) {
+  char *r;
+
   D(("authuser_opcallback"));
   if(c->rc / 100 != 2) {
     /* Wrong password or something.  We cannot proceed. */
@@ -535,6 +526,8 @@ static void authuser_opcallback(disorder_eclient *c,
   }
   /* OK, we're authenticated now. */
   c->authenticated = 1;
+  byte_xasprintf(&r, "authenticated with %s", c->ident);
+  c->callbacks->report(c->u, r);
   if(c->log_callbacks && !(c->ops && c->ops->opcallback == log_opcallback))
     /* We are a log client, switch to logging mode */
     stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, c->log_v,
@@ -1136,8 +1129,24 @@ int disorder_eclient_search(disorder_eclient *c,
                 "search", terms, (char *)0);
 }
 
+int disorder_eclient_nop(disorder_eclient *c,
+                         disorder_eclient_no_response *completed,
+                         void *v) {
+  return simple(c, no_response_opcallback, (void (*)())completed, v, 
+                "nop", (char *)0);
+}
+
 /* Log clients ***************************************************************/
 
+/** @brief Monitor the server log
+ * @param c Client
+ * @param callbacks Functions to call when anything happens
+ * @param v Passed to @p callbacks functions
+ *
+ * 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.
+ */
 int disorder_eclient_log(disorder_eclient *c,
                          const disorder_eclient_log_callbacks *callbacks,
                          void *v) {
@@ -1191,13 +1200,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,
@@ -1209,7 +1224,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,
@@ -1249,7 +1267,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 {
@@ -1276,7 +1297,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,
@@ -1292,6 +1313,43 @@ 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);
+  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