node-inspector/lib/FrontendClient.js

173 строки
4.5 KiB
JavaScript

var EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits,
debugProtocol = require('debug')('node-inspector:protocol:devtools'),
ErrorNotConnected = require('./DebuggerClient').ErrorNotConnected;
/**
* FrontendClient encapsulates communication with front-end running in browser.
* @param {{on: Function, send: Function}} connection
* Socket.io connection object.
* @constructor
* @extends EventEmitter
*/
function FrontendClient(connection) {
this._connection = connection;
this._registerEventHandlers();
}
inherits(FrontendClient, EventEmitter);
Object.defineProperties(FrontendClient.prototype, {
/** @type {boolean} */
isConnected: {
get: function() {
return this._connection != null;
}
}
});
FrontendClient.prototype._registerEventHandlers = function() {
this._connection.on('close', this._onConnectionClose.bind(this));
this._connection.on('message', this._onConnectionMessage.bind(this));
};
FrontendClient.prototype._onConnectionClose = function() {
this._connection = null;
this.emit('close');
};
FrontendClient.prototype._onConnectionMessage = function(message) {
this.emit('message', message);
};
/**
* Send a message to front-end.
* @param {!Object|string} message
*/
FrontendClient.prototype._sendMessage = function(message) {
var payload = typeof message == 'string' ? message : JSON.stringify(message);
debugProtocol('backend: ' + payload);
if (!this._connection) {
if (!this._errorMessageDisplayed) {
console.log('Cannot send response - there is no front-end connection.');
this._errorMessageDisplayed = true;
}
return;
}
this._errorMessageDisplayed = false;
this._connection.send(payload);
};
/**
* Send a response to a front-end request.
* @param {number} requestId Id of the request.
* @param {string} fullMethodName
* @param {?string} error Error message or null/undefined on success.
* @param {Object=} result Response data on success.
*/
FrontendClient.prototype.sendResponse = function(requestId,
fullMethodName,
error,
result) {
if (requestId == null) {
throw new Error(
'Cannot send response to ' +
fullMethodName +
' without a requestId');
}
var message = { id: requestId };
if (error != null) {
this._onErrorResponse(fullMethodName, error);
message.error = error.toString();
} else {
message.result = result;
}
this._sendMessage(message);
};
FrontendClient.prototype._onErrorResponse = function(fullMethodName, error) {
if (error instanceof ErrorNotConnected) {
this.sendInspectorDetached(error.message);
}
this.sendLogToConsole('error', fullMethodName + ' failed.\n' + error);
};
/**
* Send an event to the front-end.
* @param {string} eventName Event name in form 'Agent.method'.
* @param {Object=} data Event data (method arguments).
*/
FrontendClient.prototype.sendEvent = function(eventName, data) {
var message = {
method: eventName,
params: data || {}
};
if (this._eventsPaused) {
this._eventsBuffer.push(message);
} else {
this._sendMessage(message);
}
};
FrontendClient.prototype.pauseEvents = function() {
if (this._eventsPaused) return;
this._eventsPaused = true;
this._eventsBuffer = [];
};
FrontendClient.prototype.resumeEvents = function() {
if (!this._eventsPaused) return;
// We are making a copy of the buffered messages list,
// so that the messages are sent event when pauseEvents()
// is called before the next tick.
var messages = this._eventsBuffer;
process.nextTick(function() {
messages.forEach(this._sendMessage, this);
}.bind(this));
this._eventsPaused = false;
this._eventsBuffer = null;
};
/**
* Ask frontend to add a new log into console window.
* @param {string} level Message level (error, warning, log, debug).
* @param {string} text
*/
FrontendClient.prototype.sendLogToConsole = function(level, text) {
this._sendMessage('showConsole');
this.sendEvent(
'Console.messageAdded',
{
message: {
source: 3,
type: 0,
level: level,
line: 0,
column: 0,
url: '',
groupLevel: 7,
repeatCount: 1,
text: text
}
}
);
};
/**
* Shortcut for sendEvent('Inspector.detached', reason)
* @param {string} reason
*/
FrontendClient.prototype.sendInspectorDetached = function(reason) {
this.sendEvent('Inspector.detached', { reason: reason });
};
exports.FrontendClient = FrontendClient;