mirror of
https://github.com/corda/corda.git
synced 2025-06-02 15:40:53 +00:00
Added webserver to runnodes.
This commit is contained in:
parent
13551a6b23
commit
3482452c8b
@ -82,11 +82,6 @@ interface CordaRPCOps : RPCOps {
|
|||||||
*/
|
*/
|
||||||
fun nodeIdentity(): NodeInfo
|
fun nodeIdentity(): NodeInfo
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if node is up and ready
|
|
||||||
*/
|
|
||||||
fun ready(): Boolean
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add note(s) to an existing Vault transaction
|
* Add note(s) to an existing Vault transaction
|
||||||
*/
|
*/
|
||||||
@ -107,9 +102,8 @@ interface CordaRPCOps : RPCOps {
|
|||||||
*/
|
*/
|
||||||
fun uploadAttachment(jar: InputStream): SecureHash
|
fun uploadAttachment(jar: InputStream): SecureHash
|
||||||
|
|
||||||
/**
|
@Suppress("DEPRECATION")
|
||||||
* Uploads a file by data type to the node and returns a meaningful string to the user
|
@Deprecated("This service will be removed in a future milestone")
|
||||||
*/
|
|
||||||
fun uploadFile(dataType: String, name: String?, file: InputStream): String
|
fun uploadFile(dataType: String, name: String?, file: InputStream): String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -218,14 +218,22 @@ interface KeyManagementService {
|
|||||||
fun freshKey(): KeyPair
|
fun freshKey(): KeyPair
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move and document
|
// TODO: Move to a more appropriate location
|
||||||
|
/**
|
||||||
|
* An interface that denotes a service that can accept file uploads.
|
||||||
|
*/
|
||||||
interface FileUploader {
|
interface FileUploader {
|
||||||
/**
|
/**
|
||||||
* Accepts the data in the given input stream, and returns some sort of useful return message that will be sent
|
* Accepts the data in the given input stream, and returns some sort of useful return message that will be sent
|
||||||
* back to the user in the response.
|
* back to the user in the response.
|
||||||
*/
|
*/
|
||||||
fun upload(file: InputStream): String
|
fun upload(file: InputStream): String
|
||||||
fun accepts(prefix: String): Boolean
|
|
||||||
|
/**
|
||||||
|
* Check if this service accepts this type of upload. For example if you are uploading interest rates this could
|
||||||
|
* be "my-service-interest-rates". Type here does not refer to file extentions or MIME types.
|
||||||
|
*/
|
||||||
|
fun accepts(type: String): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -244,7 +252,8 @@ interface StorageService {
|
|||||||
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
|
/** Provides access to storage of arbitrary JAR files (which may contain only data, no code). */
|
||||||
val attachments: AttachmentStorage
|
val attachments: AttachmentStorage
|
||||||
|
|
||||||
/** Provides file uploads of arbitrary files to services **/
|
@Suppress("DEPRECATION")
|
||||||
|
@Deprecated("This service will be removed in a future milestone")
|
||||||
val uploaders: List<FileUploader>
|
val uploaders: List<FileUploader>
|
||||||
|
|
||||||
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
|
val stateMachineRecordedTransactionMapping: StateMachineRecordedTransactionMappingStorage
|
||||||
|
@ -82,13 +82,16 @@ path to the node's base directory.
|
|||||||
|
|
||||||
:messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
|
:messagingServerAddress: The address of the ArtemisMQ broker instance. If not provided the node will run one locally.
|
||||||
|
|
||||||
:webAddress: The host and port on which the node is available for web operations.
|
:webAddress: The host and port on which the bundled webserver will listen if it is started.
|
||||||
|
|
||||||
.. note:: If HTTPS is enabled then the browser security checks will require that the accessing url host name is one
|
.. note:: If HTTPS is enabled then the browser security checks will require that the accessing url host name is one
|
||||||
of either the machine name, fully qualified machine name, or server IP address to line up with the Subject Alternative
|
of either the machine name, fully qualified machine name, or server IP address to line up with the Subject Alternative
|
||||||
Names contained within the development certificates. This is addition to requiring the ``/config/dev/corda_dev_ca.cer``
|
Names contained within the development certificates. This is addition to requiring the ``/config/dev/corda_dev_ca.cer``
|
||||||
root certificate be installed as a Trusted CA.
|
root certificate be installed as a Trusted CA.
|
||||||
|
|
||||||
|
.. note:: The driver will not automatically create a webserver instance, but the Cordformation will. If this field
|
||||||
|
is present the web server will start.
|
||||||
|
|
||||||
:extraAdvertisedServiceIds: A list of ServiceType id strings to be advertised to the NetworkMapService and thus be available
|
:extraAdvertisedServiceIds: A list of ServiceType id strings to be advertised to the NetworkMapService and thus be available
|
||||||
when other nodes query the NetworkMapCache for supporting nodes. This can also include plugin services loaded from .jar
|
when other nodes query the NetworkMapCache for supporting nodes. This can also include plugin services loaded from .jar
|
||||||
files in the plugins folder. Optionally, a custom advertised service name can be provided by appending it to the service
|
files in the plugins folder. Optionally, a custom advertised service name can be provided by appending it to the service
|
||||||
|
@ -34,21 +34,16 @@ of the node internal subsystems.
|
|||||||
extensions to be created, or registered at startup. In particular:
|
extensions to be created, or registered at startup. In particular:
|
||||||
|
|
||||||
a. The ``webApis`` property is a list of JAX-RS annotated REST access
|
a. The ``webApis`` property is a list of JAX-RS annotated REST access
|
||||||
classes. These classes will be constructed by the embedded web server
|
classes. These classes will be constructed by the bundled web server
|
||||||
and must have a single argument constructor taking a ``ServiceHub``
|
and must have a single argument constructor taking a ``CordaRpcOps``
|
||||||
reference. This reference provides access to functions such as querying
|
reference. This will allow it to communicate with the node process
|
||||||
for states through the ``VaultService`` interface, or access to the
|
via the RPC interface. These web APIs will not be available if the
|
||||||
``NetworkMapCache`` to identify services on remote nodes. The framework will
|
bundled web server is not started.
|
||||||
provide a database transaction in scope during the lifetime of the web
|
|
||||||
call, so full access to database data is valid. Unlike
|
|
||||||
``servicePlugins`` the ``webApis`` cannot register new protocols, or
|
|
||||||
initiate threads. (N.B. The intent is to move the Web support into a
|
|
||||||
separate helper process using the RPC mechanism to control access.)
|
|
||||||
|
|
||||||
b. The ``staticServeDirs`` property maps static web content to virtual
|
b. The ``staticServeDirs`` property maps static web content to virtual
|
||||||
paths and allows simple web demos to be distributed within the CorDapp
|
paths and allows simple web demos to be distributed within the CorDapp
|
||||||
jars. (N.B. The intent is to move the Web support into a separate helper
|
jars. These static serving directories will not be available if the
|
||||||
process using the RPC mechanism to control access.)
|
bundled web server is not started.
|
||||||
|
|
||||||
c. The ``requiredFlows`` property is used to declare new protocols in
|
c. The ``requiredFlows`` property is used to declare new protocols in
|
||||||
the plugin jar. Specifically the property must return a map with a key
|
the plugin jar. Specifically the property must return a map with a key
|
||||||
|
@ -12,10 +12,10 @@ App plugins
|
|||||||
To create an app plugin you must you must extend from `CordaPluginRegistry`_. The JavaDoc contains
|
To create an app plugin you must you must extend from `CordaPluginRegistry`_. The JavaDoc contains
|
||||||
specific details of the implementation, but you can extend the server in the following ways:
|
specific details of the implementation, but you can extend the server in the following ways:
|
||||||
|
|
||||||
1. Required flows: Specify which flows will be whitelisted for use in your web APIs.
|
1. Required flows: Specify which flows will be whitelisted for use in your RPC calls.
|
||||||
2. Service plugins: Register your services (see below).
|
2. Service plugins: Register your services (see below).
|
||||||
3. Web APIs: You may register your own endpoints under /api/ of the built-in web server.
|
3. Web APIs: You may register your own endpoints under /api/ of the bundled web server.
|
||||||
4. Static web endpoints: You may register your own static serving directories for serving web content.
|
4. Static web endpoints: You may register your own static serving directories for serving web content from the web server.
|
||||||
5. Registering your additional classes used in RPC.
|
5. Registering your additional classes used in RPC.
|
||||||
|
|
||||||
Services
|
Services
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
Node administration
|
Node administration
|
||||||
===================
|
===================
|
||||||
|
|
||||||
When a node is running, it exposes an embedded database server, an embedded web server that lets you monitor it,
|
When a node is running, it exposes an RPC interface that lets you monitor it,
|
||||||
you can upload and download attachments, access a REST API and so on.
|
you can upload and download attachments, access a REST API and so on. A bundled
|
||||||
|
Jetty web server exposes the same interface over HTTP.
|
||||||
|
|
||||||
Logging
|
Logging
|
||||||
-------
|
-------
|
||||||
|
@ -346,3 +346,11 @@ external legacy systems by insertion of unpacked data into existing
|
|||||||
tables. To enable these features the contract state must implement the
|
tables. To enable these features the contract state must implement the
|
||||||
``QueryableState`` interface to define the mappings.
|
``QueryableState`` interface to define the mappings.
|
||||||
|
|
||||||
|
Node Web Server
|
||||||
|
---------------
|
||||||
|
|
||||||
|
A web server comes bundled with the node by default, but is not started
|
||||||
|
automatically. This web server exposes both RPC backed API calls and
|
||||||
|
static content serving. The web server is not automatically started,
|
||||||
|
you must explicitly start it in the node driver or define a web port
|
||||||
|
in your `Cordformation`_ configuration.
|
||||||
|
@ -45,7 +45,8 @@ The most important fields regarding network configuration are:
|
|||||||
* ``artemisAddress``: This specifies a host and port. Note that the address bound will **NOT** be ``my-corda-node``,
|
* ``artemisAddress``: This specifies a host and port. Note that the address bound will **NOT** be ``my-corda-node``,
|
||||||
but rather ``::`` (all addresses on all interfaces). The hostname specified is the hostname *that must be externally
|
but rather ``::`` (all addresses on all interfaces). The hostname specified is the hostname *that must be externally
|
||||||
resolvable by other nodes in the network*. In the above configuration this is the resolvable name of a machine in a vpn.
|
resolvable by other nodes in the network*. In the above configuration this is the resolvable name of a machine in a vpn.
|
||||||
* ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress``.
|
* ``webAddress``: The address the webserver should bind. Note that the port should be distinct from that of ``artemisAddress``
|
||||||
|
if they are on the same machine.
|
||||||
* ``networkMapService``: Details of the node running the network map service. If it's this node that's running the service
|
* ``networkMapService``: Details of the node running the network map service. If it's this node that's running the service
|
||||||
then this field must not be specified.
|
then this field must not be specified.
|
||||||
|
|
||||||
@ -58,7 +59,9 @@ You should see a banner, some log lines and eventually ``Node started up and reg
|
|||||||
|
|
||||||
.. TODO: Add a better way of polling for startup. A programmatic way of determining whether a node is up is to check whether it's ``webAddress`` is bound.
|
.. TODO: Add a better way of polling for startup. A programmatic way of determining whether a node is up is to check whether it's ``webAddress`` is bound.
|
||||||
|
|
||||||
In terms of process management there is no prescribed method. You may start the jars by hand or perhaps use systemd and friends.
|
In terms of process management there is no prescribed method. You may start the jars by hand or perhaps use systemd and friends. If you have
|
||||||
|
deployed your nodes via `Cordformation`_ you can run them with the ``runnodes`` scripts in ``build/nodes`` of your project. This is primarily
|
||||||
|
for development and testing purposes and will start all of the nodes you have created on the same machine
|
||||||
|
|
||||||
Logging
|
Logging
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
@ -24,6 +24,16 @@ if which osascript >/dev/null; then
|
|||||||
first=false
|
first=false
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
for dir in `ls`; do
|
||||||
|
if [ -d $dir ]; then
|
||||||
|
cmd="bash -c 'cd $rootdir/$dir; /usr/libexec/java_home -v 1.8 --exec java -jar JAR_NAME --webserver && exit'"
|
||||||
|
script="$script
|
||||||
|
tell application \"System Events\" to tell process \"Terminal\" to keystroke \"t\" using command down
|
||||||
|
delay 0.5
|
||||||
|
do script \"$cmd\" in window 1"
|
||||||
|
first=false
|
||||||
|
fi
|
||||||
|
done
|
||||||
script="$script
|
script="$script
|
||||||
end tell"
|
end tell"
|
||||||
osascript -e "$script"
|
osascript -e "$script"
|
||||||
@ -39,6 +49,7 @@ else
|
|||||||
if [ -d $dir ]; then
|
if [ -d $dir ]; then
|
||||||
pushd $dir >/dev/null
|
pushd $dir >/dev/null
|
||||||
xterm -T "`basename $dir`" -e 'java -jar JAR_NAME' &
|
xterm -T "`basename $dir`" -e 'java -jar JAR_NAME' &
|
||||||
|
xterm -T "`basename $dir`" -e 'java -jar JAR_NAME --webserver' &
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
@ -6,6 +6,7 @@ Pushd %~dp0
|
|||||||
FOR /D %%G in (.\*) DO (
|
FOR /D %%G in (.\*) DO (
|
||||||
Pushd %%G
|
Pushd %%G
|
||||||
start java -jar corda.jar
|
start java -jar corda.jar
|
||||||
|
start java -jar corda.jar --webserver
|
||||||
Popd
|
Popd
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,7 +80,11 @@ fun main(args: Array<String>) {
|
|||||||
log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
|
log.info("VM ${info.vmName} ${info.vmVendor} ${info.vmVersion}")
|
||||||
log.info("Machine: ${InetAddress.getLocalHost().hostName}")
|
log.info("Machine: ${InetAddress.getLocalHost().hostName}")
|
||||||
log.info("Working Directory: ${cmdlineOptions.baseDirectory}")
|
log.info("Working Directory: ${cmdlineOptions.baseDirectory}")
|
||||||
log.info("Starting as webserver: ${cmdlineOptions.isWebserver}")
|
if(cmdlineOptions.isWebserver) {
|
||||||
|
log.info("Starting as webserver on ${conf.webAddress}")
|
||||||
|
} else {
|
||||||
|
log.info("Starting as node on ${conf.artemisAddress}")
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cmdlineOptions.baseDirectory.createDirectories()
|
cmdlineOptions.baseDirectory.createDirectories()
|
||||||
|
@ -17,7 +17,7 @@ import net.corda.core.utilities.loggerFor
|
|||||||
import net.corda.node.services.User
|
import net.corda.node.services.User
|
||||||
import net.corda.node.services.config.ConfigHelper
|
import net.corda.node.services.config.ConfigHelper
|
||||||
import net.corda.node.services.config.FullNodeConfiguration
|
import net.corda.node.services.config.FullNodeConfiguration
|
||||||
import net.corda.node.services.config.NodeSSLConfiguration
|
import net.corda.node.services.config.SSLConfiguration
|
||||||
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
import net.corda.node.services.messaging.ArtemisMessagingComponent
|
||||||
import net.corda.node.services.messaging.CordaRPCClient
|
import net.corda.node.services.messaging.CordaRPCClient
|
||||||
import net.corda.node.services.messaging.NodeMessagingClient
|
import net.corda.node.services.messaging.NodeMessagingClient
|
||||||
@ -327,7 +327,7 @@ open class DriverDSL(
|
|||||||
executorService.shutdown()
|
executorService.shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun queryNodeInfo(nodeAddress: HostAndPort, sslConfig: NodeSSLConfiguration): NodeInfo? {
|
private fun queryNodeInfo(nodeAddress: HostAndPort, sslConfig: SSLConfiguration): NodeInfo? {
|
||||||
var retries = 0
|
var retries = 0
|
||||||
while (retries < 5) try {
|
while (retries < 5) try {
|
||||||
val client = CordaRPCClient(nodeAddress, sslConfig)
|
val client = CordaRPCClient(nodeAddress, sslConfig)
|
||||||
@ -335,7 +335,7 @@ open class DriverDSL(
|
|||||||
val rpcOps = client.proxy(timeout = Duration.of(15, ChronoUnit.SECONDS))
|
val rpcOps = client.proxy(timeout = Duration.of(15, ChronoUnit.SECONDS))
|
||||||
return rpcOps.nodeIdentity()
|
return rpcOps.nodeIdentity()
|
||||||
} catch(e: Exception) {
|
} catch(e: Exception) {
|
||||||
log.debug("Retrying query node info at $nodeAddress")
|
log.error("Retrying query node info at $nodeAddress")
|
||||||
retries++
|
retries++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ abstract class AbstractNode(open val configuration: NodeConfiguration,
|
|||||||
customServices.addAll(buildPluginServices(tokenizableServices))
|
customServices.addAll(buildPluginServices(tokenizableServices))
|
||||||
|
|
||||||
val uploaders: List<FileUploader> = listOf(storageServices.first.attachments as NodeAttachmentService) +
|
val uploaders: List<FileUploader> = listOf(storageServices.first.attachments as NodeAttachmentService) +
|
||||||
customServices.filter { it is AcceptsFileUpload }.map { it as AcceptsFileUpload }
|
customServices.filterIsInstance(AcceptsFileUpload::class.java)
|
||||||
(storage as StorageServiceImpl).initUploaders(uploaders)
|
(storage as StorageServiceImpl).initUploaders(uploaders)
|
||||||
|
|
||||||
// TODO: uniquenessProvider creation should be inside makeNotaryService(), but notary service initialisation
|
// TODO: uniquenessProvider creation should be inside makeNotaryService(), but notary service initialisation
|
||||||
|
@ -78,10 +78,6 @@ class CordaRPCOpsImpl(
|
|||||||
return services.myInfo
|
return services.myInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ready(): Boolean {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addVaultTransactionNote(txnId: SecureHash, txnNote: String) {
|
override fun addVaultTransactionNote(txnId: SecureHash, txnNote: String) {
|
||||||
return databaseTransaction(database) {
|
return databaseTransaction(database) {
|
||||||
services.vaultService.addNoteToTransaction(txnId, txnNote)
|
services.vaultService.addNoteToTransaction(txnId, txnNote)
|
||||||
|
@ -30,7 +30,6 @@ import java.util.*
|
|||||||
class WebServer(val config: FullNodeConfiguration) {
|
class WebServer(val config: FullNodeConfiguration) {
|
||||||
private companion object {
|
private companion object {
|
||||||
val log = loggerFor<WebServer>()
|
val log = loggerFor<WebServer>()
|
||||||
val maxRetries = 60 // TODO: Make configurable
|
|
||||||
val retryDelay = 1000L // Milliseconds
|
val retryDelay = 1000L // Milliseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ class WebServer(val config: FullNodeConfiguration) {
|
|||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
printBasicNodeInfo("Starting as webserver: ${config.webAddress}")
|
printBasicNodeInfo("Starting as webserver: ${config.webAddress}")
|
||||||
server = initWebServer(connectLocalRpcWithRetries(maxRetries))
|
server = initWebServer(retryConnectLocalRpc())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
@ -78,10 +77,10 @@ class WebServer(val config: FullNodeConfiguration) {
|
|||||||
httpsConfiguration.outputBufferSize = 32768
|
httpsConfiguration.outputBufferSize = 32768
|
||||||
httpsConfiguration.addCustomizer(SecureRequestCustomizer())
|
httpsConfiguration.addCustomizer(SecureRequestCustomizer())
|
||||||
val sslContextFactory = SslContextFactory()
|
val sslContextFactory = SslContextFactory()
|
||||||
sslContextFactory.keyStorePath = config.keyStorePath.toString()
|
sslContextFactory.keyStorePath = config.keyStoreFile.toString()
|
||||||
sslContextFactory.setKeyStorePassword(config.keyStorePassword)
|
sslContextFactory.setKeyStorePassword(config.keyStorePassword)
|
||||||
sslContextFactory.setKeyManagerPassword(config.keyStorePassword)
|
sslContextFactory.setKeyManagerPassword(config.keyStorePassword)
|
||||||
sslContextFactory.setTrustStorePath(config.trustStorePath.toString())
|
sslContextFactory.setTrustStorePath(config.trustStoreFile.toString())
|
||||||
sslContextFactory.setTrustStorePassword(config.trustStorePassword)
|
sslContextFactory.setTrustStorePassword(config.trustStorePassword)
|
||||||
sslContextFactory.setExcludeProtocols("SSL.*", "TLSv1", "TLSv1.1")
|
sslContextFactory.setExcludeProtocols("SSL.*", "TLSv1", "TLSv1.1")
|
||||||
sslContextFactory.setIncludeProtocols("TLSv1.2")
|
sslContextFactory.setIncludeProtocols("TLSv1.2")
|
||||||
@ -153,20 +152,15 @@ class WebServer(val config: FullNodeConfiguration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun connectLocalRpcWithRetries(retries: Int): CordaRPCOps {
|
private fun retryConnectLocalRpc(): CordaRPCOps {
|
||||||
for(i in 0..retries - 1) {
|
while(true) {
|
||||||
try {
|
try {
|
||||||
log.info("Connecting to node at ${config.artemisAddress} as node user")
|
return connectLocalRpcAsNodeUser()
|
||||||
val client = CordaRPCClient(config.artemisAddress, config)
|
|
||||||
client.start(ArtemisMessagingComponent.NODE_USER, ArtemisMessagingComponent.NODE_USER)
|
|
||||||
return client.proxy()
|
|
||||||
} catch (e: ActiveMQNotConnectedException) {
|
} catch (e: ActiveMQNotConnectedException) {
|
||||||
log.debug("Could not connect to ${config.artemisAddress} due to exception: ", e)
|
log.debug("Could not connect to ${config.artemisAddress} due to exception: ", e)
|
||||||
Thread.sleep(retryDelay)
|
Thread.sleep(retryDelay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return connectLocalRpcAsNodeUser()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun connectLocalRpcAsNodeUser(): CordaRPCOps {
|
private fun connectLocalRpcAsNodeUser(): CordaRPCOps {
|
||||||
|
@ -12,12 +12,11 @@ class APIServerImpl(val rpcOps: CordaRPCOps) : APIServer {
|
|||||||
return LocalDateTime.ofInstant(rpcOps.currentNodeTime(), ZoneId.of("UTC"))
|
return LocalDateTime.ofInstant(rpcOps.currentNodeTime(), ZoneId.of("UTC"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This endpoint is for polling if the webserver is serving. It will always return 200.
|
||||||
|
*/
|
||||||
override fun status(): Response {
|
override fun status(): Response {
|
||||||
return if (rpcOps.ready()) {
|
return Response.ok("started").build()
|
||||||
Response.ok("started").build()
|
|
||||||
} else {
|
|
||||||
Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("not started").build()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun info() = rpcOps.nodeIdentity()
|
override fun info() = rpcOps.nodeIdentity()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user