187 lines
5.6 KiB
JavaScript

var net = require("net");
var WebSocket = require("ws/index");
var MessageReader = require("./MessageReader");
var EventEmitter = require("events").EventEmitter;
var RETRY_INTERVAL = 300;
var MAX_RETRIES = 100;
function Debugger(options) {
var clients = this.clients = [];
this.broadcast = function(message) {
if (typeof message !== "string")
message = JSON.stringify(message);
clients.forEach(function(c) {
c.write(message + "\0");
});
};
}
(function() {
this.__proto__ = EventEmitter.prototype;
this.addClient = function(client) {
this.clients.push(client);
// client.send({$: 1});
client.debugger = this;
};
this.removeClient = function(client) {
var i = this.clients.indexOf(client);
if (i != -1)
this.clients.splice(i, 1);
client.debugger = null;
};
this.handleMessage = function(message) {
if (this.ws)
this.ws.send(JSON.stringify(message));
else if (this.v8Socket)
this.v8Socket.send(message);
else
console.error("recieved message when debugger is not ready", message);
};
this.connect = function(options) {
getDebuggerData(options.port, function(err, res) {
if (err) {
this.broadcast({ $: "error", message: err.message });
this.disconnect();
return console.log(err);
}
var tabs = res;
if (!tabs) {
this.connectToV8(options);
return;
}
if (tabs.length > 1)
console.log("connecting to first tab from " + tabs.length);
if (tabs[0] && tabs[0].webSocketDebuggerUrl) {
this.connectToWebsocket(tabs[0].webSocketDebuggerUrl);
}
}.bind(this));
};
this.connectToWebsocket = function(url) {
var broadcast = this.broadcast;
var self = this;
var ws = new WebSocket(url);
ws.on("open", function open() {
console.log("connected");
broadcast({ $: "connected" });
});
ws.on("close", function close() {
console.log("disconnected");
self.disconnect();
});
ws.on("message", function incoming(data) {
try {
var parsed = JSON.parse(data);
} catch (e) {
}
// console.log("<<" + data);
// ignore for now since this is noisy, and is not used on the client
if (parsed && parsed.method == "Runtime.consoleAPICalled")
return;
broadcast(data);
});
ws.on("error", function(e) {
console.log("error", e);
broadcast({ $: "error", err: e });
self.disconnect();
});
this.ws = ws;
};
this.connectToV8 = function(options) {
var broadcast = this.broadcast;
var self = this;
var connection = net.connect(options.port, options.host);
connection.on("connect", function() {
console.log("netproxy connected to debugger");
broadcast({ $: "connected", mode: "v8" });
});
connection.on("error", function(e) {
console.log("error in v8 connection", e);
self.disconnect();
});
connection.on("close", function(e) {
console.log("v8 connection closed", e);
self.disconnect();
});
new MessageReader(connection, function(response) {
broadcast(response.toString("utf8"));
});
connection.send = function(msg) {
if (msg.arguments && !msg.arguments.maxStringLength)
msg.arguments.maxStringLength = 10000;
var data = new Buffer(JSON.stringify(msg));
connection.write(new Buffer("Content-Length:" + data.length + "\r\n\r\n"));
connection.write(data);
};
this.v8Socket = connection;
};
this.disconnect = function() {
this.emit("disconnect");
this.clients.forEach(function(client) {
client.end();
});
if (this.ws)
this.ws.close();
if (this.v8Socket)
this.v8Socket.destroy();
};
}).call(Debugger.prototype);
function getDebuggerData(port, callback, retries) {
console.log("Connecting to port", port, retries);
if (retries == null) retries = MAX_RETRIES;
request({
host: "127.0.0.1",
port: port,
path: "/json/list",
}, function(err, res) {
if (err && retries > 0) {
return setTimeout(function() {
getDebuggerData(port, callback, retries - 1);
}, RETRY_INTERVAL);
}
console.log(res);
callback(err, res);
});
}
function request(options, callback) {
var socket = new net.Socket();
new MessageReader(socket, function(response) {
console.log("Initial connection response:", response);
socket.end();
if (response) {
try {
response = JSON.parse(response);
} catch (e) {}
}
callback(null, response);
});
socket.on("error", function(e) {
console.log("Initial connection error", options, e);
socket.end();
callback(e);
});
socket.connect(options.port, options.host);
socket.on("connect", function() {
socket.write("GET " + options.path + " HTTP/1.1\r\nConnection: close\r\n\r\n");
});
}
module.exports = Debugger;