initial commit taken from gitlab.lrz.de

This commit is contained in:
privatereese
2018-08-24 18:09:42 +02:00
parent ae54ed4c48
commit fc05486403
28494 changed files with 2159823 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
* @flow
*/
'use strict';
import type {Server as HTTPServer} from 'http';
import type {Server as HTTPSServer} from 'https';
type WebsocketServiceInterface<T> = {
+onClientConnect: (
url: string,
sendFn: (data: string) => mixed,
) => Promise<T>,
+onClientDisconnect?: (client: T) => mixed,
+onClientError?: (client: T, e: Error) => mixed,
+onClientMessage?: (client: T, message: string) => mixed,
};
type HMROptions<TClient> = {
httpServer: HTTPServer | HTTPSServer,
websocketServer: WebsocketServiceInterface<TClient>,
path: string,
};
/**
* Attaches a WebSocket based connection to the Packager to expose
* Hot Module Replacement updates to the simulator.
*/
function attachWebsocketServer<TClient: Object>({
httpServer,
websocketServer,
path,
}: HMROptions<TClient>) {
const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer({
server: httpServer,
path: path,
});
wss.on('connection', async ws => {
let connected = true;
const url = ws.upgradeReq.url;
const sendFn = (...args) => {
if (connected) {
ws.send(...args);
}
};
const client = await websocketServer.onClientConnect(url, sendFn);
ws.on('error', e => {
websocketServer.onClientError && websocketServer.onClientError(client, e);
});
ws.on('close', () => {
websocketServer.onClientDisconnect &&
websocketServer.onClientDisconnect(client);
connected = false;
});
ws.on('message', message => {
websocketServer.onClientMessage &&
websocketServer.onClientMessage(client, message);
});
});
}
module.exports = attachWebsocketServer;

View File

@@ -0,0 +1,38 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var child_process = require('child_process');
var spawn = child_process.spawn;
var path = require('path');
var fs = require('fs');
const xsel = path.join(__dirname, 'external/xsel');
fs.chmodSync(xsel, '0755');
/**
* Copy the content to host system clipboard.
*/
function copyToClipBoard(content) {
switch (process.platform) {
case 'darwin':
var child = spawn('pbcopy', []);
child.stdin.end(new Buffer(content, 'utf8'));
return true;
case 'win32':
var child = spawn('clip', []);
child.stdin.end(new Buffer(content, 'utf8'));
return true;
case 'linux':
var child = spawn(xsel, ['--clipboard', '--input']);
child.stdin.end(new Buffer(content, 'utf8'));
return true;
default:
return false;
}
}
module.exports = copyToClipBoard;

View File

