This commit is contained in:
Ondrej Zara 2019-03-19 11:13:15 +01:00
commit 8c5826972b
6 changed files with 167 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
npm-debug.log

69
commands.js Normal file
View File

@ -0,0 +1,69 @@
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.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); }
}
}
exports.create = function(mpd, command) {
return new Normal(mpd, command);
}
exports.welcome = function(mpd) {
return new Welcome(mpd);
}

6
demo/index.html Normal file
View File

@ -0,0 +1,6 @@
<!doctype html>
<html>
<script>
let ws = new WebSocket("ws://localhost:8080?server=0:6600");
</script>
</html>

4
demo/index.js Normal file
View File

@ -0,0 +1,4 @@
let httpServer = require("http").createServer();
httpServer.listen(8080);
require("..").ws2mpd(httpServer);

71
index.js Normal file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env node
const commands = require("./commands");
function log(...args) {
console.log(Date.now(), ...args);
}
function initConnection(ws, server, port) {
log(`ws connection accepted, connecting to ${server}:${port}`);
let mpd = new (require("net").Socket)();
mpd.setTimeout(0);
mpd.connect(port, server);
let commandQueue = [];
let command = null;
function waitForCommand(command) {
command.on("done", data => {
log("ws <--", data);
ws.send(data);
command = null;
processQueue();
});
}
function processQueue() {
if (command || !commandQueue.length) { return; }
command = commands.create(mpd, commandQueue.shift());
waitForCommand(command);
}
ws.on("message", message => {
log("ws -->", message.utf8Data);
commandQueue.push(message.utf8Data);
processQueue();
});
ws.on("close", (reasonCode, description) => {
log(`ws ${ws.remoteAddress} disconnected`);
mpd.end();
});
mpd.on("close", () => {
log("mpd disconnected");
ws.close();
});
waitForCommand(commands.welcome(mpd));
}
function onRequest(request) {
let s = request.resourceURL.query.server || "";
let r = s.match(/^([^:]+)(:([0-9]+))?$/);
if (!r) { return request.reject(); }
let connection = request.accept(null, request.origin);
initConnection(connection, r[1], r[3] || 6600);
}
exports.ws2mpd = function(httpServer) {
function ready() { log("ws2mpd attached to a http server", httpServer.address()); }
(httpServer.listening ? ready() : httpServer.on("listening", ready));
let wsServer = new (require("websocket").server)({
httpServer,
autoAcceptConnections: false
});
wsServer.on("request", onRequest);
}

15
package.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "ws2mpd",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node demo"
},
"author": "",
"license": "ISC",
"dependencies": {
"websocket": "^1.0.28"
}
}