mirror of
https://github.com/corda/corda.git
synced 2025-01-28 07:04:12 +00:00
Display simple statistics about the node on each tab.
This commit is contained in:
parent
51d02e1e45
commit
cd5dde70e0
@ -33,9 +33,13 @@ repositories {
|
|||||||
|
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
jcenter()
|
||||||
maven {
|
maven {
|
||||||
url 'http://www.sparetimelabs.com/maven2'
|
url 'http://www.sparetimelabs.com/maven2'
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url 'https://dl.bintray.com/kotlin/exposed'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -43,12 +47,16 @@ dependencies {
|
|||||||
compile "no.tornado:tornadofx:$tornadofx_version"
|
compile "no.tornado:tornadofx:$tornadofx_version"
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
|
||||||
|
// ONLY USING THE RPC CLIENT!?
|
||||||
|
compile project(':node')
|
||||||
|
|
||||||
compile "com.h2database:h2:$h2_version"
|
compile "com.h2database:h2:$h2_version"
|
||||||
compile "net.java.dev.jna:jna:$jna_version"
|
compile "net.java.dev.jna:jna:$jna_version"
|
||||||
compile "net.java.dev.jna:jna-platform:$jna_version"
|
compile "net.java.dev.jna:jna-platform:$jna_version"
|
||||||
compile "com.google.guava:guava:$guava_version"
|
compile "com.google.guava:guava:$guava_version"
|
||||||
compile "com.sparetimelabs:purejavacomm:$purejavacomm_version"
|
compile "com.sparetimelabs:purejavacomm:$purejavacomm_version"
|
||||||
compile "org.slf4j:log4j-over-slf4j:$slf4j_version"
|
compile "org.slf4j:log4j-over-slf4j:$slf4j_version"
|
||||||
|
compile "org.slf4j:jcl-over-slf4j:$slf4j_version"
|
||||||
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
|
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
|
||||||
compile "ch.qos.logback:logback-classic:$logback_version"
|
compile "ch.qos.logback:logback-classic:$logback_version"
|
||||||
compile "com.typesafe:config:$typesafe_config_version"
|
compile "com.typesafe:config:$typesafe_config_version"
|
||||||
@ -58,6 +66,11 @@ dependencies {
|
|||||||
testCompile group: 'junit', name: 'junit', version: "$junit_version"
|
testCompile group: 'junit', name: 'junit', version: "$junit_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We don't want the Node to drag these transitive dependencies in either!
|
||||||
|
configurations.compile.exclude module: 'commons-logging'
|
||||||
|
configurations.compile.exclude module: 'log4j-slf4j-impl'
|
||||||
|
configurations.compile.exclude module: 'log4j-core'
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes 'Main-Class': mainClassName
|
attributes 'Main-Class': mainClassName
|
||||||
|
@ -15,7 +15,10 @@ class Explorer(val explorerController: ExplorerController) : AutoCloseable {
|
|||||||
"--host=localhost",
|
"--host=localhost",
|
||||||
"--port=%d".format(config.artemisPort),
|
"--port=%d".format(config.artemisPort),
|
||||||
"--username=%s".format(config.user["user"]),
|
"--username=%s".format(config.user["user"]),
|
||||||
"--password=%s".format(config.user["password"])
|
"--password=%s".format(config.user["password"]),
|
||||||
|
"--certificatesDir=%s".format(config.ssl.certificatesDirectory),
|
||||||
|
"--keyStorePassword=%s".format(config.ssl.keyStorePassword),
|
||||||
|
"--trustStorePassword=%s".format(config.ssl.trustStorePassword)
|
||||||
)
|
)
|
||||||
process = p
|
process = p
|
||||||
|
|
||||||
|
@ -4,9 +4,12 @@ import com.typesafe.config.Config
|
|||||||
import com.typesafe.config.ConfigFactory
|
import com.typesafe.config.ConfigFactory
|
||||||
import com.typesafe.config.ConfigValue
|
import com.typesafe.config.ConfigValue
|
||||||
import com.typesafe.config.ConfigValueFactory
|
import com.typesafe.config.ConfigValueFactory
|
||||||
|
import net.corda.node.services.config.SSLConfiguration
|
||||||
import java.lang.String.join
|
import java.lang.String.join
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
class NodeConfig(
|
class NodeConfig(
|
||||||
|
baseDir: Path,
|
||||||
legalName: String,
|
legalName: String,
|
||||||
artemisPort: Int,
|
artemisPort: Int,
|
||||||
val nearestCity: String,
|
val nearestCity: String,
|
||||||
@ -15,15 +18,23 @@ class NodeConfig(
|
|||||||
val extraServices: List<String>
|
val extraServices: List<String>
|
||||||
) : NetworkMapConfig(legalName, artemisPort) {
|
) : NetworkMapConfig(legalName, artemisPort) {
|
||||||
|
|
||||||
|
val nodeDir: Path = baseDir.resolve(key)
|
||||||
|
|
||||||
private var networkMapValue: NetworkMapConfig? = null
|
private var networkMapValue: NetworkMapConfig? = null
|
||||||
var networkMap : NetworkMapConfig?
|
var networkMap : NetworkMapConfig?
|
||||||
get() { return networkMapValue }
|
get() = networkMapValue
|
||||||
set(value) { networkMapValue = value }
|
set(value) { networkMapValue = value }
|
||||||
|
|
||||||
private val userMap: Map<String, String>
|
private val userMap: Map<String, String>
|
||||||
val user: Map<String, String>
|
val user: Map<String, String>
|
||||||
get() = userMap
|
get() = userMap
|
||||||
|
|
||||||
|
val ssl: SSLConfiguration = object : SSLConfiguration {
|
||||||
|
override val certificatesDirectory: Path = nodeDir.resolve("certificates")
|
||||||
|
override val trustStorePassword: String = "trustpass"
|
||||||
|
override val keyStorePassword: String = "cordacadevpass"
|
||||||
|
}
|
||||||
|
|
||||||
val toFileConfig : Config
|
val toFileConfig : Config
|
||||||
get() = ConfigFactory.empty()
|
get() = ConfigFactory.empty()
|
||||||
.withValue("myLegalName", valueFor(legalName))
|
.withValue("myLegalName", valueFor(legalName))
|
||||||
|
@ -13,7 +13,7 @@ import tornadofx.Controller
|
|||||||
class NodeController : Controller() {
|
class NodeController : Controller() {
|
||||||
private val FIRST_PORT = 10000
|
private val FIRST_PORT = 10000
|
||||||
|
|
||||||
private val workDir = Paths.get("work", localDir).toAbsolutePath()
|
private val baseDir = Paths.get("work", localDir).toAbsolutePath()
|
||||||
private val jvm by inject<JVMConfig>()
|
private val jvm by inject<JVMConfig>()
|
||||||
|
|
||||||
private val cordaPath = Paths.get("corda", "corda.jar").toAbsolutePath()
|
private val cordaPath = Paths.get("corda", "corda.jar").toAbsolutePath()
|
||||||
@ -28,6 +28,7 @@ class NodeController : Controller() {
|
|||||||
|
|
||||||
fun validate(nodeData: NodeData): NodeConfig? {
|
fun validate(nodeData: NodeData): NodeConfig? {
|
||||||
val config = NodeConfig(
|
val config = NodeConfig(
|
||||||
|
baseDir,
|
||||||
nodeData.legalName.value.trim(),
|
nodeData.legalName.value.trim(),
|
||||||
nodeData.artemisPort.value,
|
nodeData.artemisPort.value,
|
||||||
nodeData.nearestCity.value.trim(),
|
nodeData.nearestCity.value.trim(),
|
||||||
@ -37,6 +38,7 @@ class NodeController : Controller() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (nodes.putIfAbsent(config.key, config) != null) {
|
if (nodes.putIfAbsent(config.key, config) != null) {
|
||||||
|
log.warning("Node with key '" + config.key + "' already exists.")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ class NodeController : Controller() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun runCorda(pty: R3Pty, config: NodeConfig): Boolean {
|
fun runCorda(pty: R3Pty, config: NodeConfig): Boolean {
|
||||||
val nodeDir = workDir.resolve(config.key).toFile()
|
val nodeDir = config.nodeDir.toFile()
|
||||||
|
|
||||||
if (nodeDir.mkdirs()) {
|
if (nodeDir.mkdirs()) {
|
||||||
try {
|
try {
|
||||||
@ -93,7 +95,7 @@ class NodeController : Controller() {
|
|||||||
.format(Date(ManagementFactory.getRuntimeMXBean().startTime))
|
.format(Date(ManagementFactory.getRuntimeMXBean().startTime))
|
||||||
|
|
||||||
init {
|
init {
|
||||||
log.info("Working directory: " + workDir)
|
log.info("Base directory: " + baseDir)
|
||||||
log.info("Corda JAR: " + cordaPath)
|
log.info("Corda JAR: " + cordaPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package net.corda.demobench.rpc
|
||||||
|
|
||||||
|
import com.google.common.net.HostAndPort
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.TimeUnit.SECONDS
|
||||||
|
import net.corda.core.messaging.CordaRPCOps
|
||||||
|
import net.corda.demobench.model.NodeConfig
|
||||||
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
|
class NodeRPC(config: NodeConfig, invoke: (ops: CordaRPCOps) -> Unit): AutoCloseable {
|
||||||
|
private val log = LoggerFactory.getLogger(NodeRPC::class.java)
|
||||||
|
private val ONE_SECOND = SECONDS.toMillis(1)
|
||||||
|
|
||||||
|
private val rpcClient = CordaRPCClient(HostAndPort.fromParts("localhost", config.artemisPort), config.ssl)
|
||||||
|
private val timer = Timer()
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
timer.cancel()
|
||||||
|
rpcClient.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val setupTask = object : TimerTask() {
|
||||||
|
override fun run() {
|
||||||
|
try {
|
||||||
|
rpcClient.start(config.user.getOrElse("user") { "none" }, config.user.getOrElse("password") { "none" })
|
||||||
|
val ops = rpcClient.proxy()
|
||||||
|
|
||||||
|
// Cancel the "setup" task now that we've created the RPC client.
|
||||||
|
this.cancel()
|
||||||
|
|
||||||
|
// Schedule a new task that will refresh the display once per second.
|
||||||
|
timer.schedule(object: TimerTask() {
|
||||||
|
override fun run() {
|
||||||
|
invoke(ops)
|
||||||
|
}
|
||||||
|
}, 0, ONE_SECOND)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.warn("Node '{}' not ready yet (Error: {})", config.legalName, e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait 5 seconds for the node to start, and then poll once per second.
|
||||||
|
timer.schedule(setupTask, 5 * ONE_SECOND, ONE_SECOND)
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import com.jediterm.terminal.TerminalColor
|
|||||||
import com.jediterm.terminal.TextStyle
|
import com.jediterm.terminal.TextStyle
|
||||||
import com.jediterm.terminal.ui.settings.DefaultSettingsProvider
|
import com.jediterm.terminal.ui.settings.DefaultSettingsProvider
|
||||||
import java.awt.Dimension
|
import java.awt.Dimension
|
||||||
|
import javafx.application.Platform
|
||||||
import javafx.embed.swing.SwingNode
|
import javafx.embed.swing.SwingNode
|
||||||
import javafx.scene.control.Button
|
import javafx.scene.control.Button
|
||||||
import javafx.scene.control.Label
|
import javafx.scene.control.Label
|
||||||
@ -12,9 +13,11 @@ import javafx.scene.layout.VBox
|
|||||||
import javax.swing.SwingUtilities
|
import javax.swing.SwingUtilities
|
||||||
import net.corda.demobench.model.*
|
import net.corda.demobench.model.*
|
||||||
import net.corda.demobench.pty.R3Pty
|
import net.corda.demobench.pty.R3Pty
|
||||||
|
import net.corda.demobench.rpc.NodeRPC
|
||||||
import net.corda.demobench.ui.PropertyLabel
|
import net.corda.demobench.ui.PropertyLabel
|
||||||
import tornadofx.Fragment
|
import tornadofx.Fragment
|
||||||
import tornadofx.vgrow
|
import tornadofx.vgrow
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class NodeTerminalView : Fragment() {
|
class NodeTerminalView : Fragment() {
|
||||||
override val root by fxml<VBox>()
|
override val root by fxml<VBox>()
|
||||||
@ -31,9 +34,10 @@ class NodeTerminalView : Fragment() {
|
|||||||
private val viewDatabaseButton by fxid<Button>()
|
private val viewDatabaseButton by fxid<Button>()
|
||||||
private val launchExplorerButton by fxid<Button>()
|
private val launchExplorerButton by fxid<Button>()
|
||||||
|
|
||||||
val explorer = explorerController.explorer()
|
private val explorer = explorerController.explorer()
|
||||||
val viewer = DBViewer()
|
private val viewer = DBViewer()
|
||||||
var pty : R3Pty? = null
|
private var rpc: NodeRPC? = null
|
||||||
|
private var pty: R3Pty? = null
|
||||||
|
|
||||||
fun open(config: NodeConfig) {
|
fun open(config: NodeConfig) {
|
||||||
nodeName.text = config.legalName
|
nodeName.text = config.legalName
|
||||||
@ -65,18 +69,38 @@ class NodeTerminalView : Fragment() {
|
|||||||
* the explorer has exited.
|
* the explorer has exited.
|
||||||
*/
|
*/
|
||||||
launchExplorerButton.setOnAction {
|
launchExplorerButton.setOnAction {
|
||||||
launchExplorerButton.isDisable= true
|
launchExplorerButton.isDisable = true
|
||||||
|
|
||||||
explorer.open(config, onExit = {
|
explorer.open(config, onExit = {
|
||||||
launchExplorerButton.isDisable = false
|
launchExplorerButton.isDisable = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpc = NodeRPC(config, { ops ->
|
||||||
|
try {
|
||||||
|
val verifiedTx = ops.verifiedTransactions()
|
||||||
|
val statesInVault = ops.vaultAndUpdates()
|
||||||
|
val cashBalances = ops.getCashBalances().entries.joinToString(
|
||||||
|
separator = ", ",
|
||||||
|
transform = { e -> "%s %s".format(e.value, e.key.currencyCode) }
|
||||||
|
)
|
||||||
|
|
||||||
|
Platform.runLater {
|
||||||
|
states.value = statesInVault.first.size.toString()
|
||||||
|
transactions.value = verifiedTx.first.size.toString()
|
||||||
|
balance.value = cashBalances
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.warning("RPC failed: " + e)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun close() {
|
fun close() {
|
||||||
explorer.close()
|
explorer.close()
|
||||||
viewer.close()
|
viewer.close()
|
||||||
|
rpc?.close()
|
||||||
pty?.close()
|
pty?.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user