Skip to content

Commit de8a36e

Browse files
committed
refactor(network): move network utils to cli-framework
1 parent a5d98c4 commit de8a36e

File tree

9 files changed

+37
-51
lines changed

9 files changed

+37
-51
lines changed

packages/@ionic/cli-framework/src/definitions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import * as os from 'os';
2+
13
import * as minimistType from 'minimist';
24
import { Chalk } from 'chalk';
35

46
import { AliasedMap } from './utils/object';
57

8+
export type NetworkInterface = { device: string; } & os.NetworkInterfaceInfo;
9+
610
export interface Colors {
711
/**
812
* Used to mark text as important. Comparable to HTML's <strong>.

packages/@ionic/cli-utils/src/lib/utils/__tests__/network.ts renamed to packages/@ionic/cli-framework/src/utils/__tests__/network.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import * as osSpy from 'os';
2-
import { getSuitableNetworkInterfaces } from '../network';
2+
import { getExternalIPv4Interfaces } from '../network';
33

4-
describe('@ionic/cli-utils', () => {
4+
describe('@ionic/cli-framework', () => {
55

6-
describe('lib/utils/network', () => {
6+
describe('utils/network', () => {
77

8-
describe('getSuitableNetworkInterfaces', () => {
8+
describe('getExternalIPv4Interfaces', () => {
99

1010
const networkInterfaces1 = {};
1111

@@ -30,21 +30,21 @@ describe('@ionic/cli-utils', () => {
3030

3131
it('should return empty array if no network interfaces', () => {
3232
spyOn(osSpy, 'networkInterfaces').and.callFake(() => networkInterfaces1);
33-
const result = getSuitableNetworkInterfaces();
33+
const result = getExternalIPv4Interfaces();
3434
expect(result).toEqual([]);
3535
});
3636

3737
it('should return empty array if unsuitable network interfaces found', () => {
3838
spyOn(osSpy, 'networkInterfaces').and.callFake(() => networkInterfaces2);
39-
const result = getSuitableNetworkInterfaces();
39+
const result = getExternalIPv4Interfaces();
4040
expect(result).toEqual([]);
4141
});
4242

4343
it('should find the suitable network interface', () => {
4444
spyOn(osSpy, 'networkInterfaces').and.callFake(() => networkInterfaces3);
45-
const result = getSuitableNetworkInterfaces();
45+
const result = getExternalIPv4Interfaces();
4646
expect(result.length).toEqual(1);
47-
expect(result[0].deviceName).toEqual('eth0');
47+
expect(result[0].device).toEqual('eth0');
4848
});
4949

5050
});

packages/@ionic/cli-utils/src/lib/utils/network.ts renamed to packages/@ionic/cli-framework/src/utils/network.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
import * as os from 'os';
22
import * as net from 'net';
33

4-
import { NetworkInterface } from '../../definitions';
4+
import { NetworkInterface } from '../definitions';
55

66
export const ERROR_NETWORK_ADDRESS_NOT_AVAIL = 'NETWORK_ADDRESS_NOT_AVAIL';
77

8-
export function getSuitableNetworkInterfaces(): NetworkInterface[] {
8+
export function getExternalIPv4Interfaces(): NetworkInterface[] {
99
const networkInterfaces = os.networkInterfaces();
1010
const devices: NetworkInterface[] = [];
1111

12-
for (const deviceName of Object.keys(networkInterfaces)) {
13-
const networkInterface = networkInterfaces[deviceName];
12+
for (const device of Object.keys(networkInterfaces)) {
13+
const networkInterface = networkInterfaces[device];
1414

1515
for (const networkAddress of networkInterface) {
1616
if (!networkAddress.internal && networkAddress.family === 'IPv4') {
17-
devices.push({ deviceName, ...networkAddress });
17+
devices.push({ device, ...networkAddress });
1818
}
1919
}
2020
}
@@ -35,8 +35,6 @@ export async function findClosestOpenPort(port: number, host?: string): Promise<
3535
}
3636

3737
export async function isPortAvailable(port: number, host?: string): Promise<boolean> {
38-
const net = await import('net');
39-
4038
return new Promise<boolean>((resolve, reject) => {
4139
const tester = net.createServer()
4240
.once('error', (err: any) => {

packages/@ionic/cli-utils/src/definitions.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import * as fs from 'fs';
2-
import * as os from 'os';
32

43
import * as crossSpawnType from 'cross-spawn';
54
import * as inquirerType from 'inquirer';
@@ -645,7 +644,7 @@ export interface ServeDetails {
645644
localAddress: string;
646645
externalAddress: string;
647646
port: number;
648-
externalNetworkInterfaces: NetworkInterface[];
647+
externalNetworkInterfaces: framework.NetworkInterface[];
649648
externallyAccessible: boolean;
650649
}
651650

@@ -836,8 +835,6 @@ export interface ResolvedStarterTemplate extends StarterTemplate {
836835
archive: string;
837836
}
838837

839-
export type NetworkInterface = { deviceName: string; } & os.NetworkInterfaceInfo;
840-
841838
export interface IPCMessage {
842839
type: 'telemetry';
843840
data: { command: string; args: string[]; };

packages/@ionic/cli-utils/src/lib/project/angular/serve.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as split2 from 'split2';
99
import { ParsedArgs, unparseArgs } from '@ionic/cli-framework';
1010
import { onBeforeExit } from '@ionic/cli-framework/utils/process';
1111
import { pathAccessible } from '@ionic/cli-framework/utils/fs';
12+
import { findClosestOpenPort, isHostConnectable } from '@ionic/cli-framework/utils/network';
1213

1314
import { AngularServeOptions, CommandLineInputs, CommandLineOptions, CommandMetadata, ServeDetails } from '../../../definitions';
1415
import { OptionGroup } from '../../../constants';
@@ -97,13 +98,9 @@ ${chalk.cyan('[2]')}: ${chalk.bold('https://github.com/angular/angular-cli/wiki/
9798
}
9899

99100
async serveProject(options: AngularServeOptions): Promise<ServeDetails> {
100-
const { findClosestOpenPort, isHostConnectable } = await import('../../utils/network');
101101
const [ externalIP, availableInterfaces ] = await this.selectExternalIP(options);
102102

103-
debug('finding closest port to %d', options.port);
104-
const ngPort = await findClosestOpenPort(options.port, '0.0.0.0');
105-
options.port = ngPort;
106-
103+
const ngPort = options.port = await findClosestOpenPort(options.port, '0.0.0.0');
107104
const { program } = await this.serveCommandWrapper(options);
108105

109106
debug('waiting for connectivity with ng serve (%dms timeout)', NG_SERVE_CONNECTIVITY_TIMEOUT);

packages/@ionic/cli-utils/src/lib/project/common.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import chalk from 'chalk';
22
import * as Debug from 'debug';
3+
import { ERROR_NETWORK_ADDRESS_NOT_AVAIL, findClosestOpenPort } from '@ionic/cli-framework/utils/network';
34

45
import { FatalException } from '../errors';
56

@@ -18,8 +19,6 @@ export interface Ports {
1819
* "dev logger" server.
1920
*/
2021
export async function findOpenIonicPorts(address: string, ports: Ports): Promise<Ports> {
21-
const { ERROR_NETWORK_ADDRESS_NOT_AVAIL, findClosestOpenPort } = await import('../utils/network');
22-
2322
try {
2423
const [ port, livereloadPort, notificationPort ] = await Promise.all([
2524
findClosestOpenPort(ports.port, '0.0.0.0'),

packages/@ionic/cli-utils/src/lib/project/ionic-angular/serve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as split2 from 'split2';
66
import { ParsedArgs, unparseArgs } from '@ionic/cli-framework';
77
import { onBeforeExit } from '@ionic/cli-framework/utils/process';
88
import { str2num } from '@ionic/cli-framework/utils/string';
9+
import { isHostConnectable } from '@ionic/cli-framework/utils/network';
910

1011
import { CommandLineInputs, CommandLineOptions, CommandMetadata, IonicAngularServeOptions, ServeDetails } from '../../../definitions';
1112
import { OptionGroup } from '../../../constants';
@@ -76,7 +77,6 @@ export class ServeRunner extends BaseServeRunner<IonicAngularServeOptions> {
7677
}
7778

7879
async serveProject(options: IonicAngularServeOptions): Promise<ServeDetails> {
79-
const { isHostConnectable } = await import('../../utils/network');
8080
const [ externalIP, availableInterfaces ] = await this.selectExternalIP(options);
8181
const { port, livereloadPort, notificationPort } = await findOpenIonicPorts(options.address, options);
8282

packages/@ionic/cli-utils/src/lib/project/ionic1/serve.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import * as proxyMiddlewareType from 'http-proxy-middleware'; // tslint:disable-
99

1010
import { onBeforeExit } from '@ionic/cli-framework/utils/process';
1111
import { str2num } from '@ionic/cli-framework/utils/string';
12+
import { isHostConnectable } from '@ionic/cli-framework/utils/network';
1213

1314
import { CommandLineInputs, CommandLineOptions, CommandMetadata, Ionic1ServeOptions, ProjectFileProxy, ServeDetails } from '../../../definitions';
1415
import { OptionGroup } from '../../../constants';
@@ -108,7 +109,6 @@ export class ServeRunner extends BaseServeRunner<Ionic1ServeOptions> {
108109
}
109110

110111
async serveProject(options: Ionic1ServeOptions): Promise<ServeDetails> {
111-
const { isHostConnectable } = await import('../../utils/network');
112112
const [ externalIP, availableInterfaces ] = await this.selectExternalIP(options);
113113
const { port, livereloadPort, notificationPort } = await findOpenIonicPorts(options.address, options);
114114

packages/@ionic/cli-utils/src/lib/serve.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import * as lodash from 'lodash';
77
import * as through2 from 'through2';
88
import * as split2 from 'split2';
99

10+
import { NetworkInterface } from '@ionic/cli-framework';
1011
import { BaseError } from '@ionic/cli-framework/lib/errors';
1112
import { onBeforeExit } from '@ionic/cli-framework/utils/process';
1213
import { str2num } from '@ionic/cli-framework/utils/string';
1314
import { fsReadJsonFile } from '@ionic/cli-framework/utils/fs';
15+
import { findClosestOpenPort, getExternalIPv4Interfaces } from '@ionic/cli-framework/utils/network';
1416

15-
import { CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, DevAppDetails, IConfig, ILogger, IProject, IShell, IonicEnvironment, LabServeDetails, NetworkInterface, ProjectType, PromptModule, ServeDetails, ServeOptions } from '../definitions';
17+
import { CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, DevAppDetails, IConfig, ILogger, IProject, IShell, IonicEnvironment, LabServeDetails, ProjectType, PromptModule, ServeDetails, ServeOptions } from '../definitions';
1618
import { isCordovaPackageJson } from '../guards';
1719
import { ASSETS_DIRECTORY, OptionGroup, PROJECT_FILE } from '../constants';
1820
import { FatalException, RunnerException, RunnerNotFoundException } from './errors';
@@ -250,30 +252,23 @@ export abstract class ServeRunner<T extends ServeOptions> extends Runner<T, Serv
250252
}
251253

252254
async gatherDevAppDetails(options: T, details: ServeDetails): Promise<DevAppDetails | undefined> {
253-
const { findClosestOpenPort } = await import('./utils/network');
254-
255255
if (options.devapp) {
256-
const { getSuitableNetworkInterfaces } = await import('./utils/network');
257256
const { computeBroadcastAddress } = await import('./devapp');
258257

259-
const availableInterfaces = getSuitableNetworkInterfaces();
260-
261258
// TODO: There is no accurate/reliable/realistic way to identify a WiFi
262259
// network uniquely in NodeJS. But this is where we could detect new
263260
// networks and prompt the dev if they want to "trust" it (allow binding to
264261
// 0.0.0.0 and broadcasting).
265262

266-
const interfaces = availableInterfaces
267-
.map(i => ({
268-
...i,
269-
broadcast: computeBroadcastAddress(i.address, i.netmask),
270-
}));
271-
272-
return {
273-
port: details.port,
274-
commPort: await findClosestOpenPort(DEFAULT_DEVAPP_COMM_PORT, '0.0.0.0'),
275-
interfaces,
276-
};
263+
const interfaces = getExternalIPv4Interfaces()
264+
.map(i => ({ ...i, broadcast: computeBroadcastAddress(i.address, i.netmask) }));
265+
266+
const { port } = details;
267+
268+
// the comm server always binds to 0.0.0.0 to target every possible interface
269+
const commPort = await findClosestOpenPort(DEFAULT_DEVAPP_COMM_PORT, '0.0.0.0');
270+
271+
return { port, commPort, interfaces };
277272
}
278273
}
279274

@@ -336,8 +331,6 @@ export abstract class ServeRunner<T extends ServeOptions> extends Runner<T, Serv
336331
}
337332

338333
async runLab(options: T, details: ServeDetails): Promise<LabServeDetails> {
339-
const { findClosestOpenPort } = await import('./utils/network');
340-
341334
const labDetails: LabServeDetails = {
342335
protocol: options.ssl ? 'https' : 'http',
343336
address: options.labHost,
@@ -445,13 +438,11 @@ export abstract class ServeRunner<T extends ServeOptions> extends Runner<T, Serv
445438
}
446439

447440
async selectExternalIP(options: T): Promise<[string, NetworkInterface[]]> {
448-
const { getSuitableNetworkInterfaces } = await import('./utils/network');
449-
450441
let availableInterfaces: NetworkInterface[] = [];
451442
let chosenIP = options.address;
452443

453444
if (options.address === BIND_ALL_ADDRESS) {
454-
availableInterfaces = getSuitableNetworkInterfaces();
445+
availableInterfaces = getExternalIPv4Interfaces();
455446

456447
if (availableInterfaces.length === 0) {
457448
if (options.externalAddressRequired) {
@@ -475,7 +466,7 @@ export abstract class ServeRunner<T extends ServeOptions> extends Runner<T, Serv
475466
name: 'promptedIp',
476467
message: 'Please select which IP to use:',
477468
choices: availableInterfaces.map(i => ({
478-
name: `${i.address} ${chalk.dim(`(${i.deviceName})`)}`,
469+
name: `${i.address} ${chalk.dim(`(${i.device})`)}`,
479470
value: i.address,
480471
})),
481472
});

0 commit comments

Comments
 (0)