Last active
March 5, 2016 06:59
-
-
Save djabraham/19af4ea435dd94418af0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// THIS IS NO LONGER NECESSARY, VSCODE CAN DO REMOTE DEBUGGING NOW.. | |
// | |
// Published @ http://code.xpotent.com/2015/12/debugging-nodejs-within-docker.html | |
// | |
// VSCode requests a PID at the onset of a debugging session and monitors the process | |
// to detect when it is no longer running. For some reason, VSCode does not rely on socket | |
// state to determine this. VSCode monitors the pid and will exit if it isn't active. | |
// | |
// This proxy detects the pid within one of the initial debug messages from a node instance | |
// on a remote server, then changes it to the local pid of this debug-proxy process. | |
// | |
// example request: | |
// {"command":"evaluate","arguments":{"expression":"process.pid","global":true},"type":"request","seq":1} | |
// | |
// example response: | |
// {"seq":59,"request_seq":1,"type":"response","command":"evaluate","success":true,"body": | |
// {"handle":0,"type":"number","value":<PID>,"text":"<PID>"},"refs":[],"running":true} | |
// | |
// Node must be started using the --debug flag, and preferably the --nolazy flag too. | |
// | |
// node --debug --nolazy app.js | |
// node --debug-brk --nolazy app.js | |
// node --debug=5858 --nolazy app.js | |
// | |
// Note that VSCode also emits absolute path to the remote node debugger; therefore, it is | |
// necessary to mount the source folder to the same location within the file system as the | |
// server's. Within OSX, this can be done using bind and osxfuse. Bind will need to be | |
// downloaded and built, while osxfuse can be installed. | |
// | |
// $ sudo mkdir /server-app | |
// $ sudo bindfs $(pwd)/local-source /server-app | |
// | |
// $ node debug-proxy 5860 5858 | |
// | |
// VERSION | |
// | |
// 2015-11-30 Dan Abraham - Initial release. | |
// 2015-12-04 Dan Abraham - Bug fixes, during initialization. | |
// | |
var net = require("net"); | |
var spawn = require("child_process").spawn; | |
if (process.argv.length < 4) { | |
console.log("\r\n\r\n usage: node debug-proxy.js <local-port> <remote-port>\r\n\r\n"); | |
process.exit(1); | |
} | |
var localHost = "127.0.0.1"; | |
var nodeAppName = process.argv[0]; | |
var localClientPort = parseInt(process.argv[2]); | |
var remoteProcessPort = parseInt(process.argv[3]); | |
var outputPackets = (process.argv[4]); | |
console.log(""); | |
console.log("Local Port: ", localClientPort); | |
console.log("Remote Port: ", remoteProcessPort); | |
console.log(""); | |
var remoteProcessSocket = null; | |
var localEditorSocket = null; | |
var localChildProcess = null; | |
var transactionNumber = 0; | |
var transactionNumberPid = -1; | |
var transactionTriggerPid = '{"expression":"process.pid","global":true}'; | |
process.on("SIGTERM", function (code) { | |
console.log("debugger-proxy: terminated (SIGTERM) (code: " + code + ")"); | |
localEditorShutdown(); | |
remoteProcessDetach(); | |
}); | |
process.once("uncaughtException", function (error) { | |
console.log("debugger-proxy: fatal error, shutdown initiated"); | |
console.log(error.stack); | |
localEditorShutdown(); | |
remoteProcessDetach(); | |
process.exit(); | |
}); | |
function remoteProcessDetach() { | |
if (remoteProcessSocket) { | |
console.log("debugger-proxy: executed remoteProcessDetach"); | |
remoteProcessSocket.end(); | |
remoteProcessSocket.unref(); | |
remoteProcessSocket = null; | |
} | |
} | |
// Attaching to remote node process | |
function remoteProcessAttach() { | |
console.log("debugger-proxy: attempting remoteProcessAttach"); | |
if (remoteProcessSocket == null) { | |
remoteProcessSocket = new net.Socket(); | |
remoteProcessSocket.on("data", function (data) { | |
var outString = data.toString(); | |
if (outputPackets) { | |
console.log("\r\n------------------- RESPONSE (trans: " + transactionNumber + ")\r\n"); | |
console.log(outString); | |
} | |
// Confirming it's a JSON payload, PID is expected to be a small and complete response (1 packet) | |
var jsonDelimiterIndex = outString.indexOf('{'); | |
if ((transactionNumberPid === transactionNumber) && (jsonDelimiterIndex > 0) && | |
(outString.indexOf('type":"response","command":"evaluate","success":true') > 0)) { | |
var outObject = JSON.parse(outString.substr(jsonDelimiterIndex)); | |
var originalPid = outObject.body.value; | |
outObject.body.value = process.pid; | |
outObject.body.text = process.pid.toString(); | |
var outStringNew = JSON.stringify(outObject); | |
var outPacketNew = "Content-Length: " + (outStringNew.length) + "\r\n\r\n" + outStringNew; | |
localEditorSocket.write(new Buffer(outPacketNew)); | |
console.log("\r\nPID Adjustment From (" + originalPid + ") To (" + outObject.body.value + ")\r\n"); | |
console.log(outPacketNew); | |
} else { | |
if (localEditorSocket != null) { | |
localEditorSocket.write(data); | |
} | |
} | |
}); | |
remoteProcessSocket.on("close", function () { | |
console.log("debugger-proxy: remoteProcessSocket closed"); | |
remoteProcessSocket.unref(); | |
remoteProcessSocket = null; | |
}); | |
remoteProcessSocket.on("connect", function () { | |
console.log("debugger-proxy: remoteProcessSocket connected"); | |
}); | |
remoteProcessSocket.on("error", function (err) { | |
console.log("debugger-proxy: remoteProcessSocket error"); | |
console.log(err); | |
remoteProcessSocket.unref(); | |
}); | |
remoteProcessSocket.connect(remoteProcessPort, localHost, function () { | |
console.log("debugger-proxy: remoteProcessSocket created (" + localHost + ":" + remoteProcessPort + ")"); | |
}); | |
} | |
return; | |
} | |
// Start socket server listening for local connection from editor | |
var localServer = net.createServer(function (socket) { | |
// Service only handles one editor connection at a time | |
if (localEditorSocket != null) { | |
console.log("debugger-proxy: localEditorSocket connection rejected - already connected"); | |
return; | |
} | |
console.log(""); | |
console.log("debugger-proxy: localEditorSocket connected, attaching to remoteProcessSocket"); | |
if (!remoteProcessSocket) remoteProcessAttach(); | |
// Wire up local socket server | |
transactionNumber = 0; | |
localEditorSocket = socket; | |
localEditorSocket.on("data", function (data) { | |
transactionNumber++; | |
var inString = data.toString(); | |
if (outputPackets) { | |
console.log("\r\n------------------- REQUEST (trans: " + transactionNumber + ")\r\n"); | |
console.log(inString); | |
} | |
// Flagging VSCode PID requests, so the can be changed on the inbound trip | |
if (inString.indexOf(transactionTriggerPid) > 0) | |
transactionNumberPid = transactionNumber; | |
if (remoteProcessSocket != null) { | |
remoteProcessSocket.write(data); | |
} else { | |
console.log("debugger-proxy: error connecting to remote process debugger"); | |
} | |
}); | |
localEditorSocket.on("close", function (data) { | |
console.log("debugger-proxy: localEditorSocket disconnected (trans: " + transactionNumber + ")"); | |
localEditorSocket = null; | |
}); | |
}); | |
function localEditorListen() { | |
localServer.listen(localClientPort, localHost); | |
console.log("debugger-proxy: localEditorSocket listening for connection (" + localHost + ":" + localClientPort + ")"); | |
} | |
function localEditorShutdown(restart) { | |
console.log("debugger-proxy: executed localServer shutdown"); | |
localServer.close(); | |
localServer.unref(); | |
localEditorSocket = null; | |
if (restart) { | |
setTimeout(function() { | |
localEditorListen(); | |
}, 5000) | |
} | |
} | |
localEditorListen(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment