initial
This commit is contained in:
commit
8c5826972b
6 changed files with 167 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
npm-debug.log
|
69
commands.js
Normal file
69
commands.js
Normal 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
6
demo/index.html
Normal 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
4
demo/index.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
let httpServer = require("http").createServer();
|
||||
httpServer.listen(8080);
|
||||
|
||||
require("..").ws2mpd(httpServer);
|
71
index.js
Normal file
71
index.js
Normal 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
15
package.json
Normal 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"
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue