ws2mpd/commands.js

129 lines
2.7 KiB
JavaScript

const EventEmitter = require("events");
function log(...args) {
console.log(Date.now(), ...args);
}
class Command extends EventEmitter {
constructor(mpd) {
super();
this._mpd = mpd;
this._buffer = Buffer.alloc(0);
this._dataListener = data => this._onData(data);
mpd.on("data", this._dataListener);
}
_onData(data) {
log("<-- mpd", data);
this._buffer = Buffer.concat([this._buffer, data]);
this._processBuffer();
}
_processBuffer() {} // abstract
_done(data) {
this._mpd.off("data", this._dataListener);
this._buffer = null;
this.emit("done", data);
}
_getLine() {
let index = this._buffer.indexOf(0x0a);
if (index == -1) { return null; }
let str = this._buffer.slice(0, index).toString("utf8");
this._buffer = this._buffer.slice(index+1);
return str;
}
}
class Normal extends Command {
constructor(mpd, command) {
super(mpd);
this._lines = [];
log("--> mpd", command);
mpd.write(command + "\n");
}
_processBuffer() {
while (1) {
let line = this._getLine();
if (!line) { break; }
this._lines.push(line);
if (line.startsWith("OK") || line.startsWith("ACK")) { return this._done(this._lines); }
}
}
}
class Welcome extends Command {
_processBuffer() {
let line = this._getLine();
if (line) { this._done([line]); }
}
}
class AlbumArt extends Command {
constructor(mpd, command) {
super(mpd);
this._size = 0;
this._binary = 0;
this._data = null;
this._lines = [];
log("--> mpd", command);
mpd.write(command + "\n");
}
_processBuffer() {
if (!this._size) {
let line = this._getLine();
if (!line) { return; }
this._lines.push(line);
if (line.startsWith("ACK")) { // no art!
this._done(this._lines);
return;
}
this._size = Number(line.split(": ").pop());
log("size", this._size);
}
if (!this._binary) {
let line = this._getLine();
if (!line) { return; }
this._lines.push(line);
this._binary = Number(line.split(": ").pop());
log("binary", this._binary);
}
if (!this._data) {
// binary data has this._binary bytes + 1 newline
if (this._buffer.length >= this._binary+1) {
this._data = this._buffer.slice(0, this._binary);
this._buffer = this._buffer.slice(this._binary+1);
this._lines.push([...this._data]);
log("data", this._data.length);
} else { return; }
}
let line = this._getLine();
if (!line) { return; }
this._lines.push(line);
this._done(this._lines);
}
}
exports.create = function(mpd, command) {
if (command.startsWith("albumart")) {
return new AlbumArt(mpd, command);
} else {
return new Normal(mpd, command);
}
return new Normal(mpd, command);
}
exports.welcome = function(mpd) {
return new Welcome(mpd);
}