From 8880d1c2f66b431fd9feae837af25a46f7e00bbb Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 7 Oct 2022 15:01:18 -0700 Subject: [PATCH 1/5] Support UI listening on mutliple addresses. --- src/emulator/ExpressBasedEmulator.ts | 28 +++++++++++++++++----------- src/emulator/controller.ts | 9 ++++++--- src/emulator/hub.ts | 7 ++++++- src/emulator/portUtils.ts | 8 ++++---- src/emulator/ui.ts | 15 +++++++-------- 5 files changed, 40 insertions(+), 27 deletions(-) diff --git a/src/emulator/ExpressBasedEmulator.ts b/src/emulator/ExpressBasedEmulator.ts index 1b09085f645..d380fe1640f 100644 --- a/src/emulator/ExpressBasedEmulator.ts +++ b/src/emulator/ExpressBasedEmulator.ts @@ -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(); @@ -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 { diff --git a/src/emulator/controller.ts b/src/emulator/controller.ts index 95aa457c2c9..557c571ca0d 100644 --- a/src/emulator/controller.ts +++ b/src/emulator/controller.ts @@ -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 @@ -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); } diff --git a/src/emulator/hub.ts b/src/emulator/hub.ts index 1c2a6d062de..2f4e3e68db2 100644 --- a/src/emulator/hub.ts +++ b/src/emulator/hub.ts @@ -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"); @@ -23,6 +24,7 @@ export interface Locator { export interface EmulatorHubArgs { projectId: string; listen: ListenSpec[]; + listenForEmulator: Record; } export type GetEmulatorsResponse = Record; @@ -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); }); diff --git a/src/emulator/portUtils.ts b/src/emulator/portUtils.ts index 82dde2d7830..69365697ea1 100644 --- a/src/emulator/portUtils.ts +++ b/src/emulator/portUtils.ts @@ -174,11 +174,11 @@ const EMULATOR_CAN_LISTEN_ON_PRIMARY_ONLY: Record = { // 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, diff --git a/src/emulator/ui.ts b/src/emulator/ui.ts index 38f275594b1..2796f225a00 100644 --- a/src/emulator/ui.ts +++ b/src/emulator/ui.ts @@ -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; } @@ -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 = { - 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, }; @@ -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), }; } From e7e69d42305b429e4c3abdc0212039a910152ca5 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 7 Oct 2022 15:05:50 -0700 Subject: [PATCH 2/5] Release UI v1.11.0. --- CHANGELOG.md | 2 ++ src/emulator/downloadableEmulators.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25abc0a9c01..d026176130b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 listens on both IPv4 and IPv6 address by default (if possible). +- Fixes Firestore emulator excessive logs about discovery endpoint not found. diff --git a/src/emulator/downloadableEmulators.ts b/src/emulator/downloadableEmulators.ts index f8e385334e5..b480779f5cc 100644 --- a/src/emulator/downloadableEmulators.ts +++ b/src/emulator/downloadableEmulators.ts @@ -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", }, }, From 03bf262d2710b69cb79d515dbb2ea0dc34d25c5b Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 7 Oct 2022 15:08:11 -0700 Subject: [PATCH 3/5] Add PR number. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d026176130b..f089556097a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +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 listens on both IPv4 and IPv6 address by default (if possible). -- Fixes Firestore emulator excessive logs about discovery endpoint not found. +- Emulator UI and hub now listens on both IPv4 and IPv6 address by default (if possible) (#5088). +- Fixes Firestore emulator excessive logs about discovery endpoint not found (#5088). From 88f6d7ba502f8c099305e48409d478184cb4802c Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 7 Oct 2022 15:10:02 -0700 Subject: [PATCH 4/5] Fix typo. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f089556097a..3340085786d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +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 listens on both IPv4 and IPv6 address by default (if possible) (#5088). -- Fixes Firestore emulator excessive logs about discovery endpoint not found (#5088). +- 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). From cd0f3d53dbb159a87f689c86533285612e39cc65 Mon Sep 17 00:00:00 2001 From: Yuchen Shi Date: Fri, 7 Oct 2022 15:17:06 -0700 Subject: [PATCH 5/5] Fix emulator table when failed. --- src/commands/emulators-start.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/emulators-start.ts b/src/commands/emulators-start.ts index b2ac228325b..65a33784ca5 100644 --- a/src/commands/emulators-start.ts +++ b/src/commands/emulators-start.ts @@ -101,6 +101,7 @@ function printEmulatorOverview(options: any): void { if (uiRunning) { row.push(""); } + return row; } let uiLink = "n/a"; if (isSupportedByUi && uiRunning) {