Skip to content

Commit 1bedea2

Browse files
authored
Support Firebase sutdio port forwarding in emulator suite (#8443)
* Trying out some IDX hax * Oops * round 2 * Progess! * Progess! * More hax * a cleaner appraoch * For functions, too * For functions, too * Dont double apply * Dont double apply * websockets too * extra url * PR cleanup * Use WEB_HOST instead * Use 443 instead
1 parent 4712d8f commit 1bedea2

File tree

4 files changed

+52
-26
lines changed

4 files changed

+52
-26
lines changed

src/emulator/env.ts

+29
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { formatHost } from "./functionsEmulatorShared";
44
import { Account } from "../types/auth/index";
55
import { EmulatorLogger } from "./emulatorLogger";
66
import { getCredentialPathAsync, hasDefaultCredentials } from "../defaultCredentials";
7+
import { FirestoreEmulatorInfo } from "./firestoreEmulator";
78

89
/**
910
* Adds or replaces emulator-related env vars (for Admin SDKs, etc.).
@@ -14,6 +15,7 @@ export function setEnvVarsForEmulators(
1415
env: Record<string, string | undefined>,
1516
emulators: EmulatorInfo[],
1617
): void {
18+
maybeUsePortForwarding(emulators);
1719
for (const emu of emulators) {
1820
const host = formatHost(emu);
1921
switch (emu.name) {
@@ -85,3 +87,30 @@ export async function getCredentialsEnvironment(
8587
}
8688
return credentialEnv;
8789
}
90+
91+
export function maybeUsePortForwarding(emulatorInfos: EmulatorInfo[]): EmulatorInfo[] {
92+
const portForwardingHost = process.env.WEB_HOST;
93+
if (portForwardingHost) {
94+
for (const info of emulatorInfos) {
95+
if (info.host.includes(portForwardingHost)) {
96+
// Don't double apply this.
97+
// TODO: Just deep copy everything each time.
98+
continue;
99+
}
100+
const url = `${info.port}-${portForwardingHost}`;
101+
info.host = url;
102+
info.listen = info.listen?.map((l) => {
103+
l.address = url;
104+
l.port = 443;
105+
return l;
106+
});
107+
info.port = 443;
108+
const fsInfo = info as FirestoreEmulatorInfo;
109+
if (fsInfo.webSocketPort) {
110+
fsInfo.webSocketHost = `${fsInfo.webSocketPort}-${portForwardingHost}`;
111+
fsInfo.webSocketPort = 443;
112+
}
113+
}
114+
}
115+
return emulatorInfos;
116+
}

src/emulator/functionsEmulator.ts

+4-6
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ import * as functionsEnv from "../functions/env";
5959
import { AUTH_BLOCKING_EVENTS, BEFORE_CREATE_EVENT } from "../functions/events/v1";
6060
import { BlockingFunctionsConfig } from "../gcp/identityPlatform";
6161
import { resolveBackend } from "../deploy/functions/build";
62-
import { getCredentialsEnvironment, setEnvVarsForEmulators } from "./env";
62+
import { getCredentialsEnvironment, maybeUsePortForwarding, setEnvVarsForEmulators } from "./env";
6363
import { runWithVirtualEnv } from "../functions/python";
6464
import { Runtime } from "../deploy/functions/runtimes/supported";
6565
import { ExtensionsEmulator } from "./extensionsEmulator";
@@ -1427,6 +1427,7 @@ export class FunctionsEmulator implements EmulatorInstance {
14271427
if (this.args.remoteEmulators) {
14281428
emulatorInfos = emulatorInfos.concat(Object.values(this.args.remoteEmulators));
14291429
}
1430+
maybeUsePortForwarding(emulatorInfos);
14301431
setEnvVarsForEmulators(envs, emulatorInfos);
14311432

14321433
if (this.debugMode) {
@@ -1710,12 +1711,9 @@ export class FunctionsEmulator implements EmulatorInstance {
17101711
* @param emulator
17111712
*/
17121713
private getEmulatorInfo(emulator: Emulators): EmulatorInfo | undefined {
1713-
if (this.args.remoteEmulators) {
1714-
if (this.args.remoteEmulators[emulator]) {
1715-
return this.args.remoteEmulators[emulator];
1716-
}
1714+
if (this.args.remoteEmulators?.[emulator]) {
1715+
return this.args.remoteEmulators[emulator];
17171716
}
1718-
17191717
return EmulatorRegistry.getInfo(emulator);
17201718
}
17211719

src/emulator/hub.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export interface EmulatorHubArgs {
2929
listenForEmulator: Record<PortName, ListenSpec[]>;
3030
}
3131

32-
export type GetEmulatorsResponse = Record<string, EmulatorInfo>;
32+
export type GetEmulatorsResponse = Partial<Record<Emulators, EmulatorInfo>>;
3333

3434
export class EmulatorHub extends ExpressBasedEmulator {
3535
static CLI_VERSION = pkg.version;
@@ -79,7 +79,7 @@ export class EmulatorHub extends ExpressBasedEmulator {
7979
await this.writeLocatorFile();
8080
}
8181

82-
getRunningEmulatorsMapping(): any {
82+
getRunningEmulatorsMapping(): GetEmulatorsResponse {
8383
const emulators: GetEmulatorsResponse = {};
8484
for (const info of EmulatorRegistry.listRunningWithInfo()) {
8585
emulators[info.name] = {

src/emulator/ui.ts

+17-18
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,24 @@ import { EmulatorRegistry } from "./registry";
66
import { FirebaseError } from "../error";
77
import { EmulatorLogger } from "./emulatorLogger";
88
import { Constants } from "./constants";
9-
import { emulatorSession } from "../track";
9+
import { AnalyticsSession, emulatorSession } from "../track";
1010
import { ExpressBasedEmulator } from "./ExpressBasedEmulator";
1111
import { ALL_EXPERIMENTS, ExperimentName, isEnabled } from "../experiments";
12-
import { EmulatorHub } from "./hub";
12+
import { EmulatorHub, GetEmulatorsResponse } from "./hub";
13+
import { maybeUsePortForwarding } from "./env";
1314

1415
export interface EmulatorUIOptions {
1516
listen: ListenSpec[];
1617
projectId: string;
1718
}
1819

20+
// Response shape for /api/config endpoint. Contains info about which emulators are running and where.
21+
interface EmulatorConfigInfo extends GetEmulatorsResponse {
22+
projectId: string;
23+
experiments: string[];
24+
analytics?: AnalyticsSession;
25+
}
26+
1927
export class EmulatorUI extends ExpressBasedEmulator {
2028
constructor(private args: EmulatorUIOptions) {
2129
super({
@@ -49,27 +57,18 @@ export class EmulatorUI extends ExpressBasedEmulator {
4957

5058
// Exposes the host and port of various emulators to facilitate accessing
5159
// them using client SDKs. For features that involve multiple emulators or
52-
// hard to accomplish using client SDKs, consider adding an API below.
60+
// hard to accomplish using client SDKs, consider adding an API below
5361
app.get(
5462
"/api/config",
5563
this.jsonHandler(() => {
56-
const json = {
64+
const emulatorInfos = (hub! as EmulatorHub).getRunningEmulatorsMapping();
65+
maybeUsePortForwarding(Object.values(emulatorInfos));
66+
const json: EmulatorConfigInfo = {
5767
projectId,
58-
experiments: [],
59-
...(hub! as EmulatorHub).getRunningEmulatorsMapping(),
68+
experiments: enabledExperiments ?? [],
69+
analytics: emulatorGaSession,
70+
...emulatorInfos,
6071
};
61-
62-
// Googlers: see go/firebase-emulator-ui-usage-collection-design?pli=1#heading=h.jwz7lj6r67z8
63-
// for more detail
64-
if (emulatorGaSession) {
65-
json.analytics = emulatorGaSession;
66-
}
67-
68-
// pick up any experiments enabled with `firebase experiment:enable`
69-
if (enabledExperiments) {
70-
json.experiments = enabledExperiments;
71-
}
72-
7372
return Promise.resolve(json);
7473
}),
7574
);

0 commit comments

Comments
 (0)