diff --git a/demo/index.html b/demo/index.html index 4a9679b..4b1c88d 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/demo/index.js b/demo/index.js index c9ae2c4..fa26301 100644 --- a/demo/index.js +++ b/demo/index.js @@ -1,4 +1,6 @@ let httpServer = require("http").createServer(); httpServer.listen(8080); -require("..").ws2mpd(httpServer); +let mod = require(".."); +mod.logging(true); +mod.ws2mpd(httpServer); diff --git a/index.js b/index.js index 7bf4b8f..fedc959 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ #!/usr/bin/env node -const commands = require("./commands"); const log = require("./log.js").log; +const Queue = require("./queue").Queue; function initConnection(request) { let ws = request.accept(); @@ -16,47 +16,36 @@ function initConnection(request) { mpd.setTimeout(0); mpd.connect(port, host); - let commandQueue = []; - let command = null; - - function waitForCommand(cmd) { - command = cmd; - cmd.on("done", data => { - log("ws <--", data); - ws.send(JSON.stringify(data)); - command = null; - processQueue(); - }); - } - - function processQueue() { - if (command || !commandQueue.length) { return; } - let cmd = commands.create(mpd, commandQueue.shift()); - waitForCommand(cmd); - } - - ws.on("message", message => { - log("ws -->", message.utf8Data); - commandQueue.push(message.utf8Data); - processQueue(); + // data coming from the response parser + let queue = new Queue(mpd); + queue.on("response", data => { + log("ws <--", data); + ws.send(JSON.stringify(data)); }); + // data going into the response parser + ws.on("message", message => { + log("ws -->", message.utf8Data); + queue.add(message.utf8Data); + }); + + // client closes ws.on("close", (reasonCode, description) => { log(`ws ${ws.remoteAddress} disconnected`); mpd.end(); }); + // server closes mpd.on("close", () => { log("mpd disconnected"); ws.close(); }); + // fail to conect mpd.on("error", () => { log("mpd connection error"); ws.close(); }); - - waitForCommand(commands.welcome(mpd)); } exports.logging = function(enabled) { diff --git a/package.json b/package.json index 1906ea5..ad34e33 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ws2mpd", - "version": "2.1.0", + "version": "2.2.0", "description": "", "main": "index.js", "scripts": { diff --git a/commands.js b/queue.js similarity index 65% rename from commands.js rename to queue.js index e5e386b..c8113fe 100644 --- a/commands.js +++ b/queue.js @@ -1,7 +1,7 @@ const EventEmitter = require("events"); const log = require("./log.js").log; -class Command extends EventEmitter { +class Response extends EventEmitter { constructor(mpd) { super(); this._mpd = mpd; @@ -33,12 +33,10 @@ class Command extends EventEmitter { } } -class Normal extends Command { - constructor(mpd, command) { +class Normal extends Response { + constructor(mpd) { super(mpd); this._lines = []; - log("--> mpd", command); - mpd.write(command + "\n"); } _processBuffer() { @@ -51,23 +49,22 @@ class Normal extends Command { } } -class Welcome extends Command { +class Idle extends Normal {} + +class Welcome extends Response { _processBuffer() { let line = this._getLine(); if (line) { this._done([line]); } } } -class AlbumArt extends Command { - constructor(mpd, command) { +class Binary extends Response { + constructor(mpd) { super(mpd); this._size = 0; this._binary = 0; this._data = null; this._lines = []; - - log("--> mpd", command); - mpd.write(command + "\n"); } _processBuffer() { @@ -101,25 +98,59 @@ class AlbumArt extends Command { 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); + +exports.Queue = class extends EventEmitter { + constructor(mpd) { + super(); + this._mpd = mpd; + this._waiting = []; + this._current = null; + + this._create(Welcome); + } + + add(str) { + if (str == "noidle" && this._current instanceof Idle) { + this._mpd.write(str + "\n"); + return; + } + this._waiting.push(str); + this._process(); + } + + _process() { + if (this._current || !this._waiting.length) { return; } + let str = this._waiting.shift(); + this._create(getCtor(str)); + log("--> mpd", str); + this._mpd.write(str + "\n"); + } + + _create(ctor) { + let cmd = new ctor(this._mpd); + this._current = cmd; + + cmd.on("done", data => { + this.emit("response", data); + this._current = null; + this._process(); + }); } - return new Normal(mpd, command); } -exports.welcome = function(mpd) { - return new Welcome(mpd); +function getCtor(command) { + switch (true) { + case command.startsWith("idle"): return Idle; + case command.startsWith("albumart") || command.startsWith("readpicture"): return Binary; + default: return Normal; + } }