Skip to content

Commit e2ec941

Browse files
authored
fix(rspeedy/core): take the first network found instead of the last one (#457)
<!-- Thank you for submitting a pull request! We appreciate the time and effort you have invested in making these changes. Please ensure that you provide enough information to allow others to review your pull request. Upon submission, your pull request will be automatically assigned with reviewers. If you want to learn more about contributing to this project, please visit: https://github.com/lynx-family/lynx-stack/blob/main/CONTRIBUTING.md. --> ## Summary <!-- Can you explain the reasoning behind implementing this change? What problem or issue does this pull request resolve? --> Following up to #91, port webpack/webpack-dev-server#5411 <!-- It would be helpful if you could provide any relevant context, such as GitHub issues or related discussions. --> ## Checklist <!--- Check and mark with an "x" --> - [x] Tests updated (or not required). - [ ] Documentation updated (or **not required**).
1 parent f628037 commit e2ec941

File tree

4 files changed

+220
-8
lines changed

4 files changed

+220
-8
lines changed

.changeset/real-hounds-tan.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@lynx-js/rspeedy": patch
3+
---
4+
5+
Select the most appropriate network interface.
6+
7+
This is a port of [webpack/webpack-dev-server#5411](https://github.com/webpack/webpack-dev-server/pull/5411).

packages/rspeedy/core/src/plugins/dev.plugin.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export async function findIp(
167167

168168
let host: string | undefined
169169

170-
Object.values(os.networkInterfaces())
170+
const networks = Object.values(os.networkInterfaces())
171171
.flatMap((networks) => networks ?? [])
172172
.filter((network) => {
173173
if (!network || !network.address) {
@@ -192,12 +192,16 @@ export async function findIp(
192192

193193
return network.address
194194
})
195-
.forEach((network) => {
196-
host = network.address
197-
if (host.includes(':')) {
198-
host = `[${host}]`
199-
}
200-
})
195+
196+
if (networks.length > 0) {
197+
// Take the first network found
198+
// See: https://github.com/webpack/webpack-dev-server/pull/5411/
199+
host = networks[0]!.address
200+
201+
if (host.includes(':')) {
202+
host = `[${host}]`
203+
}
204+
}
201205

202206
if (!host) {
203207
throw new Error(`No valid IP found`)

packages/rspeedy/core/test/plugins/dev.plugin.test.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,28 @@ import { assert, beforeEach, describe, expect, test, vi } from 'vitest'
99

1010
import { createStubRspeedy } from '../createStubRspeedy.js'
1111

12+
vi.mock('node:os')
13+
1214
describe('Plugins - Dev', () => {
13-
beforeEach(() => {
15+
beforeEach(async () => {
1416
vi.stubEnv('NODE_ENV', 'development')
1517
vi.mock('../../src/webpack/ProvidePlugin.js')
1618

19+
const { default: os } = await import('node:os')
20+
21+
vi.mocked(os.networkInterfaces).mockReturnValue({
22+
eth0: [
23+
{
24+
address: '192.168.1.1',
25+
family: 'IPv4',
26+
internal: false,
27+
netmask: '255.255.255.0',
28+
mac: '00:00:00:00:00:00',
29+
cidr: '192.168.1.1/24',
30+
},
31+
],
32+
})
33+
1734
return () => {
1835
vi.unstubAllEnvs()
1936
.restoreAllMocks()
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// Copyright 2024 The Lynx Authors. All rights reserved.
2+
// Licensed under the Apache License Version 2.0 that can be found in the
3+
// LICENSE file in the root directory of this source tree.
4+
5+
import { describe, expect, test, vi } from 'vitest'
6+
7+
vi.mock('node:os')
8+
9+
describe('findIp', () => {
10+
test('v4', async () => {
11+
const { default: os } = await import('node:os')
12+
13+
vi.mocked(os.networkInterfaces).mockReturnValue({
14+
eth0: [
15+
{
16+
address: '192.168.1.1',
17+
family: 'IPv4',
18+
internal: false,
19+
netmask: '255.255.255.0',
20+
mac: '00:00:00:00:00:00',
21+
cidr: '192.168.1.1/24',
22+
},
23+
],
24+
})
25+
26+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
27+
28+
const ip = await findIp('v4')
29+
expect(ip).toBe('192.168.1.1')
30+
})
31+
32+
test('v6', async () => {
33+
const { default: os } = await import('node:os')
34+
35+
vi.mocked(os.networkInterfaces).mockReturnValue({
36+
eth0: [
37+
{
38+
address: 'fd00::1',
39+
family: 'IPv6',
40+
internal: false,
41+
netmask: 'ffff:ffff:ffff:ffff::',
42+
mac: '00:00:00:00:00:00',
43+
cidr: 'fd00::1/64',
44+
scopeid: 0,
45+
},
46+
],
47+
})
48+
49+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
50+
51+
const ip = await findIp('v6')
52+
expect(ip).toBe('[fd00::1]')
53+
})
54+
55+
test('multiple ips (should use the first ip)', async () => {
56+
const { default: os } = await import('node:os')
57+
58+
vi.mocked(os.networkInterfaces).mockReturnValue({
59+
eth0: [
60+
{
61+
address: '192.168.1.1',
62+
family: 'IPv4',
63+
internal: false,
64+
netmask: '255.255.255.0',
65+
mac: '00:00:00:00:00:00',
66+
cidr: '192.168.1.1/24',
67+
},
68+
{
69+
address: '192.168.2.1',
70+
family: 'IPv4',
71+
internal: false,
72+
netmask: '255.255.255.0',
73+
mac: '00:00:00:00:00:00',
74+
cidr: '192.168.2.1/24',
75+
},
76+
],
77+
})
78+
79+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
80+
81+
const ip = await findIp('v4')
82+
expect(ip).toBe('192.168.1.1') // should use the first ip
83+
})
84+
85+
test('multiple ips (should ignore internal ips)', async () => {
86+
const { default: os } = await import('node:os')
87+
88+
vi.mocked(os.networkInterfaces).mockReturnValue({
89+
eth0: [
90+
{
91+
address: '192.168.2.1',
92+
family: 'IPv4',
93+
internal: true,
94+
netmask: '255.255.255.0',
95+
mac: '00:00:00:00:00:00',
96+
cidr: '192.168.2.1/24',
97+
},
98+
{
99+
address: '192.168.1.1',
100+
family: 'IPv4',
101+
internal: false,
102+
netmask: '255.255.255.0',
103+
mac: '00:00:00:00:00:00',
104+
cidr: '192.168.1.1/24',
105+
},
106+
],
107+
})
108+
109+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
110+
111+
const ip = await findIp('v4')
112+
expect(ip).toBe('192.168.1.1') // should ignore internal ips
113+
})
114+
115+
test('no v4 ips', async () => {
116+
const { default: os } = await import('node:os')
117+
118+
vi.mocked(os.networkInterfaces).mockReturnValue({
119+
eth0: [
120+
{
121+
address: 'fd00::1',
122+
family: 'IPv6',
123+
internal: false,
124+
netmask: 'ffff:ffff:ffff:ffff::',
125+
mac: '00:00:00:00:00:00',
126+
cidr: 'fd00::1/64',
127+
scopeid: 0,
128+
},
129+
],
130+
})
131+
132+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
133+
134+
await expect(findIp('v4')).rejects.toThrow(
135+
'No valid IP found',
136+
)
137+
})
138+
139+
test('no ips', async () => {
140+
const { default: os } = await import('node:os')
141+
142+
vi.mocked(os.networkInterfaces).mockReturnValue({})
143+
144+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
145+
146+
await expect(findIp('v4')).rejects.toThrow(
147+
'No valid IP found',
148+
)
149+
})
150+
151+
test('invalid network interfaces', async () => {
152+
const { default: os } = await import('node:os')
153+
154+
vi.mocked(os.networkInterfaces).mockReturnValue({
155+
// @ts-expect-error mocked invalid network interfaces
156+
eth0: null,
157+
})
158+
159+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
160+
161+
await expect(findIp('v4')).rejects.toThrow(
162+
'No valid IP found',
163+
)
164+
})
165+
166+
test('invalid ip address', async () => {
167+
const { default: os } = await import('node:os')
168+
169+
vi.mocked(os.networkInterfaces).mockReturnValue({
170+
eth0: [
171+
{
172+
// @ts-expect-error invalid ip address
173+
address: null,
174+
},
175+
],
176+
})
177+
178+
const { findIp } = await import('../../src/plugins/dev.plugin.js')
179+
180+
await expect(findIp('v4')).rejects.toThrow(
181+
'No valid IP found',
182+
)
183+
})
184+
})

0 commit comments

Comments
 (0)