Skip to content

Commit

Permalink
Support UI listening on mutliple addresses. (#5088)
Browse files Browse the repository at this point in the history
* Support UI listening on mutliple addresses.

* Release UI v1.11.0.
  • Loading branch information
yuchenshi committed Oct 7, 2022
1 parent 70180c9 commit 8f18fba
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 34 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
- Enable single project mode for the database emulator (#5068).
- Ravamp emulator networking to assign ports early and explictly listen on IP addresses (#5083).
- Emulator UI and hub now listen on both IPv4 and IPv6 address by default (if possible) (#5088).
- Fix Firestore emulator excessive logs about discovery endpoint not found (#5088).
1 change: 1 addition & 0 deletions src/commands/emulators-start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ function printEmulatorOverview(options: any): void {
if (uiRunning) {
row.push("");
}
return row;
}
let uiLink = "n/a";
if (isSupportedByUi && uiRunning) {
Expand Down
28 changes: 17 additions & 11 deletions src/emulator/ExpressBasedEmulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ export abstract class ExpressBasedEmulator implements EmulatorInstance {
const promises = [];
const specs = this.options.listen;

for (const opt of ExpressBasedEmulator.listenOptionsFromSpecs(specs)) {
promises.push(
new Promise((resolve, reject) => {
const server = createServer(app).listen(opt);
server.once("listening", resolve);
server.once("error", reject);
this.destroyers.add(utils.createDestroyer(server));
})
);
}
}

/**
* Translate addresses and ports to low-level net/http server options.
*/
static listenOptionsFromSpecs(specs: ListenSpec[]): ListenOptions[] {
const listenOptions: ListenOptions[] = [];

const dualStackPorts = new Set();
Expand Down Expand Up @@ -89,17 +105,7 @@ export abstract class ExpressBasedEmulator implements EmulatorInstance {
});
}
}

for (const opt of listenOptions) {
promises.push(
new Promise((resolve, reject) => {
const server = createServer(app).listen(opt);
server.once("listening", resolve);
server.once("error", reject);
this.destroyers.add(utils.createDestroyer(server));
})
);
}
return listenOptions;
}

async connect(): Promise<void> {
Expand Down
9 changes: 6 additions & 3 deletions src/emulator/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,11 @@ export async function startAll(
}

if (listenForEmulator.hub) {
const hub = new EmulatorHub({ projectId, listen: listenForEmulator[Emulators.HUB] });
const hub = new EmulatorHub({
projectId,
listen: listenForEmulator[Emulators.HUB],
listenForEmulator,
});

// Log the command for analytics, we only report this for "hub"
// since we originally mistakenly reported emulators:start events
Expand Down Expand Up @@ -820,11 +824,10 @@ export async function startAll(
}

if (listenForEmulator.ui) {
const uiAddr = legacyGetFirstAddr(Emulators.UI);
const ui = new EmulatorUI({
projectId: projectId,
auto_download: true,
...uiAddr,
listen: listenForEmulator[Emulators.UI],
});
await startEmulator(ui);
}
Expand Down
14 changes: 7 additions & 7 deletions src/emulator/downloadableEmulators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ export const DownloadDetails: { [s in DownloadableEmulators]: EmulatorDownloadDe
},
}
: {
version: "1.10.0",
downloadPath: path.join(CACHE_DIR, "ui-v1.10.0.zip"),
unzipDir: path.join(CACHE_DIR, "ui-v1.10.0"),
binaryPath: path.join(CACHE_DIR, "ui-v1.10.0", "server", "server.js"),
version: "1.11.0",
downloadPath: path.join(CACHE_DIR, "ui-v1.11.0.zip"),
unzipDir: path.join(CACHE_DIR, "ui-v1.11.0"),
binaryPath: path.join(CACHE_DIR, "ui-v1.11.0", "server", "server.js"),
opts: {
cacheDir: CACHE_DIR,
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v1.10.0.zip",
expectedSize: 3062540,
expectedChecksum: "7dec1e82acccc196efc4d364e2664288",
remoteUrl: "https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v1.11.0.zip",
expectedSize: 3061915,
expectedChecksum: "94679756dc270754e9a4dc9d1c6fc4e1",
namePrefix: "ui",
},
},
Expand Down
7 changes: 6 additions & 1 deletion src/emulator/hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { HubExport } from "./hubExport";
import { EmulatorRegistry } from "./registry";
import { FunctionsEmulator } from "./functionsEmulator";
import { ExpressBasedEmulator } from "./ExpressBasedEmulator";
import { PortName } from "./portUtils";

// We use the CLI version from package.json
const pkg = require("../../package.json");
Expand All @@ -23,6 +24,7 @@ export interface Locator {
export interface EmulatorHubArgs {
projectId: string;
listen: ListenSpec[];
listenForEmulator: Record<PortName, ListenSpec[]>;
}

export type GetEmulatorsResponse = Record<string, EmulatorInfo>;
Expand Down Expand Up @@ -87,7 +89,10 @@ export class EmulatorHub extends ExpressBasedEmulator {
app.get(EmulatorHub.PATH_EMULATORS, (req, res) => {
const body: GetEmulatorsResponse = {};
for (const info of EmulatorRegistry.listRunningWithInfo()) {
body[info.name] = info;
body[info.name] = {
listen: this.args.listenForEmulator[info.name],
...info,
};
}
res.json(body);
});
Expand Down
8 changes: 4 additions & 4 deletions src/emulator/portUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ const EMULATOR_CAN_LISTEN_ON_PRIMARY_ONLY: Record<PortName, boolean> = {
// Listening on multiple addresses to maximize the chance of discovery.
hub: false,

// TODO: Modify the following emulators to listen on multiple addresses.
// Separate Node.js process that supports multi-listen. For consistency, we
// resolve the addresses in the CLI and pass the result to the UI.
ui: false,

// Separate Node.js process that requires a separate update.
// For consistency, we can resolve in the CLI and pass in the results.
ui: true,
// TODO: Modify the following emulators to listen on multiple addresses.

// Express-based servers, can be reused for multiple listen sockets.
auth: true,
Expand Down
15 changes: 7 additions & 8 deletions src/emulator/ui.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { EmulatorInstance, EmulatorInfo, Emulators } from "./types";
import { EmulatorInstance, EmulatorInfo, Emulators, ListenSpec } from "./types";
import * as downloadableEmulators from "./downloadableEmulators";
import { EmulatorRegistry } from "./registry";
import { FirebaseError } from "../error";
import { Constants } from "./constants";
import { emulatorSession } from "../track";
import { ExpressBasedEmulator } from "./ExpressBasedEmulator";

export interface EmulatorUIOptions {
port: number;
host: string;
listen: ListenSpec[];
projectId: string;
auto_download?: boolean;
}
Expand All @@ -23,10 +23,9 @@ export class EmulatorUI implements EmulatorInstance {
)}!`
);
}
const { auto_download: autoDownload, host, port, projectId } = this.args;
const { auto_download: autoDownload, projectId } = this.args;
const env: Partial<NodeJS.ProcessEnv> = {
HOST: host.toString(),
PORT: port.toString(),
LISTEN: JSON.stringify(ExpressBasedEmulator.listenOptionsFromSpecs(this.args.listen)),
GCLOUD_PROJECT: projectId,
[Constants.FIREBASE_EMULATOR_HUB]: EmulatorRegistry.url(Emulators.HUB).host,
};
Expand All @@ -50,8 +49,8 @@ export class EmulatorUI implements EmulatorInstance {
getInfo(): EmulatorInfo {
return {
name: this.getName(),
host: this.args.host,
port: this.args.port,
host: this.args.listen[0].address,
port: this.args.listen[0].port,
pid: downloadableEmulators.getPID(Emulators.UI),
};
}
Expand Down

0 comments on commit 8f18fba

Please sign in to comment.