define([ 'dojo/_base/declare', 'dojo/Stateful', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/node!fs', 'dojo/node!child_process', 'xide/debugger/utils/TCPUtils' ],function(declare,Stateful,lang,array,fs,child,TCPUtils){ return declare("xide.debugger.DebuggerServer", [Stateful], { inspector_instance:null, debugger_url:null, app_instance:null, options:null, inspector_pid:null, _defaultOptions:function(){ return { auto_start_debug_server:false, check_server_ready:true, web_port:8080, web_host:"0.0.0.0", debug_port:5858, no_live_edit:false, inspector_path:'/node-inspector/bin/inspector', working_path:'/PMaster/x4mm/Utils/nodejs/', node_modules_path:'node_modules' }; }, /*** * init - initialize the Debug Server with options * @param options */ init:function(options) { this.options = this._defaultOptions(); var myself = this; for(var property in this.options) { if (options[property]) { this.options[property] = options[property]; } } }, /*** * Starts the debug server instance * * @param readyCallback(url,pid) * @param errorCallback(msg) */ start:function(readyCallback,errorCallback) { this._createInspectorInstance(readyCallback,errorCallback); }, /*** * Debugs module * * @param app * @param readyCallback(url,app_pid,server_pid) * @param errorCallback(msg) */ run:function(app,readyCallback,errorCallback) { if (this.options.auto_start_debug_server) { // Launch Server if auto_start is set var myself=this; this._createInspectorInstance(function(url,pid) { myself.debugger_url = url; myself.inspector_pid = pid; myself._createAppInstance(app,readyCallback,errorCallback); }); } else { // If not, check if server is ready if check_server_ready is set if (this.options.check_server_ready) { var myself=this; TCPUtils.checkPort(this.options.web_port, this.options.web_host, function(error,status) { if (status=="closed") { if (typeof errorCallback == 'function') { errorCallback("Server instance is not ready in "+ myself.options.web_host+":"+myself.options.web_port+ ".\nConsider using auto_start_debug_server option to start it automatically."); } } else if(status=='open'){ myself._createAppInstance(app,readyCallback,errorCallback); } }); } else { // If not check_server_ready, just launch... this._createAppInstance(app,readyCallback,errorCallback); } } }, _createAppInstance:function(app,readyCallback,errorCallback) { var options= [ "--debug="+this.options.debug_port, "--debug-brk" ]; // Parsing command line options for the app to be debugged var command_line = []; var app_call = app.split(" "); if (app_call.length>1) { app = app_call[0]; for(n in app_call) { if (n>0) { command_line.push(app_call[n]); } } } var module_path=this.options.working_path+app; if (!this._checkFileExists(module_path)) { if (typeof errorCallback == 'function') { errorCallback("Cannot find module: "+module_path); } return; } var fork = child.fork; this.app_instance = fork( this.options.working_path+app, command_line, { silent:false, cwd: this.options.working_path, execArgv:options } ); // Check if new process has PID. If not, throw error if (this.app_instance.pid) { if (typeof readyCallback == 'function') { readyCallback(this.debugger_url,this.app_instance.pid,this.inspector_pid); } } else { if (typeof errorCallback == 'function') { errorCallback("Unexpected error trying to run "+app); } } this.app_instance.on('error',function(msg) { if (typeof errorCallback == 'function') { errorCallback(msg); } }); }, _checkFileExists:function(file) { if (file.search('/.js')==-1) { file+='.js'; } return (fs.existsSync(file)); }, _createInspectorInstance:function(readyCallback,errorCallback) { var options= [ "--web-port="+this.options.web_port, "--web-host="+this.options.web_host, "--debug-port="+this.options.debug_port ]; if (!this.options.no_live_edit) { options.push("--save-live-edit"); } var fork = child.fork; var modules_working_path = this.options.working_path+ this.options.node_modules_path; var module_path=modules_working_path+this.options.inspector_path; if (!this._checkFileExists(module_path)) { if (typeof errorCallback == 'function') { errorCallback("Cannot find module: "+module_path); } return; } // Calling node-inspector this.inspector_instance = fork( module_path, options, { silent:true, cwd:modules_working_path } ); var myself=this; // Receiving response from the fork creation this.inspector_instance.on('message', function(msg) { switch(msg.event) { // Everything OK case 'SERVER.LISTENING': myself.inspector_pid = myself.inspector_instance.pid; myself.debugger_url = msg.address.url; if (typeof readyCallback == 'function') { readyCallback(myself.debugger_url ,myself.inspector_pid); } break; // Something happened... case 'SERVER.ERROR': switch(msg.error.code) { // The server is already in case "EADDRINUSE": myself.debugger_url="http://"+myself.options.web_host+":"+myself.options.web_port; myself.debugger_url+="/debug?port="+myself.options.debug_port; myself.inspector_pid = null; if (typeof readyCallback == 'function') { readyCallback(myself.debugger_url ,myself.inspector_pid); } break; // Another thing... default: if (typeof errorCallback == 'function') { errorCallback("Unexpected error trying to run inspector server"); } } break; } }); this.inspector_instance.on('error',function(msg) { if (typeof errorCallback == 'function') { errorCallback(msg); } }); }, /*** * Stops the inspector instance * * @param pid */ stop:function(pid) { process.kill(pid); } }); });