this._cb_update_state = cb_update_state;
this._debug_enabled = debug_enabled;
this._queue = ['init'];
+ this._recv_buffer = [];
+ this._recv_buffer_last = 0;
this.state = {};
}
this._queue.push(msg);
this._socket.send(msg, function(x) {
_this.log(0x1, 'send: ' + msg + ':', x);
+ if (x.bytesWritten < 0) {
+ _this.log(0x1, 'reconnecting...');
+ _this._socket.reconnect();
+ _this.queue = [msg];
+ _this._socket.send(msg);
+ }
});
}
+Mpc.prototype._parse_result = function(lines) {
+ var state = {};
+ var keys = [];
+ var key, val, i;
+
+ lines.forEach(function(line) {
+ i = line.indexOf(':');
+ if (i == -1)
+ return; // Ignores the OK line
+ key = line.substr(0, i);
+ keys.push(key);
+ val = line.substr(i + 2);
+ state[key] = val;
+ });
+
+ return {
+ 'state': state,
+ 'keys': keys,
+ };
+}
+
Mpc.prototype.recv_msg = function(lines) {
- curr = this._queue.shift();
+ var state, keys, ret;
+ var curr = this._queue.shift();
this.log(0x2, 'recv: [' + curr + ']:', lines.join('\n'));
+ if (lines[0].substr(0, 4) == 'ACK ')
+ this.err(curr, lines.join('\n'));
curr = curr.split(' ');
switch (curr[0]) {
- // Needs to return a list of dicts (see above for dicts).
- //case 'playlistinfo':
+ case 'playlistinfo':
+ var i = 2, playlist = [], song;
+ while (i < lines.length) {
+ if (lines[i].substr(0, 5) == 'file:') {
+ song = this._parse_result(lines.splice(0, i + 1)).state;
+ playlist = playlist.concat(song);
+ i = 0;
+ } else
+ ++i;
+ }
+ this.state.Playlist = playlist;
+ this.state.Playlist.lastUpdate = (new Date()).getTime();
+ this._cb_update_state(this.state);
+ break;
+
case 'currentsong':
+ this.state.Currentsong = this._parse_result(lines).state;
+ this.state.Currentsong.lastUpdate = (new Date()).getTime();
+ this._cb_update_state(this.state);
+ break;
+
case 'stats':
case 'status':
- state = {};
- keys = [];
- lines.forEach(function(line) {
- i = line.indexOf(':');
- if (i == -1)
- return; // Ignores the OK line
- key = line.substr(0, i);
- keys.push(key);
- val = line.substr(i + 2);
- state[key] = val;
- });
+ ret = this._parse_result(lines);
+ state = ret.state;
+ keys = ret.keys;
// When mpd is stopped, it gives us back crap values for some things.
if ('state' in state && state.state == 'stop') {
}
// Now merge the current state with the previous one so that we don't
// lose information like volume or song position.
- curr_state = this.state;
+ var curr_state = this.state;
keys.forEach(function(key) {
curr_state[key] = state[key];
});
this._cb_update_state(curr_state);
break;
+
default:
this._cb_update_state(lines, curr);
break;
Mpc.prototype.recv = function(msg) {
/* We can get back a bunch of responses in a row, so parse them out */
- /* XXX: Do we have to handle partial reads ? like long playlists ... */
- lines = msg.split('\n');
+ var lines = this._recv_buffer = this._recv_buffer.concat(msg.split('\n'));
var i = 0;
while (i < lines.length) {
- if (lines[i] == 'OK' || lines[i].substr(0, 3) == 'OK ') {
+ if (lines[i] == 'OK' || lines[i].substr(0, 3) == 'OK ' ||
+ lines[i].substr(0, 4) == 'ACK ') {
this.recv_msg(lines.splice(0, i + 1));
i = 0;
} else
++i;
}
+
+ if (lines.length && this._recv_buffer_last != lines.length) {
+ // Keep sucking in data so long as more exists.
+ this._recv_buffer_last = lines.length;
+ this._socket.poll();
+ } else
+ this._recv_buffer_last = lines.length;
}
/*
// seekid {SONGID} {TIME}
Mpc.prototype.seekid = Mpc.__make_send_arg2('seekid');
// seekcur {TIME}
-Mpc.prototype.seekcur = Mpc.__make_send_arg1('seek');
+Mpc.prototype.seekcur = Mpc.__make_send_arg1('seekcur');
// stop
Mpc.prototype.stop = Mpc.__make_send_void('stop');