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