-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify occupied port handling in start command (#39078)
Summary: Pull Request resolved: #39078 Simplifies and hardens behaviour for detecting other processes / dev server instances when running `react-native start`. - New flow: - Exits with error message if port is taken by another process (*no longer suggests next port*). - Exits with info message if port is taken by another instance of this dev server (**unchanged**). - Continues if result unknown. - *(No longer logs dedicated message for another RN server running in a different project root.)* - This now checks if the TCP port is in use before attempting an HTTP fetch. Previous behaviour: [`handlePortUnavailable`](https://github.com/react-native-community/cli/blob/734222118707fff41c71463528e4e0c227b31cc6/packages/cli-tools/src/handlePortUnavailable.ts#L8). This decouples us from some lower-level `react-native-community/cli-tools` utils, which remain reused by the `android` and `ios` commands. Changelog: [Internal] Reviewed By: motiz88 Differential Revision: D48433285 fbshipit-source-id: 03cf450824ebd1e1e750f087c060c2f81e0a6851
- Loading branch information
1 parent
53855ee
commit 8fcb34b
Showing
3 changed files
with
107 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
packages/community-cli-plugin/src/utils/isDevServerRunning.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @flow strict-local | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
|
||
import net from 'net'; | ||
import fetch from 'node-fetch'; | ||
|
||
/** | ||
* Determine whether we can run the dev server. | ||
* | ||
* Return values: | ||
* - `not_running`: The port is unoccupied. | ||
* - `matched_server_running`: The port is occupied by another instance of this | ||
* dev server (matching the passed `projectRoot`). | ||
* - `port_taken`: The port is occupied by another process. | ||
* - `unknown`: An error was encountered; attempt server creation anyway. | ||
*/ | ||
export default async function isDevServerRunning( | ||
host: string, | ||
port: number, | ||
projectRoot: string, | ||
): Promise< | ||
'not_running' | 'matched_server_running' | 'port_taken' | 'unknown', | ||
> { | ||
try { | ||
if (!(await isPortOccupied(host, port))) { | ||
return 'not_running'; | ||
} | ||
|
||
const statusResponse = await fetch(`http://localhost:${port}/status`); | ||
const body = await statusResponse.text(); | ||
|
||
return body === 'packager-status:running' && | ||
statusResponse.headers.get('X-React-Native-Project-Root') === projectRoot | ||
? 'matched_server_running' | ||
: 'port_taken'; | ||
} catch (e) { | ||
return 'unknown'; | ||
} | ||
} | ||
|
||
async function isPortOccupied(host: string, port: number): Promise<boolean> { | ||
let result = false; | ||
const server = net.createServer(); | ||
|
||
return new Promise((resolve, reject) => { | ||
server.once('error', e => { | ||
server.close(); | ||
if (e.code === 'EADDRINUSE') { | ||
result = true; | ||
} else { | ||
reject(e); | ||
} | ||
}); | ||
server.once('listening', () => { | ||
result = false; | ||
server.close(); | ||
}); | ||
server.once('close', () => { | ||
resolve(result); | ||
}); | ||
server.listen({host, port}); | ||
}); | ||
} |