@@ -0,0 +1,130 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
/**
* This file is a copy of the reference `DeltaPatcher`, located in
* metro. The reason to not reuse that file is that in this context
* we cannot have flow annotations or CJS syntax (since this file is directly)
* injected into a static HTML page.
*
* TODO: Find a simple and lightweight way to compile `DeltaPatcher` to avoid
* having this duplicated file.
*/
(function(global) {
'use strict';
/**
* This is a reference client for the Delta Bundler: it maintains cached the
* last patched bundle delta and it's capable of applying new Deltas received
* from the Bundler.
*/
class DeltaPatcher {
constructor() {
this._lastBundle = {
pre: new Map(),
post: new Map(),
modules: new Map(),
id: undefined,
};
this._initialized = false;
this._lastNumModifiedFiles = 0;
this._lastModifiedDate = new Date();
}
static get(id) {
let deltaPatcher = this._deltaPatchers.get(id);
if (!deltaPatcher) {
deltaPatcher = new DeltaPatcher();
this._deltaPatchers.set(id, deltaPatcher);
}
return deltaPatcher;
}
/**
* Applies a Delta Bundle to the current bundle.
*/
applyDelta(deltaBundle) {
// Make sure that the first received delta is a fresh one.
if (!this._initialized && !deltaBundle.reset) {
throw new Error(
'DeltaPatcher should receive a fresh Delta when being initialized',
);
}
this._initialized = true;
// Reset the current delta when we receive a fresh delta.
if (deltaBundle.reset) {
this._lastBundle = {
pre: new Map(),
post: new Map(),
modules: new Map(),
id: undefined,
};
}
this._lastNumModifiedFiles =
deltaBundle.pre.size + deltaBundle.post.size + deltaBundle.delta.size;
if (this._lastNumModifiedFiles > 0) {
this._lastModifiedDate = new Date();
}
this._patchMap(this._lastBundle.pre, deltaBundle.pre);
this._patchMap(this._lastBundle.post, deltaBundle.post);
this._patchMap(this._lastBundle.modules, deltaBundle.delta);
this._lastBundle.id = deltaBundle.id;
return this;
}
getLastBundleId() {
return this._lastBundle.id;
}
/**
* Returns the number of modified files in the last received Delta. This is
* currently used to populate the `X-Metro-Files-Changed-Count` HTTP header
* when metro serves the whole JS bundle, and can potentially be removed once
* we only send the actual deltas to clients.
*/
getLastNumModifiedFiles() {
return this._lastNumModifiedFiles;
}
getLastModifiedDate() {
return this._lastModifiedDate;
}
getAllModules() {
return [].concat(
Array.from(this._lastBundle.pre.values()),
Array.from(this._lastBundle.modules.values()),
Array.from(this._lastBundle.post.values()),
);
}
_patchMap(original, patch) {
for (const [key, value] of patch.entries()) {
if (value == null) {
original.delete(key);
} else {
original.set(key, value);
}
}
}
}
DeltaPatcher._deltaPatchers = new Map();
global.DeltaPatcher = DeltaPatcher;
})(window);

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/* global __fbBatchedBridge, self, importScripts, postMessage, onmessage: true */
/* eslint no-unused-vars: 0 */
'use strict';
onmessage = (function() {
var visibilityState;
var showVisibilityWarning = (function() {
var hasWarned = false;
return function() {
// Wait until `YellowBox` gets initialized before displaying the warning.
if (hasWarned || console.warn.toString().includes('[native code]')) {
return;
}
hasWarned = true;
console.warn(
'Remote debugger is in a background tab which may cause apps to ' +
'perform slowly. Fix this by foregrounding the tab (or opening it in ' +
'a separate window).'
);
};
})();
var messageHandlers = {
'executeApplicationScript': function(message, sendReply) {
for (var key in message.inject) {
self[key] = JSON.parse(message.inject[key]);
}
var error;
try {
importScripts(message.url);
} catch (err) {
error = err.message;
}
sendReply(null /* result */, error);
},
'setDebuggerVisibility': function(message) {
visibilityState = message.visibilityState;
},
};
return function(message) {
if (visibilityState === 'hidden') {
showVisibilityWarning();
}
var object = message.data;
var sendReply = function(result, error) {
postMessage({replyID: object.id, result: result, error: error});
};
var handler = messageHandlers[object.method];
if (handler) {
// Special cased handlers
handler(object, sendReply);
} else {
// Other methods get called on the bridge
var returnValue = [[], [], [], 0];
var error;
try {
if (typeof __fbBatchedBridge === 'object') {
returnValue = __fbBatchedBridge[object.method].apply(null, object.arguments);
} else {
error = 'Failed to call function, __fbBatchedBridge is undefined';
}
} catch (err) {
error = err.message;
} finally {
sendReply(JSON.stringify(returnValue), error);
}
}
};
})();

View File

