Skip to content

Commit

Permalink
Fix port conflicts with functions:shell (#3223)
Browse files Browse the repository at this point in the history
  • Loading branch information
samtstern committed Mar 23, 2021
1 parent cae8fa5 commit 20e11f8
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 40 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Fixes an issue where `ext:dev:init` failed when Typescript was chosen.
- Add support for reading/writing mfaInfo field in Auth Emulator (#3173).
- Work around CORS issues with jsdom in Auth Emulator and Emulator Hub (#3224).
- Fixes port conflict issues with `functions:shell` (#3210).
4 changes: 2 additions & 2 deletions src/commands/experimental-functions-shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

var { Command } = require("../command");
var { requirePermissions } = require("../requirePermissions");
var action = require("../functionsShellCommandAction");
var { actionFunction } = require("../functionsShellCommandAction");
var requireConfig = require("../requireConfig");

module.exports = new Command("experimental:functions:shell")
Expand All @@ -12,4 +12,4 @@ module.exports = new Command("experimental:functions:shell")
.option("-p, --port <port>", "the port on which to emulate functions (default: 5000)", 5000)
.before(requireConfig)
.before(requirePermissions)
.action(action);
.action(actionFunction);
6 changes: 3 additions & 3 deletions src/commands/functions-shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

var { Command } = require("../command");
var { requirePermissions } = require("../requirePermissions");
var action = require("../functionsShellCommandAction");
var { actionFunction } = require("../functionsShellCommandAction");
var requireConfig = require("../requireConfig");
var commandUtils = require("../emulator/commandUtils");

module.exports = new Command("functions:shell")
.description("launch full Node shell with emulated functions")
.option("-p, --port <port>", "the port on which to emulate functions", 5000)
.option("-p, --port <port>", "the port on which to emulate functions")
.option(commandUtils.FLAG_INSPECT_FUNCTIONS, commandUtils.DESC_INSPECT_FUNCTIONS)
.before(requireConfig)
.before(requirePermissions)
.action(action);
.action(actionFunction);
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */

"use strict";

var clc = require("cli-color");
var repl = require("repl");
var _ = require("lodash");

var request = require("request");
var util = require("util");

var { FunctionsServer } = require("./serve/functions");
var LocalFunction = require("./localFunction");
var utils = require("./utils");
const { logger } = require("./logger");
var shell = require("./emulator/functionsEmulatorShell");
var commandUtils = require("./emulator/commandUtils");
var { EMULATORS_SUPPORTED_BY_FUNCTIONS } = require("./emulator/types");
var { EmulatorHubClient } = require("./emulator/hubClient");
import * as clc from "cli-color";
import * as repl from "repl";
import * as _ from "lodash";
import * as request from "request";
import * as util from "util";

import { FunctionsServer } from "./serve/functions";
import * as LocalFunction from "./localFunction";
import * as utils from "./utils";
import { logger } from "./logger";
import * as shell from "./emulator/functionsEmulatorShell";
import * as commandUtils from "./emulator/commandUtils";
import { EMULATORS_SUPPORTED_BY_FUNCTIONS, EmulatorInfo, Emulators } from "./emulator/types";
import { EmulatorHubClient } from "./emulator/hubClient";
import { Constants } from "./emulator/constants";
import { findAvailablePort } from "./emulator/portUtils";

const serveFunctions = new FunctionsServer();

module.exports = async function (options) {
options.port = parseInt(options.port, 10);
export const actionFunction = async (options: any) => {
if (options.port) {
options.port = parseInt(options.port, 10);
}

let debugPort = undefined;
if (options.inspectFunctions) {
debugPort = commandUtils.parseInspectionPort(options);
}

const hubClient = new EmulatorHubClient(options.project);
/** @type {Record<string,object>} */
let remoteEmulators = {};

let remoteEmulators: Record<string, EmulatorInfo> = {};
if (hubClient.foundHub()) {
remoteEmulators = await hubClient.getEmulators();
logger.debug("Running emulators: ", remoteEmulators);
Expand All @@ -43,16 +43,34 @@ module.exports = async function (options) {
(e) => remoteEmulators[e] === undefined
);

const functionsInfo = remoteEmulators[Emulators.FUNCTIONS];
if (functionsInfo) {
utils.logLabeledWarning(
"functions",
`You are already running the Cloud Functions emulator on port ${functionsInfo.port}. Running the emulator and the Functions shell simultaenously can result in unexpected behavior.`
);
} else if (!options.port) {
// If the user did not pass in any port and the functions emulator is not already running, we can
// use the port defined for the Functions emulator in their firebase.json
options.port = options.config.get(Constants.getPortKey(Emulators.FUNCTIONS), undefined);
}

// If the port was not set by the --port flag or determined from 'firebase.json', just scan
// up from 5000
if (!options.port) {
options.port = await findAvailablePort("localhost", 5000);
}

return serveFunctions
.start(options, {
quiet: true,
remoteEmulators,
debugPort,
})
.then(function () {
.then(() => {
return serveFunctions.connect();
})
.then(function () {
.then(() => {
const instance = serveFunctions.get();
const emulator = new shell.FunctionsEmulatorShell(instance);

Expand All @@ -61,14 +79,14 @@ module.exports = async function (options) {
process.exit();
}

var initializeContext = function (context) {
_.forEach(emulator.triggers, function (trigger) {
if (_.includes(emulator.emulatedFunctions, trigger.name)) {
var localFunction = new LocalFunction(trigger, emulator.urls, emulator);
var triggerNameDotNotation = trigger.name.replace(/-/g, ".");
const initializeContext = (context: any) => {
for (const trigger of emulator.triggers) {
if (emulator.emulatedFunctions.includes(trigger.name)) {
const localFunction = new LocalFunction(trigger, emulator.urls, emulator);
const triggerNameDotNotation = trigger.name.replace(/-/g, ".");
_.set(context, triggerNameDotNotation, localFunction.call);
}
});
}
context.help =
"Instructions for the Functions Shell can be found at: " +
"https://firebase.google.com/docs/functions/local-emulator";
Expand All @@ -90,7 +108,7 @@ module.exports = async function (options) {
)}`
);

var writer = function (output) {
const writer = (output: any) => {
// Prevent full print out of Request object when a request is made
// @ts-ignore
if (output instanceof request.Request) {
Expand All @@ -99,18 +117,18 @@ module.exports = async function (options) {
return util.inspect(output);
};

var prompt = "firebase > ";
const prompt = "firebase > ";

var replServer = repl.start({
const replServer = repl.start({
prompt: prompt,
writer: writer,
useColors: true,
});
initializeContext(replServer.context);
replServer.on("reset", initializeContext);

return new Promise(function (resolve) {
replServer.on("exit", function () {
return new Promise((resolve) => {
replServer.on("exit", () => {
return serveFunctions.stop().then(resolve).catch(resolve);
});
});
Expand Down

0 comments on commit 20e11f8

Please sign in to comment.