Compare commits

...

7 Commits

Author SHA1 Message Date
Carson
cc13ba80cc Handle a user-supplied NULL/NA for port 2019-09-12 11:00:05 -05:00
Carson
bb3f324b56 findPort() instead of randomPort() 2019-09-12 10:47:05 -05:00
Carson
84d53e57e4 staticdocs entry 2019-09-11 16:46:05 -05:00
Carson
f8d048a742 Resolve the host before finding the port 2019-09-11 14:34:06 -05:00
Carson
0697dc2b72 more cleanup 2019-09-11 14:26:35 -05:00
Carson
55349d7770 clean-up docs 2019-09-11 14:24:16 -05:00
Carson
2c753fae8f Export randomPort(). Closes #2562 2019-09-11 14:20:21 -05:00
7 changed files with 91 additions and 58 deletions

View File

@@ -84,6 +84,7 @@ export(fileInput)
export(fillCol) export(fillCol)
export(fillPage) export(fillPage)
export(fillRow) export(fillRow)
export(findPort)
export(fixedPage) export(fixedPage)
export(fixedPanel) export(fixedPanel)
export(fixedRow) export(fixedRow)

View File

@@ -724,7 +724,7 @@ isRunning <- function() {
#' } #' }
#' @export #' @export
runApp <- function(appDir=getwd(), runApp <- function(appDir=getwd(),
port=getOption('shiny.port'), port=getOption('shiny.port', findPort(host = host)),
launch.browser=getOption('shiny.launch.browser', launch.browser=getOption('shiny.launch.browser',
interactive()), interactive()),
host=getOption('shiny.host', '127.0.0.1'), host=getOption('shiny.host', '127.0.0.1'),
@@ -794,12 +794,12 @@ runApp <- function(appDir=getwd(),
if (arg %in% names(appOps)) appOps[[arg]] else default if (arg %in% names(appOps)) appOps[[arg]] else default
} }
if (missing(host))
host <- findVal("host", host %OR% '0.0.0.0')
if (missing(port)) if (missing(port))
port <- findVal("port", port) port <- findVal("port", port %OR% findPort(host = host))
if (missing(launch.browser)) if (missing(launch.browser))
launch.browser <- findVal("launch.browser", launch.browser) launch.browser <- findVal("launch.browser", launch.browser)
if (missing(host))
host <- findVal("host", host)
if (missing(quiet)) if (missing(quiet))
quiet <- findVal("quiet", quiet) quiet <- findVal("quiet", quiet)
if (missing(display.mode)) if (missing(display.mode))
@@ -807,8 +807,6 @@ runApp <- function(appDir=getwd(),
if (missing(test.mode)) if (missing(test.mode))
test.mode <- findVal("test.mode", test.mode) test.mode <- findVal("test.mode", test.mode)
if (is.null(host) || is.na(host)) host <- '0.0.0.0'
workerId(workerId) workerId(workerId)
if (inShinyServer()) { if (inShinyServer()) {
@@ -883,44 +881,6 @@ runApp <- function(appDir=getwd(),
require(shiny) require(shiny)
# determine port if we need to
if (is.null(port)) {
# Try up to 20 random ports. If we don't succeed just plow ahead
# with the final value we tried, and let the "real" startServer
# somewhere down the line fail and throw the error to the user.
#
# If we (think we) succeed, save the value as .globals$lastPort,
# and try that first next time the user wants a random port.
for (i in 1:20) {
if (!is.null(.globals$lastPort)) {
port <- .globals$lastPort
.globals$lastPort <- NULL
}
else {
# Try up to 20 random ports
while (TRUE) {
port <- p_randomInt(3000, 8000)
# Reject ports in this range that are considered unsafe by Chrome
# http://superuser.com/questions/188058/which-ports-are-considered-unsafe-on-chrome
# https://github.com/rstudio/shiny/issues/1784
if (!port %in% c(3659, 4045, 6000, 6665:6669, 6697)) {
break
}
}
}
# Test port to see if we can use it
tmp <- try(startServer(host, port, list()), silent=TRUE)
if (!inherits(tmp, 'try-error')) {
stopServer(tmp)
.globals$lastPort <- port
break
}
}
}
# Invoke user-defined onStop callbacks, before the application's internal # Invoke user-defined onStop callbacks, before the application's internal
# onStop callbacks. # onStop callbacks.
on.exit({ on.exit({
@@ -1062,7 +1022,7 @@ stopApp <- function(returnValue = invisible()) {
#' } #' }
#' @export #' @export
runExample <- function(example=NA, runExample <- function(example=NA,
port=NULL, port=getOption('shiny.port', findPort(host = host)),
launch.browser=getOption('shiny.launch.browser', launch.browser=getOption('shiny.launch.browser',
interactive()), interactive()),
host=getOption('shiny.host', '127.0.0.1'), host=getOption('shiny.host', '127.0.0.1'),
@@ -1126,7 +1086,7 @@ runExample <- function(example=NA,
#' runGadget(shinyApp(ui, server)) #' runGadget(shinyApp(ui, server))
#' } #' }
#' @export #' @export
runGadget <- function(app, server = NULL, port = getOption("shiny.port"), runGadget <- function(app, server = NULL, port = getOption("shiny.port", findPort()),
viewer = paneViewer(), stopOnCancel = TRUE) { viewer = paneViewer(), stopOnCancel = TRUE) {
if (!is.shiny.appobj(app)) { if (!is.shiny.appobj(app)) {
@@ -1221,6 +1181,41 @@ browserViewer <- function(browser = getOption("browser")) {
} }
} }
#' Find an open TCP port
#'
#' Finds a random available TCP port for listening on.
#'
#' @param min Minimum port number.
#' @param max Maximum port number.
#' @param host see [httpuv::randomPort()].
#' @param n Number of ports to try before giving up.
#' @param cache if `TRUE`, use the last random port if it's available.
#'
#' @details This function automatically excludes some ports
#' which are considered unsafe by web browsers.
#'
#' @seealso [httpuv::randomPort()]
#' @export
#' @examples
#'
#' findPort()
#' findPort()
#' findPort(cache = FALSE)
findPort <- function(min = 3000L, max = 8000L,
host = getOption("shiny.host", "127.0.0.1"),
n = 20, cache = TRUE) {
if (cache && !is.null(.globals$lastPort)) {
tmp <- try(startServer(host, .globals$lastPort, list()), silent = TRUE)
if (!inherits(tmp, 'try-error')) {
stopServer(tmp)
return(.globals$lastPort)
}
}
.globals$lastPort <- withPrivateSeed(httpuv::randomPort(min, max, host, n))
.globals$lastPort
}
# Returns TRUE if we're running in Shiny Server or other hosting environment, # Returns TRUE if we're running in Shiny Server or other hosting environment,
# otherwise returns FALSE. # otherwise returns FALSE.
inShinyServer <- function() { inShinyServer <- function() {

View File

@@ -204,7 +204,8 @@ sd_section("Utility functions",
"onStop", "onStop",
"diskCache", "diskCache",
"memoryCache", "memoryCache",
"reexports" "reexports",
"findPort"
) )
) )
sd_section("Plot interaction", sd_section("Plot interaction",

36
man/findPort.Rd Normal file
View File

@@ -0,0 +1,36 @@
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/server.R
\name{findPort}
\alias{findPort}
\title{Find an open TCP port}
\usage{
findPort(min = 3000L, max = 8000L, host = getOption("shiny.host",
"127.0.0.1"), n = 20, cache = TRUE)
}
\arguments{
\item{min}{Minimum port number.}
\item{max}{Maximum port number.}
\item{host}{see \code{\link[httpuv:randomPort]{httpuv::randomPort()}}.}
\item{n}{Number of ports to try before giving up.}
\item{cache}{if \code{TRUE}, use the last random port if it's available.}
}
\description{
Finds a random available TCP port for listening on.
}
\details{
This function automatically excludes some ports
which are considered unsafe by web browsers.
}
\examples{
findPort()
findPort()
findPort(cache = FALSE)
}
\seealso{
\code{\link[httpuv:randomPort]{httpuv::randomPort()}}
}

View File

@@ -4,11 +4,11 @@
\alias{runApp} \alias{runApp}
\title{Run Shiny Application} \title{Run Shiny Application}
\usage{ \usage{
runApp(appDir = getwd(), port = getOption("shiny.port"), runApp(appDir = getwd(), port = getOption("shiny.port", findPort(host =
launch.browser = getOption("shiny.launch.browser", interactive()), host)), launch.browser = getOption("shiny.launch.browser",
host = getOption("shiny.host", "127.0.0.1"), workerId = "", interactive()), host = getOption("shiny.host", "127.0.0.1"),
quiet = FALSE, display.mode = c("auto", "normal", "showcase"), workerId = "", quiet = FALSE, display.mode = c("auto", "normal",
test.mode = getOption("shiny.testmode", FALSE)) "showcase"), test.mode = getOption("shiny.testmode", FALSE))
} }
\arguments{ \arguments{
\item{appDir}{The application to run. Should be one of the following: \item{appDir}{The application to run. Should be one of the following:

View File

@@ -4,10 +4,10 @@
\alias{runExample} \alias{runExample}
\title{Run Shiny Example Applications} \title{Run Shiny Example Applications}
\usage{ \usage{
runExample(example = NA, port = NULL, runExample(example = NA, port = getOption("shiny.port", findPort(host =
launch.browser = getOption("shiny.launch.browser", interactive()), host)), launch.browser = getOption("shiny.launch.browser",
host = getOption("shiny.host", "127.0.0.1"), display.mode = c("auto", interactive()), host = getOption("shiny.host", "127.0.0.1"),
"normal", "showcase")) display.mode = c("auto", "normal", "showcase"))
} }
\arguments{ \arguments{
\item{example}{The name of the example to run, or \code{NA} (the default) to \item{example}{The name of the example to run, or \code{NA} (the default) to

View File

@@ -4,8 +4,8 @@
\alias{runGadget} \alias{runGadget}
\title{Run a gadget} \title{Run a gadget}
\usage{ \usage{
runGadget(app, server = NULL, port = getOption("shiny.port"), runGadget(app, server = NULL, port = getOption("shiny.port",
viewer = paneViewer(), stopOnCancel = TRUE) findPort()), viewer = paneViewer(), stopOnCancel = TRUE)
} }
\arguments{ \arguments{
\item{app}{Either a Shiny app object as created by \item{app}{Either a Shiny app object as created by