Skip to content

Commit 570cd57

Browse files
authored
Merge pull request #3000 from remotion-dev/port-selection
2 parents d6b0a87 + 50b1424 commit 570cd57

4 files changed

Lines changed: 95 additions & 19 deletions

File tree

packages/cli/src/preview-server/start-server.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,24 @@ export const startServer = async (options: {
109109
undefined;
110110

111111
const maxTries = 5;
112+
113+
// Default Node.js host, but explicity
114+
const host = '0.0.0.0';
115+
112116
for (let i = 0; i < maxTries; i++) {
113117
try {
114118
const selectedPort = await new Promise<number>((resolve, reject) => {
115-
RenderInternals.getDesiredPort(desiredPort, 3000, 3100)
119+
RenderInternals.getDesiredPort({
120+
desiredPort,
121+
from: 3000,
122+
to: 3100,
123+
hostsToTry: ['127.0.0.1', '0.0.0.0'],
124+
})
116125
.then(({port, didUsePort}) => {
117-
server.listen(port);
126+
server.listen({
127+
port,
128+
host,
129+
});
118130
server.on('listening', () => {
119131
resolve(port);
120132
return didUsePort();

packages/renderer/src/get-port.ts

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import net from 'net';
22
import {createLock} from './locks';
33

4-
const getAvailablePort = (portToTry: number) =>
5-
new Promise<'available' | 'unavailable'>((resolve) => {
6-
let status: 'available' | 'unavailable' = 'unavailable';
4+
type PortStatus = 'available' | 'unavailable';
5+
6+
const isPortAvailableOnHost = ({
7+
portToTry,
8+
host,
9+
}: {
10+
portToTry: number;
11+
host: string;
12+
}): Promise<PortStatus> => {
13+
return new Promise<PortStatus>((resolve) => {
14+
let status: PortStatus = 'unavailable';
715

8-
const host = '127.0.0.1';
916
const socket = new net.Socket();
1017

1118
socket.on('connect', () => {
@@ -28,12 +35,42 @@ const getAvailablePort = (portToTry: number) =>
2835

2936
socket.connect(portToTry, host);
3037
});
38+
};
39+
40+
export const testPortAvailableOnMultipleHosts = async ({
41+
hosts,
42+
port,
43+
}: {
44+
port: number;
45+
hosts: string[];
46+
}): Promise<PortStatus> => {
47+
const results = await Promise.all(
48+
hosts.map((host) => {
49+
return isPortAvailableOnHost({portToTry: port, host});
50+
}),
51+
);
52+
53+
return results.every((r) => r === 'available') ? 'available' : 'unavailable';
54+
};
3155

32-
const getPort = async (from: number, to: number) => {
56+
const getPort = async ({
57+
from,
58+
to,
59+
hostsToTest,
60+
}: {
61+
from: number;
62+
to: number;
63+
hostsToTest: string[];
64+
}) => {
3365
const ports = makeRange(from, to);
3466

3567
for (const port of ports) {
36-
if ((await getAvailablePort(port)) === 'available') {
68+
if (
69+
(await testPortAvailableOnMultipleHosts({
70+
port,
71+
hosts: hostsToTest,
72+
})) === 'available'
73+
) {
3774
return port;
3875
}
3976
}
@@ -43,22 +80,31 @@ const getPort = async (from: number, to: number) => {
4380

4481
const portLocks = createLock({timeout: 10000});
4582

46-
export const getDesiredPort = async (
47-
desiredPort: number | undefined,
48-
from: number,
49-
to: number,
50-
) => {
83+
export const getDesiredPort = async ({
84+
desiredPort,
85+
from,
86+
hostsToTry,
87+
to,
88+
}: {
89+
desiredPort: number | undefined;
90+
from: number;
91+
to: number;
92+
hostsToTry: string[];
93+
}) => {
5194
await portLocks.waitForAllToBeDone();
5295
const lockPortSelection = portLocks.lock();
5396
const didUsePort = () => portLocks.unlock(lockPortSelection);
5497
if (
5598
typeof desiredPort !== 'undefined' &&
56-
(await getAvailablePort(desiredPort)) === 'available'
99+
(await testPortAvailableOnMultipleHosts({
100+
port: desiredPort,
101+
hosts: ['0.0.0.0', '127.0.0.1'],
102+
})) === 'available'
57103
) {
58104
return {port: desiredPort, didUsePort};
59105
}
60106

61-
const actualPort = await getPort(from, to);
107+
const actualPort = await getPort({from, to, hostsToTest: hostsToTry});
62108

63109
// If did specify a port but did not get that one, fail hard.
64110
if (desiredPort && desiredPort !== actualPort) {

packages/renderer/src/serve-static.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,20 @@ export const serveStatic = async (
7070
let selectedPort: number | null = null;
7171

7272
const maxTries = 5;
73+
74+
// Default Node.js host, but explicity
75+
const host = '0.0.0.0';
7376
for (let i = 0; i < maxTries; i++) {
7477
try {
7578
selectedPort = await new Promise<number>((resolve, reject) => {
76-
getDesiredPort(options?.port ?? undefined, 3000, 3100)
79+
getDesiredPort({
80+
desiredPort: options?.port ?? undefined,
81+
from: 3000,
82+
to: 3100,
83+
hostsToTry: ['0.0.0.0', '127.0.0.1'],
84+
})
7785
.then(({port, didUsePort}) => {
78-
server.listen(port);
86+
server.listen({port, host});
7987
server.on('listening', () => {
8088
resolve(port);
8189
return didUsePort();

packages/renderer/src/test/port-selection.test.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,18 @@ import {getDesiredPort} from '../get-port';
44
test('Port selection should only be freed once the previous result has been used', async () => {
55
let ports = 0;
66

7-
const {port, didUsePort} = await getDesiredPort(undefined, 3100, 3200);
8-
const secondPort = getDesiredPort(port, 3100, 3200).then(() => ports++);
7+
const {port, didUsePort} = await getDesiredPort({
8+
desiredPort: undefined,
9+
from: 3100,
10+
to: 3200,
11+
hostsToTry: ['0.0.0.0', '127.0.0.1'],
12+
});
13+
const secondPort = getDesiredPort({
14+
desiredPort: port,
15+
from: 3100,
16+
to: 3200,
17+
hostsToTry: ['0.0.0.0', '127.0.0.1'],
18+
}).then(() => ports++);
919

1020
await new Promise<void>((resolve) => {
1121
setTimeout(resolve, 2000);

0 commit comments

Comments
 (0)