chiark / gitweb /
synchronize with disorder.dev
[disorder] / clients / test-eclient.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2006 Richard Kettlewell
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #include <config.h>
22 #include "types.h"
23
24 #include <sys/select.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <time.h>
30
31 #include "queue.h"
32 #include "mem.h"
33 #include "log.h"
34 #include "eclient.h"
35 #include "configuration.h"
36 #include "syscalls.h"
37 #include "wstat.h"
38 #include "charset.h"
39
40 /* TODO: a more comprehensive test */
41
42 static fd_set rfd, wfd;
43 static int maxfd;
44 static disorder_eclient *clients[1024];
45 static char **tracks;
46 static disorder_eclient *c;
47 static char u_value;
48 static int quit;
49
50 static const char *modes[] = { "none", "read", "write", "read write" };
51
52 static void cb_comms_error(void *u, const char *msg) {
53   assert(u == &u_value);
54   fprintf(stderr, "! comms error: %s\n", msg);
55 }
56
57 static void cb_protocol_error(void *u,
58                               void attribute((unused)) *v,
59                               int attribute((unused)) code,
60                               const char *msg) {
61   assert(u == &u_value);
62   fprintf(stderr, "! protocol error: %s\n", msg);
63 }
64
65 static void cb_poll(void *u, disorder_eclient *c_, int fd, unsigned mode) {
66   assert(u == &u_value);
67   assert(fd >= 0);
68   assert(fd < 1024);                    /* bodge */
69   fprintf(stderr, "  poll callback %d %s\n", fd, modes[mode]);
70   if(mode & DISORDER_POLL_READ)
71     FD_SET(fd, &rfd);
72   else
73     FD_CLR(fd, &rfd);
74   if(mode & DISORDER_POLL_WRITE)
75     FD_SET(fd, &wfd);
76   else
77     FD_CLR(fd, &wfd);
78   clients[fd] = mode ? c_ : 0;
79   if(fd > maxfd) maxfd = fd;
80 }
81
82 static void cb_report(void attribute((unused)) *u,
83                       const char attribute((unused)) *msg) {
84 }
85
86 static const disorder_eclient_callbacks callbacks = {
87   cb_comms_error,
88   cb_protocol_error,
89   cb_poll,
90   cb_report
91 };
92
93 /* cheap plastic event loop */
94 static void loop(void) {
95   int n;
96   
97   while(!quit) {
98     fd_set r = rfd, w = wfd;
99     n = select(maxfd + 1, &r, &w, 0, 0);
100     if(n < 0) {
101       if(errno == EINTR) continue;
102       fatal(errno, "select");
103     }
104     for(n = 0; n <= maxfd; ++n)
105       if(clients[n] && (FD_ISSET(n, &r) || FD_ISSET(n, &w)))
106         disorder_eclient_polled(clients[n],
107                                 ((FD_ISSET(n, &r) ? DISORDER_POLL_READ : 0)
108                                  |(FD_ISSET(n, &w) ? DISORDER_POLL_WRITE : 0)));
109   }
110   printf(". quit\n");
111 }
112
113 static void done(void) {
114   printf(". done\n");
115   disorder_eclient_close(c);
116   quit = 1;
117 }
118
119 static void play_completed(void *v) {
120   assert(v == tracks);
121   printf("* played: %s\n", *tracks);
122   ++tracks;
123   if(*tracks) {
124     if(disorder_eclient_play(c, *tracks, play_completed, tracks))
125       exit(1);
126   } else
127     done();
128 }
129
130 static void version_completed(void *v, const char *value) {
131   printf("* version: %s\n", value);
132   if(v) {
133     if(*tracks) {
134       if(disorder_eclient_play(c, *tracks, play_completed, tracks))
135         exit(1);
136     } else
137       done();
138   }
139 }
140
141 /* TODO: de-dupe with disorder.c */
142 static void print_queue_entry(const struct queue_entry *q) {
143   if(q->track) xprintf("track %s\n", nullcheck(utf82mb(q->track)));
144   if(q->id) xprintf("  id %s\n", nullcheck(utf82mb(q->id)));
145   if(q->submitter) xprintf("  submitted by %s at %s",
146                            nullcheck(utf82mb(q->submitter)), ctime(&q->when));
147   if(q->played) xprintf("  played at %s", ctime(&q->played));
148   if(q->state == playing_started
149      || q->state == playing_paused) xprintf("  %lds so far",  q->sofar);
150   else if(q->expected) xprintf("  might start at %s", ctime(&q->expected));
151   if(q->scratched) xprintf("  scratched by %s\n",
152                            nullcheck(utf82mb(q->scratched)));
153   else xprintf("  %s\n", playing_states[q->state]);
154   if(q->wstat) xprintf("  %s\n", wstat(q->wstat));
155 }
156
157 static void recent_completed(void *v, struct queue_entry *q) {
158   assert(v == 0);
159   for(; q; q = q->next)
160     print_queue_entry(q);
161   if(disorder_eclient_version(c, version_completed, (void *)"")) exit(1);
162 }
163
164 int main(int argc, char **argv) {
165   assert(argc > 0);
166   mem_init();
167   debugging = 0;                        /* turn on for even more verbosity */
168   if(config_read(0)) fatal(0, "config_read failed");
169   tracks = &argv[1];
170   c = disorder_eclient_new(&callbacks, &u_value);
171   assert(c != 0);
172   /* stack up several version commands to test pipelining */
173   if(disorder_eclient_version(c, version_completed, 0)) exit(1);
174   if(disorder_eclient_version(c, version_completed, 0)) exit(1);
175   if(disorder_eclient_version(c, version_completed, 0)) exit(1);
176   if(disorder_eclient_version(c, version_completed, 0)) exit(1);
177   if(disorder_eclient_version(c, version_completed, 0)) exit(1);
178   if(disorder_eclient_recent(c, recent_completed, 0)) exit(1);
179   loop();
180   exit(0);
181 }
182
183 /*
184 Local Variables:
185 c-basic-offset:2
186 comment-column:40
187 End:
188 */