X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/f08c0859513712f805da09ae1e1bcefb436b4096..417ef7de00568897d331d282478d93b323574f8c:/server/server-queue.c diff --git a/server/server-queue.c b/server/server-queue.c index 2b0e89e..25dae71 100644 --- a/server/server-queue.c +++ b/server/server-queue.c @@ -1,67 +1,39 @@ /* * This file is part of DisOrder. - * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell + * Copyright (C) 2004-2008 Richard Kettlewell * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA + * along with this program. If not, see . */ - -#include -#include "types.h" - -#include -#include -#include -#include -#include - -#include "mem.h" -#include "log.h" -#include "split.h" -#include "printf.h" -#include "queue.h" -#include "server-queue.h" -#include "eventlog.h" -#include "plugin.h" -#include "basen.h" -#include "configuration.h" -#include "inputline.h" -#include "disorder.h" +/** @file server/server-queue.c + * @brief Server-specific track queue support + */ +#include "disorder-server.h" /* the head of the queue is played next, so normally we add to the tail */ -struct queue_entry qhead = { &qhead, &qhead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +struct queue_entry qhead = { + .next = &qhead, + .prev = &qhead +}; /* the head of the recent list is the oldest thing, the tail the most recently * played */ -struct queue_entry phead = { &phead, &phead, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +struct queue_entry phead = { + .next = &phead, + .prev = &phead +}; -static long pcount; - -/* add new entry @n@ to a doubly linked list just after @b@ */ -static void l_add(struct queue_entry *b, struct queue_entry *n) { - n->prev = b; - n->next = b->next; - n->next->prev = n; - n->prev->next = n; -} - -/* remove an entry from a doubly-linked list */ -static void l_remove(struct queue_entry *node) { - node->next->prev = node->prev; - node->prev->next = node->next; -} +long pcount; void queue_fix_sofar(struct queue_entry *q) { long sofar; @@ -78,41 +50,66 @@ void queue_fix_sofar(struct queue_entry *q) { if(q->uptopause == -1) /* Don't know how far thru. */ sofar = -1; else if(q->lastresumed) /* Has been paused and resumed. */ - sofar = q->uptopause + time(0) - q->lastresumed; + sofar = q->uptopause + xtime(0) - q->lastresumed; else /* Currently paused. */ sofar = q->uptopause; } else /* Never been paused. */ - sofar = time(0) - q->played; + sofar = xtime(0) - q->played; q->sofar = sofar; } } static void queue_read_error(const char *msg, void *u) { - fatal(0, "error parsing queue %s: %s", (const char *)u, msg); + disorder_fatal(0, "error parsing queue %s: %s", (const char *)u, msg); } static void queue_do_read(struct queue_entry *head, const char *path) { char *buffer; FILE *fp; struct queue_entry *q; + int ver = 0; if(!(fp = fopen(path, "r"))) { if(errno == ENOENT) return; /* no queue */ - fatal(errno, "error opening %s", path); + disorder_fatal(errno, "error opening %s", path); } head->next = head->prev = head; while(!inputline(path, fp, &buffer, '\n')) { + if(buffer[0] == '#') { + /* Version indicator */ + ver = atoi(buffer + 1); + continue; + } q = xmalloc(sizeof *q); queue_unmarshall(q, buffer, queue_read_error, (void *)path); + if(ver < 1) { + /* Fix up origin field as best we can; will be wrong in some cases but + * hopefully not too horribly so. */ + q->origin = q->submitter ? origin_picked : origin_random; + /* Eliminated obsolete states, since they are assumed elsewhere not to be + * set. */ + switch(q->state) { + case playing_isscratch: + q->origin = origin_scratch; + q->state = playing_unplayed; + break; + case playing_random: + q->state = playing_unplayed; + break; + default: + break; + } + } if(head == &qhead && (!q->track || !q->when)) - fatal(0, "incomplete queue entry in %s", path); - l_add(head->prev, q); + disorder_fatal(0, "incomplete queue entry in %s", path); + queue_insert_entry(head->prev, q); } - if(ferror(fp)) fatal(errno, "error reading %s", path); + if(ferror(fp)) + disorder_fatal(errno, "error reading %s", path); fclose(fp); } @@ -139,12 +136,15 @@ static void queue_do_write(const struct queue_entry *head, const char *path) { struct queue_entry *q; byte_xasprintf(&tmp, "%s.new", path); - if(!(fp = fopen(tmp, "w"))) fatal(errno, "error opening %s", tmp); + if(!(fp = fopen(tmp, "w"))) disorder_fatal(errno, "error opening %s", tmp); + /* Save version indicator */ + if(fprintf(fp, "#1\n") < 0) + disorder_fatal(errno, "error writing %s", tmp); for(q = head->next; q != head; q = q->next) if(fprintf(fp, "%s\n", queue_marshall(q)) < 0) - fatal(errno, "error writing %s", tmp); - if(fclose(fp) < 0) fatal(errno, "error closing %s", tmp); - if(rename(tmp, path) < 0) fatal(errno, "error replacing %s", path); + disorder_fatal(errno, "error writing %s", tmp); + if(fclose(fp) < 0) disorder_fatal(errno, "error closing %s", tmp); + if(rename(tmp, path) < 0) disorder_fatal(errno, "error replacing %s", path); } void queue_write(void) { @@ -155,148 +155,6 @@ void recent_write(void) { queue_do_write(&phead, config_get_file("recent")); } -static void queue_id(struct queue_entry *q) { - static unsigned long serial; - unsigned long a[3]; - char buffer[128]; - - a[0] = serial++ & 0xFFFFFFFFUL; - a[1] = time(0) & 0xFFFFFFFFUL; - a[2] = getpid() & 0xFFFFFFFFUL; - basen(a, 3, buffer, sizeof buffer, 62); - q->id = xstrdup(buffer); -} - -struct queue_entry *queue_add(const char *track, const char *submitter, - int where) { - struct queue_entry *q, *beforeme; - - q = xmalloc(sizeof *q); - q->track = xstrdup(track); - q->submitter = submitter ? xstrdup(submitter) : 0; - q->state = playing_unplayed; - queue_id(q); - time(&q->when); - switch(where) { - case WHERE_START: - l_add(&qhead, q); - break; - case WHERE_END: - l_add(qhead.prev, q); - break; - case WHERE_BEFORE_RANDOM: - /* We want to find the point in the queue before the block of random tracks - * at the end. */ - beforeme = &qhead; - while(beforeme->prev != &qhead - && beforeme->prev->state == playing_random) - beforeme = beforeme->prev; - l_add(beforeme->prev, q); - break; - } - /* submitter will be a null pointer for a scratch */ - if(submitter) - notify_queue(track, submitter); - eventlog_raw("queue", queue_marshall(q), (const char *)0); - return q; -} - -int queue_move(struct queue_entry *q, int delta, const char *who) { - int moved = 0; - char buffer[20]; - - /* not the most efficient approach but hopefuly relatively comprehensible: - * the idea is that for each step we determine which nodes are affected, and - * fill in all the links starting at the 'prev' end and moving towards the - * 'next' end. */ - - while(delta > 0 && q->prev != &qhead) { - struct queue_entry *n, *p, *pp; - - n = q->next; - p = q->prev; - pp = p->prev; - pp->next = q; - q->prev = pp; - q->next = p; - p->prev = q; - p->next = n; - n->prev = p; - --delta; - ++moved; - } - - while(delta < 0 && q->next != &qhead) { - struct queue_entry *n, *p, *nn; - - p = q->prev; - n = q->next; - nn = n->next; - p->next = n; - n->prev = p; - n->next = q; - q->prev = n; - q->next = nn; - nn->prev = q; - ++delta; - --moved; - } - - if(moved) { - info("user %s moved %s", who, q->id); - notify_queue_move(q->track, who); - sprintf(buffer, "%d", moved); - eventlog("moved", who, (char *)0); - } - - return delta; -} - -static int find_in_list(struct queue_entry *needle, - int nqs, struct queue_entry **qs) { - int n; - - for(n = 0; n < nqs; ++n) - if(qs[n] == needle) - return 1; - return 0; -} - -void queue_moveafter(struct queue_entry *target, - int nqs, struct queue_entry **qs, - const char *who) { - struct queue_entry *q; - int n; - - /* Normalize */ - if(!target) - target = &qhead; - else - while(find_in_list(target, nqs, qs)) - target = target->prev; - /* Do the move */ - for(n = 0; n < nqs; ++n) { - q = qs[n]; - l_remove(q); - l_add(target, q); - target = q; - /* Log the individual tracks */ - info("user %s moved %s", who, q->id); - notify_queue_move(q->track, who); - } - /* Report that the queue changed to the event log */ - eventlog("moved", who, (char *)0); -} - -void queue_remove(struct queue_entry *which, const char *who) { - if(who) { - info("user %s removed %s", who, which->id); - notify_queue_move(which->track, who); - } - eventlog("removed", which->id, who, (const char *)0); - l_remove(which); -} - struct queue_entry *queue_find(const char *key) { struct queue_entry *q; @@ -307,19 +165,6 @@ struct queue_entry *queue_find(const char *key) { return q != &qhead ? q : 0; } -void queue_played(struct queue_entry *q) { - while(pcount && pcount >= config->history) { - eventlog("recent_removed", phead.next->id, (char *)0); - l_remove(phead.next); - pcount--; - } - if(config->history) { - eventlog_raw("recent_added", queue_marshall(q), (char *)0); - l_add(phead.prev, q); - ++pcount; - } -} - /* Local Variables: c-basic-offset:2