@@ -0,0 +1,71 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
/* global Blob, URL: true */
(function(global) {
'use strict';
let cachedBundleUrls = new Map();
/**
* Converts the passed delta URL into an URL object containing already the
* whole JS bundle Blob.
*/
async function deltaUrlToBlobUrl(deltaUrl) {
const client = global.DeltaPatcher.get(deltaUrl);
const deltaBundleId = client.getLastBundleId()
? `&deltaBundleId=${client.getLastBundleId()}`
: '';
const data = await fetch(deltaUrl + deltaBundleId);
const bundle = await data.json();
const deltaPatcher = client.applyDelta({
id: bundle.id,
pre: new Map(bundle.pre),
post: new Map(bundle.post),
delta: new Map(bundle.delta),
reset: bundle.reset,
});
let cachedBundle = cachedBundleUrls.get(deltaUrl);
// If nothing changed, avoid recreating a bundle blob by reusing the
// previous one.
if (deltaPatcher.getLastNumModifiedFiles() === 0 && cachedBundle) {
return cachedBundle;
}
// Clean up the previous bundle URL to not leak memory.
if (cachedBundle) {
URL.revokeObjectURL(cachedBundle);
}
// To make Source Maps work correctly, we need to add a newline between
// modules.
const blobContent = deltaPatcher
.getAllModules()
.map(module => module + '\n');
// Build the blob with the whole JS bundle.
const blob = new Blob(blobContent, {
type: 'application/javascript',
});
const bundleContents = URL.createObjectURL(blob);
cachedBundleUrls.set(deltaUrl, bundleContents);
return bundleContents;
}
global.deltaUrlToBlobUrl = deltaUrlToBlobUrl;
})(window || {});

File diff suppressed because one or more lines are too long

BIN
node_modules/react-native/local-cli/server/util/external/xsel generated vendored Executable file

Binary file not shown.

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
const WebSocket = require('ws');
const parseMessage = require('./messageSocket').parseMessage;
const PROTOCOL_VERSION = 2;
const TARGET_SERVER = 'server';
function getMessageId() {
return `${Date.now()}:${Math.random()}`;
}
class JsPackagerClient {
constructor(url) {
this.ws = new WebSocket(url);
this.msgCallbacks = new Map();
this.openPromise = new Promise((resolve, reject) => {
this.ws.on('error', error => reject(error));
this.ws.on('open', resolve);
});
this.ws.on('message', (data, flags) => {
const message = parseMessage(data, flags.binary);
const msgCallback = this.msgCallbacks.get(message.id);
if (message === undefined || message.id === undefined) {
// gracefully ignore wrong messages or broadcasts
} else if (msgCallback === undefined) {
console.warn(`Response with non-existing message id: '${message.id}'`);
} else {
if (message.error === undefined) {
msgCallback.resolve(message.result);
} else {
msgCallback.reject(message.error);
}
}
});
}
sendRequest(method, target, params) {
return this.openPromise.then(() => new Promise((resolve, reject) => {
const messageId = getMessageId();
this.msgCallbacks.set(messageId, {resolve: resolve, reject: reject});
this.ws.send(
JSON.stringify({
version: PROTOCOL_VERSION,
target: target,
method: method,
id: messageId,
params: params,
}),
error => {
if (error !== undefined) {
this.msgCallbacks.delete(messageId);
reject(error);
}
});
}));
}
sendNotification(method, target, params) {
return this.openPromise.then(() => new Promise((resolve, reject) => {
this.ws.send(
JSON.stringify({
version: PROTOCOL_VERSION,
target: target,
method: method,
params: params,
}),
error => {
if (error !== undefined) {
reject(error);
} else {
resolve();
}
});
}));
}
sendBroadcast(method, params) {
return this.sendNotification(method, undefined, params);
}
getPeers() {
return new Promise((resolve, reject) => {
this.sendRequest('getpeers', TARGET_SERVER, undefined).then(
response => {
if (!response instanceof Map) {
reject('Results received from server are of wrong format:\n' +
JSON.stringify(response));
} else {
resolve(response);
}
},
reject);
});
}
getId() {
return this.sendRequest('getid', TARGET_SERVER, undefined);
}
}
module.exports = JsPackagerClient;

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/
'use strict';
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
* found when Flow v0.54 was deployed. To see the error delete this comment and
* run Flow. */
const opn = require('opn');
const execSync = require('child_process').execSync;
function commandExistsUnixSync (commandName, callback) {
try {
var stdout = execSync('command -v ' + commandName +
' 2>/dev/null' +
' && { echo >&1 \'' + commandName + ' found\'; exit 0; }');
return !!stdout;
} catch (error) {
return false;
}
}
function getChromeAppName(): string {
switch (process.platform) {
case 'darwin':
return 'google chrome';
case 'win32':
return 'chrome';
case 'linux':
if (commandExistsUnixSync('google-chrome')) {
return 'google-chrome';
} else if (commandExistsUnixSync('chromium-browser')) {
return 'chromium-browser';
} else {
return 'chromium';
}
default:
return 'google-chrome';
}
}
function launchChrome(url: string) {
opn(url, {app: [getChromeAppName()]}, function(err) {
if (err) {
console.error('Google Chrome exited with error:', err);
}
});
}
module.exports = launchChrome;

