208 lines
5.3 KiB
JavaScript
208 lines
5.3 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.default = void 0;
|
|
|
|
function _ws() {
|
|
const data = require("ws");
|
|
|
|
_ws = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _cliTools() {
|
|
const data = require("@react-native-community/cli-tools");
|
|
|
|
_cliTools = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _prettyFormat() {
|
|
const data = _interopRequireDefault(require("pretty-format"));
|
|
|
|
_prettyFormat = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
/**
|
|
* This number is used to version the communication protocol between
|
|
* Dev tooling like Flipper and Metro, so that in the future we can recognize
|
|
* messages coming from old clients, so that it will be simpler to implement
|
|
* backward compatibility.
|
|
*
|
|
* We start at 2 as the protocol is currently the same as used internally at FB,
|
|
* which happens to be at version 2 as well.
|
|
*/
|
|
const PROTOCOL_VERSION = 2;
|
|
|
|
function parseMessage(data) {
|
|
try {
|
|
const message = JSON.parse(data);
|
|
|
|
if (message.version === PROTOCOL_VERSION) {
|
|
return message;
|
|
}
|
|
|
|
_cliTools().logger.error('Received message had wrong protocol version: ' + message.version);
|
|
} catch (_unused) {
|
|
_cliTools().logger.error('Failed to parse the message as JSON:\n' + data);
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
/**
|
|
* Two types of messages will arrive in this function,
|
|
* 1) messages generated by Metro itself (through the reporter abstraction)
|
|
* those are yet to be serialized, and can contain any kind of data structure
|
|
* 2) a specific event generated by Metro is `client_log`, which describes
|
|
* console.* calls in the app.
|
|
* The arguments send to the console are pretty printed so that they can be
|
|
* displayed in a nicer way in dev tools
|
|
*
|
|
* @param message
|
|
*/
|
|
|
|
|
|
function serializeMessage(message) {
|
|
// We do want to send Metro report messages, but their contents is not guaranteed to be serializable.
|
|
// For some known types we will pretty print otherwise not serializable parts first:
|
|
let toSerialize = message;
|
|
|
|
if (message && message.error && message.error instanceof Error) {
|
|
toSerialize = { ...message,
|
|
error: (0, _prettyFormat().default)(message.error, {
|
|
escapeString: true,
|
|
highlight: true,
|
|
maxDepth: 3,
|
|
min: true
|
|
})
|
|
};
|
|
} else if (message && message.type === 'client_log') {
|
|
toSerialize = { ...message,
|
|
data: message.data.map(item => typeof item === 'string' ? item : (0, _prettyFormat().default)(item, {
|
|
escapeString: true,
|
|
highlight: true,
|
|
maxDepth: 3,
|
|
min: true,
|
|
plugins: [_prettyFormat().default.plugins.ReactElement]
|
|
}))
|
|
};
|
|
}
|
|
|
|
try {
|
|
return JSON.stringify(toSerialize);
|
|
} catch (e) {
|
|
_cliTools().logger.error('Failed to serialize: ' + e);
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Starts the eventsSocket at the given path
|
|
*
|
|
* @param server
|
|
* @param path typically: 'events/'
|
|
* @param messageSocket: webSocket to which all connected RN apps are listening
|
|
*/
|
|
function attachToServer(server, path, messageSocket) {
|
|
const wss = new (_ws().Server)({
|
|
server: server,
|
|
path: path,
|
|
|
|
verifyClient({
|
|
origin
|
|
}) {
|
|
// This exposes the full JS logs and enables issuing commands like reload
|
|
// so let's make sure only locally running stuff can connect to it
|
|
return origin.startsWith('http://localhost:') || origin.startsWith('file:');
|
|
}
|
|
|
|
});
|
|
const clients = new Map();
|
|
let nextClientId = 0;
|
|
/**
|
|
* broadCastEvent is called by reportEvent (below), which is called by the
|
|
* default reporter of this server, to make sure that all Metro events are
|
|
* broadcasted to all connected clients
|
|
* (that is, all devtools such as Flipper, _not_: connected apps)
|
|
*
|
|
* @param message
|
|
*/
|
|
|
|
function broadCastEvent(message) {
|
|
if (!clients.size) {
|
|
return;
|
|
}
|
|
|
|
const serialized = serializeMessage(message);
|
|
|
|
if (!serialized) {
|
|
return;
|
|
}
|
|
|
|
for (const ws of clients.values()) {
|
|
try {
|
|
ws.send(serialized);
|
|
} catch (e) {
|
|
_cliTools().logger.error(`Failed to send broadcast to client due to:\n ${e.toString()}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
wss.on('connection', function (clientWs) {
|
|
const clientId = `client#${nextClientId++}`;
|
|
clients.set(clientId, clientWs);
|
|
|
|
clientWs.onclose = clientWs.onerror = () => {
|
|
clients.delete(clientId);
|
|
};
|
|
|
|
clientWs.onmessage = event => {
|
|
const message = parseMessage(event.data.toString());
|
|
|
|
if (message == null) {
|
|
return;
|
|
}
|
|
|
|
if (message.type === 'command') {
|
|
try {
|
|
/**
|
|
* messageSocket.broadcast (not to be confused with our own broadcast above)
|
|
* forwards a command to all connected React Native applications.
|
|
*/
|
|
messageSocket.broadcast(message.command, message.params);
|
|
} catch (e) {
|
|
_cliTools().logger.error('Failed to forward message to clients: ', e);
|
|
}
|
|
} else {
|
|
_cliTools().logger.error('Unknown message type: ', message.type);
|
|
}
|
|
};
|
|
});
|
|
return {
|
|
reportEvent: event => {
|
|
broadCastEvent(event);
|
|
}
|
|
};
|
|
}
|
|
|
|
var _default = {
|
|
attachToServer
|
|
};
|
|
exports.default = _default;
|
|
|
|
//# sourceMappingURL=eventsSocketServer.js.map
|