diff --git a/desktop/flipper-server/package.json b/desktop/flipper-server/package.json index 3b54ace5d..0bf3714f5 100644 --- a/desktop/flipper-server/package.json +++ b/desktop/flipper-server/package.json @@ -17,12 +17,14 @@ "flipper-pkg-lib": "0.0.0", "flipper-server-companion": "0.0.0", "flipper-server-core": "0.0.0", + "flipper-server-client": "0.0.0", "fs-extra": "^11.1.0", "http-proxy": "^1.18.1", "metro": "^0.70.2", "open": "^8.3.0", "p-filter": "^2.1.0", - "ws": "^8.5.0", + "ws": "8.8.0", + "reconnecting-websocket": "^4.4.0", "xdg-basedir": "^4", "yargs": "^17.6.2" }, diff --git a/desktop/flipper-server/src/index.tsx b/desktop/flipper-server/src/index.tsx index 47d166709..26c25dfea 100644 --- a/desktop/flipper-server/src/index.tsx +++ b/desktop/flipper-server/src/index.tsx @@ -28,6 +28,12 @@ import {isTest} from 'flipper-common'; import exitHook from 'exit-hook'; import {getAuthToken} from 'flipper-server-core'; import {findInstallation} from './findInstallation'; +import ReconnectingWebSocket from 'reconnecting-websocket'; +import { + createFlipperServerWithSocket, + FlipperServerState, +} from 'flipper-server-client'; +import WS from 'ws'; const argv = yargs .usage('yarn flipper-server [args]') @@ -71,6 +77,11 @@ const argv = yargs type: 'boolean', default: true, }, + replace: { + describe: 'Replaces any running instance, if any.', + type: 'boolean', + default: true, + }, }) .version('DEV') .help() @@ -87,6 +98,41 @@ const rootPath = argv.bundler : path.resolve(__dirname, '..'); // in pre packaged versions of the server, static is copied inside the package const staticPath = path.join(rootPath, 'static'); +async function connectToRunningServer(url: URL) { + console.info(`[flipper-server] Obtain connection to existing server.`); + console.info(`[flipper-server] URL: ${url}`); + const options = { + WebSocket: class WSWithUnixDomainSocketSupport extends WS { + constructor(url: string, protocols: string | string[]) { + // Flipper exports could be large, and we snd them over the wire + // Setting this limit fairly high (1GB) to allow any reasonable Flipper export to be loaded + super(url, protocols, {maxPayload: 1024 * 1024 * 1024}); + } + }, + }; + const socket = new ReconnectingWebSocket(url.toString(), [], options); + const server = await createFlipperServerWithSocket( + socket as WebSocket, + (_state: FlipperServerState) => {}, + ); + return server; +} + +async function shutdown() { + console.info('[flipper-server] Attempt to shutdown.'); + + const tokenPath = path.resolve(staticPath, 'auth.token'); + const token = await fs.readFile(tokenPath, 'utf-8'); + + const searchParams = new URLSearchParams({token: token ?? ''}); + const url = new URL(`ws://localhost:${argv.port}?${searchParams}`); + const server = await connectToRunningServer(url); + await server.exec('shutdown').catch(() => { + /** shutdown will ultimately make this request fail, ignore error. */ + console.info('[flipper-server] Shutdown may have succeeded'); + }); +} + async function start() { const enhanceLogger = await initializeLogger(staticPath); @@ -119,8 +165,14 @@ async function start() { ); if (await checkPortInUse(argv.port)) { - console.warn(`[flipper-server] Port ${argv.port} is already in use`); - return; + console.warn(`[flipper-server] Port ${argv.port} is already in use.`); + if (!argv.replace) { + console.info( + `[flipper-server] Not replacing existing instance, exiting.`, + ); + return; + } + await shutdown(); } const {app, server, socket, readyForIncomingConnections} = await startServer({ diff --git a/desktop/flipper-server/tsconfig.json b/desktop/flipper-server/tsconfig.json index 215a4c1f9..1ba68669e 100644 --- a/desktop/flipper-server/tsconfig.json +++ b/desktop/flipper-server/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "lib", "rootDir": "src", - "lib": ["ES2019"], + "lib": ["DOM", "ES2019"], "types": ["../types/flipperGlobals", "../types/metro-resolver", "../types/metro"] }, "include": ["./src/*"], @@ -17,6 +17,9 @@ { "path": "../flipper-server-companion" }, + { + "path": "../flipper-server-client" + }, { "path": "../pkg-lib" } diff --git a/desktop/scripts/build-flipper-server-release.tsx b/desktop/scripts/build-flipper-server-release.tsx index e73e7ec71..bfce3f987 100644 --- a/desktop/scripts/build-flipper-server-release.tsx +++ b/desktop/scripts/build-flipper-server-release.tsx @@ -252,6 +252,7 @@ async function linkLocalDeps(buildFolder: string) { 'flipper-common': `file:${rootDir}/flipper-common`, 'flipper-frontend-core': `file:${rootDir}/flipper-frontend-core`, 'flipper-plugin-core': `file:${rootDir}/flipper-plugin-core`, + 'flipper-server-client': `file:${rootDir}/flipper-server-client`, 'flipper-server-companion': `file:${rootDir}/flipper-server-companion`, 'flipper-server-core': `file:${rootDir}/flipper-server-core`, 'flipper-pkg-lib': `file:${rootDir}/pkg-lib`, diff --git a/desktop/yarn.lock b/desktop/yarn.lock index 3786bb1f2..db7abc294 100644 --- a/desktop/yarn.lock +++ b/desktop/yarn.lock @@ -15434,7 +15434,7 @@ ws@^7.0.0, ws@^7.4.5, ws@^7.5.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== -ws@^8.5.0, ws@^8.6.0: +ws@^8.6.0: version "8.6.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.6.0.tgz#e5e9f1d9e7ff88083d0c0dd8281ea662a42c9c23" integrity sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==