View File

@@ -0,0 +1,200 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var chalk = require('chalk');
var fs = require('fs');
var path = require('path');
var child_process = require('child_process');
const isAbsolutePath = require('absolute-path');
const shellQuote = require('shell-quote');
function isTerminalEditor(editor) {
switch (editor) {
case 'vim':
case 'emacs':
case 'nano':
return true;
}
return false;
}
// Map from full process name to binary that starts the process
// We can't just re-use full process name, because it will spawn a new instance
// of the app every time
var COMMON_EDITORS = {
'/Applications/Atom.app/Contents/MacOS/Atom': 'atom',
'/Applications/Atom Beta.app/Contents/MacOS/Atom Beta':
'/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',
'/Applications/IntelliJ IDEA.app/Contents/MacOS/idea': 'idea',
'/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':
'/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',
'/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':
'/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',
'/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',
'/Applications/WebStorm.app/Contents/MacOS/webstorm': 'webstorm',
};
function addWorkspaceToArgumentsIfExists(args, workspace) {
if (workspace) {
args.unshift(workspace);
}
return args;
}
function getArgumentsForLineNumber(editor, fileName, lineNumber, workspace) {
switch (path.basename(editor)) {
case 'vim':
case 'mvim':
return [fileName, '+' + lineNumber];
case 'atom':
case 'Atom':
case 'Atom Beta':
case 'subl':
case 'sublime':
case 'webstorm':
case 'wstorm':
case 'appcode':
case 'charm':
case 'idea':
return [fileName + ':' + lineNumber];
case 'joe':
case 'emacs':
case 'emacsclient':
return ['+' + lineNumber, fileName];
case 'rmate':
case 'mate':
case 'mine':
return ['--line', lineNumber, fileName];
case 'code':
return addWorkspaceToArgumentsIfExists(['-g', fileName + ':' + lineNumber], workspace);
}
// For all others, drop the lineNumber until we have
// a mapping above, since providing the lineNumber incorrectly
// can result in errors or confusing behavior.
return [fileName];
}
function guessEditor() {
// Explicit config always wins
if (process.env.REACT_EDITOR) {
return shellQuote.parse(process.env.REACT_EDITOR);
}
// Using `ps x` on OSX we can find out which editor is currently running.
// Potentially we could use similar technique for Windows and Linux
if (process.platform === 'darwin') {
try {
var output = child_process.execSync('ps x').toString();
var processNames = Object.keys(COMMON_EDITORS);
for (var i = 0; i < processNames.length; i++) {
var processName = processNames[i];
if (output.indexOf(processName) !== -1) {
return [COMMON_EDITORS[processName]];
}
}
} catch (error) {
// Ignore...
}
}
// Last resort, use old skool env vars
if (process.env.VISUAL) {
return [process.env.VISUAL];
} else if (process.env.EDITOR) {
return [process.env.EDITOR];
}
return [null];
}
function printInstructions(title) {
console.log([
'',
chalk.bgBlue.white.bold(' ' + title + ' '),
' When you see Red Box with stack trace, you can click any ',
' stack frame to jump to the source file. The packager will launch your ',
' editor of choice. It will first look at REACT_EDITOR environment ',
' variable, then at EDITOR. To set it up, you can add something like ',
' export REACT_EDITOR=atom to your ~/.bashrc or ~/.zshrc depending on ',
' which shell you use.',
''
].join('\n'));
}
function transformToAbsolutePathIfNeeded(pathName) {
if (!isAbsolutePath(pathName)) {
pathName = path.resolve(process.cwd(), pathName);
}
return pathName;
}
function findRootForFile(projectRoots, fileName) {
fileName = transformToAbsolutePathIfNeeded(fileName);
return projectRoots.find((root) => {
root = transformToAbsolutePathIfNeeded(root);
return fileName.startsWith(root + path.sep);
});
}
var _childProcess = null;
function launchEditor(fileName, lineNumber, projectRoots) {
if (!fs.existsSync(fileName)) {
return;
}
// Sanitize lineNumber to prevent malicious use on win32
// via: https://github.com/nodejs/node/blob/c3bb4b1aa5e907d489619fb43d233c3336bfc03d/lib/child_process.js#L333
if (lineNumber && isNaN(lineNumber)) {
return;
}
let [editor, ...args] = guessEditor();
if (!editor) {
printInstructions('PRO TIP');
return;
}
var workspace = findRootForFile(projectRoots, fileName);
if (lineNumber) {
args = args.concat(getArgumentsForLineNumber(editor, fileName, lineNumber, workspace));
} else {
args.push(fileName);
}
console.log('Opening ' + chalk.underline(fileName) + ' with ' + chalk.bold(editor));
if (_childProcess && isTerminalEditor(editor)) {
// There's an existing editor process already and it's attached
// to the terminal, so go kill it. Otherwise two separate editor
// instances attach to the stdin/stdout which gets confusing.
_childProcess.kill('SIGKILL');
}
if (process.platform === 'win32') {
// On Windows, launch the editor in a shell because spawn can only
// launch .exe files.
_childProcess = child_process.spawn('cmd.exe', ['/C', editor].concat(args), {stdio: 'inherit'});
} else {
_childProcess = child_process.spawn(editor, args, {stdio: 'inherit'});
}
_childProcess.on('exit', function(errorCode) {
_childProcess = null;
if (errorCode) {
console.log(chalk.red('Your editor exited with an error!'));
printInstructions('Keep these instructions in mind:');
}
});
_childProcess.on('error', function(error) {
console.log(chalk.red(error.message));
printInstructions('How to fix:');
});
}
module.exports = launchEditor;

