DemoBench: open web page automatically once web server has started.

This commit is contained in:
Mike Hearn 2017-04-24 12:59:22 +02:00
parent e139df7891
commit 2de5c0b218
2 changed files with 59 additions and 35 deletions

View File

@ -1,6 +1,5 @@
package net.corda.demobench.views
import com.google.common.util.concurrent.RateLimiter
import com.jediterm.terminal.TerminalColor
import com.jediterm.terminal.TextStyle
import com.jediterm.terminal.ui.settings.DefaultSettingsProvider
@ -13,6 +12,8 @@ import javafx.scene.layout.StackPane
import javafx.scene.layout.VBox
import javafx.util.Duration
import net.corda.client.rpc.notUsed
import net.corda.core.success
import net.corda.core.then
import net.corda.demobench.explorer.ExplorerController
import net.corda.demobench.model.NodeConfig
import net.corda.demobench.model.NodeController
@ -24,12 +25,9 @@ import net.corda.demobench.web.DBViewer
import net.corda.demobench.web.WebServerController
import tornadofx.*
import java.awt.Dimension
import java.io.IOException
import java.net.SocketException
import java.net.URL
import java.net.URI
import java.util.logging.Level
import javax.swing.SwingUtilities
import kotlin.concurrent.thread
class NodeTerminalView : Fragment() {
override val root by fxml<VBox>()
@ -131,6 +129,8 @@ class NodeTerminalView : Fragment() {
}
}
private var webURL: URI? = null
/*
* We only want to run one web server for each node.
* So disable the "launch" button when we have
@ -139,32 +139,20 @@ class NodeTerminalView : Fragment() {
*/
fun configureWebButton(config: NodeConfig) {
launchWebButton.setOnAction {
if (webURL != null) {
app.hostServices.showDocument(webURL.toString())
return@setOnAction
}
launchWebButton.isDisable = true
webServer.open(config, onExit = {
launchWebButton.isDisable = false
})
openBrowserWhenWebServerHasStarted(config)
}
}
private fun openBrowserWhenWebServerHasStarted(config: NodeConfig) {
thread {
log.info("Waiting for web server to start ...")
val url = URL("http://localhost:${config.webPort}/")
val rateLimiter = RateLimiter.create(1.0)
while (true) {
try {
rateLimiter.acquire()
val conn = url.openConnection()
conn.connectTimeout = 1000 // msec
conn.connect()
log.info("Web server started")
app.hostServices.showDocument(url.toString())
break
} catch(e: SocketException) {
} catch(e: IOException) {
log.info("Starting web server for ${config.legalName}")
webServer.open(config) then {
Platform.runLater { launchWebButton.isDisable = false }
} success {
log.info("Web server for ${config.legalName} started on $it")
Platform.runLater {
webURL = it
app.hostServices.showDocument(it.toString())
}
}
}

View File

@ -1,10 +1,21 @@
package net.corda.demobench.web
import com.google.common.util.concurrent.ListenableFuture
import com.google.common.util.concurrent.RateLimiter
import com.google.common.util.concurrent.SettableFuture
import net.corda.core.catch
import net.corda.core.minutes
import net.corda.core.until
import net.corda.core.utilities.loggerFor
import net.corda.demobench.model.NodeConfig
import net.corda.demobench.readErrorLines
import java.io.IOException
import java.net.HttpURLConnection
import java.net.URI
import java.time.Instant
import java.util.concurrent.Executors
import java.util.concurrent.TimeoutException
import kotlin.concurrent.thread
class WebServer internal constructor(private val webServerController: WebServerController) : AutoCloseable {
private companion object {
@ -15,13 +26,12 @@ class WebServer internal constructor(private val webServerController: WebServerC
private var process: Process? = null
@Throws(IOException::class)
fun open(config: NodeConfig, onExit: (NodeConfig) -> Unit) {
fun open(config: NodeConfig): ListenableFuture<URI> {
val nodeDir = config.nodeDir.toFile()
if (!nodeDir.isDirectory) {
log.warn("Working directory '{}' does not exist.", nodeDir.absolutePath)
onExit(config)
return
return SettableFuture.create()
}
try {
@ -46,12 +56,18 @@ class WebServer internal constructor(private val webServerController: WebServerC
} else {
log.error("Web Server for '{}' has exited (value={}, {})", config.legalName, exitValue, errors)
}
onExit(config)
}
val future = SettableFuture.create<URI>()
thread {
future.catch {
log.info("Waiting for web server for ${config.legalName} to start ...")
waitForStart(config.webPort)
}
}
return future
} catch (e: IOException) {
log.error("Failed to launch Web Server for '{}': {}", config.legalName, e.message)
onExit(config)
throw e
}
}
@ -68,4 +84,24 @@ class WebServer internal constructor(private val webServerController: WebServerC
log.error("Failed to close stream: '{}'", e.message)
}
}
private fun waitForStart(port: Int): URI {
val url = URI("http://localhost:$port/")
val rateLimiter = RateLimiter.create(2.0)
val start = Instant.now()
val timeout = 1.minutes
while ((start until Instant.now()) < timeout) {
try {
rateLimiter.acquire()
val conn = url.toURL().openConnection() as HttpURLConnection
conn.connectTimeout = 500 // msec
conn.requestMethod = "HEAD"
conn.connect()
conn.disconnect()
return url
} catch(e: IOException) {
}
}
throw TimeoutException("Web server did not start within ${timeout.seconds} seconds")
}
}