diff --git a/packages/cli-plugin-metro/src/commands/start/runServer.ts b/packages/cli-plugin-metro/src/commands/start/runServer.ts index 11d554374..063778e0c 100644 --- a/packages/cli-plugin-metro/src/commands/start/runServer.ts +++ b/packages/cli-plugin-metro/src/commands/start/runServer.ts @@ -70,7 +70,12 @@ async function runServer(_argv: Array, ctx: Config, args: Args) { ); } - const {middleware, attachToServer} = createDevServerMiddleware({ + const { + middleware, + websocketEndpoints, + messageSocketEndpoint, + eventsSocketEndpoint, + } = createDevServerMiddleware({ host: args.host, port: metroConfig.server.port, watchFolders: metroConfig.watchFolders, @@ -94,14 +99,13 @@ async function runServer(_argv: Array, ctx: Config, args: Args) { secureCert: args.cert, secureKey: args.key, hmrEnabled: true, + websocketEndpoints, }); - const {messageSocket, eventsSocket} = attachToServer(serverInstance); - - reportEvent = eventsSocket.reportEvent; + reportEvent = eventsSocketEndpoint.reportEvent; if (args.interactive) { - enableWatchMode(messageSocket); + enableWatchMode(messageSocketEndpoint); } // In Node 8, the default keep-alive for an HTTP connection is 5 seconds. In diff --git a/packages/cli-server-api/package.json b/packages/cli-server-api/package.json index 6abf8cdd5..4d1365911 100644 --- a/packages/cli-server-api/package.json +++ b/packages/cli-server-api/package.json @@ -15,13 +15,13 @@ "nocache": "^3.0.1", "pretty-format": "^26.6.2", "serve-static": "^1.13.1", - "ws": "^1.1.0" + "ws": "^7.5.1" }, "devDependencies": { "@types/compression": "^1.0.1", "@types/connect": "^3.4.33", "@types/errorhandler": "^0.0.32", - "@types/ws": "^6.0.3" + "@types/ws": "^7.4.7" }, "files": [ "build", diff --git a/packages/cli-server-api/src/index.ts b/packages/cli-server-api/src/index.ts index 038479bc4..fc100faa5 100644 --- a/packages/cli-server-api/src/index.ts +++ b/packages/cli-server-api/src/index.ts @@ -1,5 +1,4 @@ -import http, {Server as HttpServer} from 'http'; -import {Server as HttpsServer} from 'https'; +import http from 'http'; import compression from 'compression'; import connect from 'connect'; @@ -17,9 +16,9 @@ import securityHeadersMiddleware from './securityHeadersMiddleware'; import statusPageMiddleware from './statusPageMiddleware'; import systraceProfileMiddleware from './systraceProfileMiddleware'; -import debuggerProxyServer from './websocket/debuggerProxyServer'; -import eventsSocketServer from './websocket/eventsSocketServer'; -import messageSocketServer from './websocket/messageSocketServer'; +import createDebuggerProxyEndpoint from './websocket/createDebuggerProxyEndpoint'; +import createMessageSocketEndpoint from './websocket/createMessageSocketEndpoint'; +import createEventsSocketEndpoint from './websocket/createEventsSocketEndpoint'; export {devToolsMiddleware}; export {indexPageMiddleware}; @@ -30,10 +29,6 @@ export {securityHeadersMiddleware}; export {statusPageMiddleware}; export {systraceProfileMiddleware}; -export {debuggerProxyServer}; -export {eventsSocketServer}; -export {messageSocketServer}; - type MiddlewareOptions = { host?: string; watchFolders: ReadonlyArray; @@ -41,8 +36,13 @@ type MiddlewareOptions = { }; export function createDevServerMiddleware(options: MiddlewareOptions) { - let isDebuggerConnected = () => false; - let broadcast = (_event: any) => {}; + const debuggerProxyEndpoint = createDebuggerProxyEndpoint(); + const isDebuggerConnected = debuggerProxyEndpoint.isDebuggerConnected; + + const messageSocketEndpoint = createMessageSocketEndpoint(); + const broadcast = messageSocketEndpoint.broadcast; + + const eventsSocketEndpoint = createEventsSocketEndpoint(broadcast); const middleware = connect() .use(securityHeadersMiddleware) @@ -52,7 +52,7 @@ export function createDevServerMiddleware(options: MiddlewareOptions) { .use('/debugger-ui', debuggerUIMiddleware()) .use( '/launch-js-devtools', - devToolsMiddleware(options, () => isDebuggerConnected()), + devToolsMiddleware(options, isDebuggerConnected), ) .use('/open-stack-frame', openStackFrameInEditorMiddleware(options)) .use('/open-url', openURLMiddleware) @@ -71,28 +71,14 @@ export function createDevServerMiddleware(options: MiddlewareOptions) { }); return { - attachToServer(server: HttpServer | HttpsServer) { - const debuggerProxy = debuggerProxyServer.attachToServer( - server, - '/debugger-proxy', - ); - const messageSocket = messageSocketServer.attachToServer( - server, - '/message', - ); - broadcast = messageSocket.broadcast; - isDebuggerConnected = debuggerProxy.isDebuggerConnected; - const eventsSocket = eventsSocketServer.attachToServer( - server, - '/events', - messageSocket, - ); - return { - debuggerProxy, - eventsSocket, - messageSocket, - }; + websocketEndpoints: { + '/debugger-proxy': debuggerProxyEndpoint.server, + '/message': messageSocketEndpoint.server, + '/events': eventsSocketEndpoint.server, }, + debuggerProxyEndpoint, + messageSocketEndpoint, + eventsSocketEndpoint, middleware, }; } diff --git a/packages/cli-server-api/src/websocket/debuggerProxyServer.ts b/packages/cli-server-api/src/websocket/createDebuggerProxyEndpoint.ts similarity index 61% rename from packages/cli-server-api/src/websocket/debuggerProxyServer.ts rename to packages/cli-server-api/src/websocket/createDebuggerProxyEndpoint.ts index a182b3532..0b9db16f7 100644 --- a/packages/cli-server-api/src/websocket/debuggerProxyServer.ts +++ b/packages/cli-server-api/src/websocket/createDebuggerProxyEndpoint.ts @@ -9,15 +9,14 @@ import ws from 'ws'; import {logger} from '@react-native-community/cli-tools'; -import {Server as HttpServer} from 'http'; -import {Server as HttpsServer} from 'https'; -type Server = HttpServer | HttpsServer; -function attachToServer(server: Server, path: string) { +export default function createDebuggerProxyEndpoint(): { + server: ws.Server; + isDebuggerConnected: () => boolean; +} { const WebSocketServer = ws.Server; const wss = new WebSocketServer({ - server, - path, + noServer: true, }); let debuggerSocket: ws | null; @@ -48,37 +47,33 @@ function attachToServer(server: Server, path: string) { send(debuggerSocket, JSON.stringify({method: '$disconnected'})); }; - wss.on('connection', (connection: ws) => { - // @ts-ignore current definition of ws does not have upgradeReq type - const {url} = connection.upgradeReq; + wss.on('connection', (socket, request) => { + const {url} = request; - if (url.indexOf('role=debugger') > -1) { + if (url && url.indexOf('role=debugger') > -1) { if (debuggerSocket) { - connection.close(1011, 'Another debugger is already connected'); + socket.close(1011, 'Another debugger is already connected'); return; } - debuggerSocket = connection; + debuggerSocket = socket; if (debuggerSocket) { debuggerSocket.onerror = debuggerSocketCloseHandler; debuggerSocket.onclose = debuggerSocketCloseHandler; debuggerSocket.onmessage = ({data}) => send(clientSocket, data); } - } else if (url.indexOf('role=client') > -1) { + } else if (url && url.indexOf('role=client') > -1) { if (clientSocket) { - // @ts-ignore not nullable with current type definition of ws - clientSocket.onerror = null; - // @ts-ignore not nullable with current type definition of ws - clientSocket.onclose = null; - // @ts-ignore not nullable with current type definition of ws - clientSocket.onmessage = null; + clientSocket.onerror = () => {}; + clientSocket.onclose = () => {}; + clientSocket.onmessage = () => {}; clientSocket.close(1011, 'Another client connected'); } - clientSocket = connection; + clientSocket = socket; clientSocket.onerror = clientSocketCloseHandler; clientSocket.onclose = clientSocketCloseHandler; clientSocket.onmessage = ({data}) => send(debuggerSocket, data); } else { - connection.close(1011, 'Missing role param'); + socket.close(1011, 'Missing role param'); } }); @@ -89,7 +84,3 @@ function attachToServer(server: Server, path: string) { }, }; } - -export default { - attachToServer, -}; diff --git a/packages/cli-server-api/src/websocket/eventsSocketServer.ts b/packages/cli-server-api/src/websocket/createEventsSocketEndpoint.ts similarity index 89% rename from packages/cli-server-api/src/websocket/eventsSocketServer.ts rename to packages/cli-server-api/src/websocket/createEventsSocketEndpoint.ts index 77c8559d7..950a113b9 100644 --- a/packages/cli-server-api/src/websocket/eventsSocketServer.ts +++ b/packages/cli-server-api/src/websocket/createEventsSocketEndpoint.ts @@ -1,9 +1,6 @@ import {Server as WebSocketServer} from 'ws'; import {logger} from '@react-native-community/cli-tools'; import prettyFormat from 'pretty-format'; -import {Server as HttpServer} from 'http'; -import {Server as HttpsServer} from 'https'; -import messageSocketModule from './messageSocketServer'; /** * The eventsSocket websocket listens at the 'events/` for websocket @@ -21,8 +18,6 @@ import messageSocketModule from './messageSocketServer'; * Two useful commands are 'reload' and 'devmenu'. */ -type Server = HttpServer | HttpsServer; - type Command = { version: number; type: 'command'; @@ -105,23 +100,18 @@ function serializeMessage(message: any) { } } -type MessageSocket = ReturnType; - /** * 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: Server, - path: string, - messageSocket: MessageSocket, -) { +export default function createEventsSocketEndpoint( + broadcast: (method: string, params?: Record) => void, +): { + server: WebSocketServer; + reportEvent: (event: any) => void; +} { const wss = new WebSocketServer({ - server: server, - path: path, + noServer: true, verifyClient({origin}: {origin: string}) { // 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 @@ -186,7 +176,7 @@ function attachToServer( * 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); + broadcast(message.command, message.params); } catch (e) { logger.error('Failed to forward message to clients: ', e); } @@ -197,12 +187,9 @@ function attachToServer( }); return { + server: wss, reportEvent: (event: any) => { broadCastEvent(event); }, }; } - -export default { - attachToServer, -}; diff --git a/packages/cli-server-api/src/websocket/messageSocketServer.ts b/packages/cli-server-api/src/websocket/createMessageSocketEndpoint.ts similarity index 95% rename from packages/cli-server-api/src/websocket/messageSocketServer.ts rename to packages/cli-server-api/src/websocket/createMessageSocketEndpoint.ts index ba7658f24..7430d5a55 100644 --- a/packages/cli-server-api/src/websocket/messageSocketServer.ts +++ b/packages/cli-server-api/src/websocket/createMessageSocketEndpoint.ts @@ -8,8 +8,6 @@ import url from 'url'; import {Server as WebSocketServer} from 'ws'; import {logger} from '@react-native-community/cli-tools'; -import {Server as HttpServer} from 'http'; -import {Server as HttpsServer} from 'https'; const PROTOCOL_VERSION = 2; @@ -70,11 +68,12 @@ function isResponse(message: Message) { ); } -type Server = HttpServer | HttpsServer; -function attachToServer(server: Server, path: string) { +export default function createMessageSocketEndpoint(): { + server: WebSocketServer; + broadcast: (method: string, params?: Record) => void; +} { const wss = new WebSocketServer({ - server, - path, + noServer: true, }); const clients = new Map(); let nextClientId = 0; @@ -211,8 +210,7 @@ function attachToServer(server: Server, path: string) { clients.set(clientId, clientWs); const onCloseHandler = () => { - // @ts-ignore - clientWs.onmessage = null; + clientWs.onmessage = () => {}; clients.delete(clientId); }; clientWs.onclose = onCloseHandler; @@ -245,10 +243,9 @@ function attachToServer(server: Server, path: string) { }); return { + server: wss, broadcast: (method: string, params?: Record) => { handleSendBroadcast(null, {method, params}); }, }; } - -export default {attachToServer, parseMessage}; diff --git a/packages/debugger-ui/src/ui/index.js b/packages/debugger-ui/src/ui/index.js index 93beae395..b8d1e93c5 100644 --- a/packages/debugger-ui/src/ui/index.js +++ b/packages/debugger-ui/src/ui/index.js @@ -49,7 +49,7 @@ const Page = (window.Page = { const statusNode = document.getElementById('status'); switch (status.type) { case 'connected': - statusNode.innerHTML = 'Debugger session #' + status.id + ' active.'; + statusNode.innerHTML = 'Debugger session active.'; break; case 'error': statusNode.innerHTML = diff --git a/yarn.lock b/yarn.lock index 2e1722318..d026db245 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2536,10 +2536,10 @@ resolved "https://registry.yarnpkg.com/@types/wcwidth/-/wcwidth-1.0.0.tgz#a58f4673050f98c46ae8f852340889343b21a1f5" integrity sha512-X/WFfwGCIisEnd9EOSsX/jt7BHPDkcvQVYwVzc1nsE2K5bC56mWKnmNs0wyjcGcQsP7Wxq2zWSmhDDbF5Z7dDg== -"@types/ws@^6.0.3": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.4.tgz#7797707c8acce8f76d8c34b370d4645b70421ff1" - integrity sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg== +"@types/ws@^7.4.7": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== dependencies: "@types/node" "*" @@ -8961,11 +8961,6 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - integrity sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= - ora@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" @@ -9409,17 +9404,7 @@ pkg-up@^2.0.0: dependencies: find-up "^2.1.0" -pkginfo@0.3.x: - version "0.3.1" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" - integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= - -pkginfo@0.x.x: - version "0.4.1" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.1.tgz#b5418ef0439de5425fc4995042dced14fb2a84ff" - integrity sha1-tUGO8EOd5UJfxJlQQtztFPsqhP8= - -plist@^3.0.1, plist@^3.0.2: +plist@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.2.tgz#74bbf011124b90421c22d15779cee60060ba95bc" integrity sha512-MSrkwZBdQ6YapHy87/8hDU8MnIcyxBKjeF+McXnr5A9MtffPewTs7G3hlpodT5TacyfIyFTaJEhh3GGcmasTgQ== @@ -11663,11 +11648,6 @@ uid-number@0.0.6: resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" - integrity sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= - umask@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" @@ -12171,14 +12151,6 @@ write-pkg@^4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^1.1.0: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" - integrity sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w== - dependencies: - options ">=0.0.5" - ultron "1.0.x" - ws@^5.1.1: version "5.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"