View File

@@ -0,0 +1,218 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
const url = require('url');
const WebSocketServer = require('ws').Server;
const PROTOCOL_VERSION = 2;
const notifier = require('node-notifier');
function parseMessage(data, binary) {
if (binary) {
console.error('Expected text message, got binary!');
return undefined;
}
try {
const message = JSON.parse(data);
if (message.version === PROTOCOL_VERSION) {
return message;
}
console.error('Received message had wrong protocol version: '
+ message.version);
} catch (e) {
console.error('Failed to parse the message as JSON:\n' + data);
}
return undefined;
}
function isBroadcast(message) {
return (
typeof message.method === 'string' &&
message.id === undefined &&
message.target === undefined
);
}
function isRequest(message) {
return (
typeof message.method === 'string' &&
typeof message.target === 'string');
}
function isResponse(message) {
return (
typeof message.id === 'object' &&
typeof message.id.requestId !== undefined &&
typeof message.id.clientId === 'string' && (
message.result !== undefined ||
message.error !== undefined
));
}
function attachToServer(server, path) {
const wss = new WebSocketServer({
server: server,
path: path
});
const clients = new Map();
let nextClientId = 0;
function getClientWs(clientId) {
const clientWs = clients.get(clientId);
if (clientWs === undefined) {
throw `could not find id "${clientId}" while forwarding request`;
}
return clientWs;
}
function handleSendBroadcast(broadcasterId, message) {
const forwarded = {
version: PROTOCOL_VERSION,
method: message.method,
params: message.params,
};
if (clients.size === 0) {
notifier.notify({
'title': 'React Native: No apps connected',
'message': `Sending '${message.method}' to all React Native apps ` +
'failed. Make sure your app is running in the simulator ' +
'or on a phone connected via USB.'
});
}
for (const [otherId, otherWs] of clients) {
if (otherId !== broadcasterId) {
try {
otherWs.send(JSON.stringify(forwarded));
} catch (e) {
console.error(`Failed to send broadcast to client: '${otherId}' ` +
`due to:\n ${e.toString()}`);
}
}
}
}
wss.on('connection', function(clientWs) {
const clientId = `client#${nextClientId++}`;
function handleCaughtError(message, error) {
const errorMessage = {
id: message.id,
method: message.method,
target: message.target,
error: message.error === undefined ? 'undefined' : 'defined',
params: message.params === undefined ? 'undefined' : 'defined',
result: message.result === undefined ? 'undefined' : 'defined',
};
if (message.id === undefined) {
console.error(
`Handling message from ${clientId} failed with:\n${error}\n` +
`message:\n${JSON.stringify(errorMessage)}`);
} else {
try {
clientWs.send(JSON.stringify({
version: PROTOCOL_VERSION,
error: error,
id: message.id,
}));
} catch (e) {
console.error(`Failed to reply to ${clientId} with error:\n${error}` +
`\nmessage:\n${JSON.stringify(errorMessage)}` +
`\ndue to error: ${e.toString()}`);
}
}
}
function handleServerRequest(message) {
let result = null;
switch (message.method) {
case 'getid':
result = clientId;
break;
case 'getpeers':
result = {};
clients.forEach((otherWs, otherId) => {
if (clientId !== otherId) {
result[otherId] = url.parse(otherWs.upgradeReq.url, true).query;
}
});
break;
default:
throw `unknown method: ${message.method}`;
}
clientWs.send(JSON.stringify({
version: PROTOCOL_VERSION,
result: result,
id: message.id
}));
}
function forwardRequest(message) {
getClientWs(message.target).send(JSON.stringify({
version: PROTOCOL_VERSION,
method: message.method,
params: message.params,
id: (message.id === undefined
? undefined
: {requestId: message.id, clientId: clientId}),
}));
}
function forwardResponse(message) {
getClientWs(message.id.clientId).send(JSON.stringify({
version: PROTOCOL_VERSION,
result: message.result,
error: message.error,
id: message.id.requestId,
}));
}
clients.set(clientId, clientWs);
clientWs.onclose =
clientWs.onerror = () => {
clientWs.onmessage = null;
clients.delete(clientId);
};
clientWs.onmessage = (event) => {
const message = parseMessage(event.data, event.binary);
if (message === undefined) {
console.error('Received message not matching protocol');
return;
}
try {
if (isBroadcast(message)) {
handleSendBroadcast(clientId, message);
} else if (isRequest(message)) {
if (message.target === 'server') {
handleServerRequest(message);
} else {
forwardRequest(message);
}
} else if (isResponse(message)) {
forwardResponse(message);
} else {
throw 'Invalid message, did not match the protocol';
}
} catch (e) {
handleCaughtError(message, e.toString());
}
};
});
return {
broadcast: (method, params) => {
handleSendBroadcast(null, {method: method, params: params});
}
};
}
module.exports = {
attachToServer: attachToServer,
parseMessage: parseMessage,
};

View File

@@ -0,0 +1,75 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
function attachToServer(server, path) {
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({
server: server,
path: path
});
var debuggerSocket, clientSocket;
function send(dest, message) {
if (!dest) {
return;
}
try {
dest.send(message);
} catch (e) {
console.warn(e);
// Sometimes this call throws 'not opened'
}
}
wss.on('connection', function(ws) {
const {url} = ws.upgradeReq;
if (url.indexOf('role=debugger') > -1) {
if (debuggerSocket) {
ws.close(1011, 'Another debugger is already connected');
return;
}
debuggerSocket = ws;
debuggerSocket.onerror =
debuggerSocket.onclose = () => {
debuggerSocket = null;
if (clientSocket) {
clientSocket.close(1011, 'Debugger was disconnected');
}
};
debuggerSocket.onmessage = ({data}) => send(clientSocket, data);
} else if (url.indexOf('role=client') > -1) {
if (clientSocket) {
clientSocket.onerror = clientSocket.onclose = clientSocket.onmessage = null;
clientSocket.close(1011, 'Another client connected');
}
clientSocket = ws;
clientSocket.onerror =
clientSocket.onclose = () => {
clientSocket = null;
send(debuggerSocket, JSON.stringify({method: '$disconnected'}));
};
clientSocket.onmessage = ({data}) => send(debuggerSocket, data);
} else {
ws.close(1011, 'Missing role param');
}
});
return {
server: wss,
isChromeConnected: function() {
return !!debuggerSocket;
}
};
}
module.exports = {
attachToServer: attachToServer
};