This is an automated email from the ASF dual-hosted git repository.
aradzinski pushed a commit to branch NLPCRAFT-170
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
The following commit(s) were added to refs/heads/NLPCRAFT-170 by this push:
new 139a0c3 Update NCCli.scala
139a0c3 is described below
commit 139a0c39ab35c9ed233027941a8b3d770459fb6a
Author: Aaron Radzinski <[email protected]>
AuthorDate: Tue Dec 8 21:34:02 2020 -0800
Update NCCli.scala
---
.../nlpcraft/model/tools/cmdline/NCCli.scala | 339 ++++++++++++++++++++-
1 file changed, 330 insertions(+), 9 deletions(-)
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
index 797a00b..e79c878 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/tools/cmdline/NCCli.scala
@@ -546,7 +546,7 @@ object NCCli extends App {
}
}
- @volatile private val state = ReplState()
+ private val state = ReplState()
// Single CLI command.
case class Command(
@@ -1083,7 +1083,7 @@ object NCCli extends App {
synopsis = s"Starts local server.",
desc = Some(
s"Server is started in the external JVM process with both
stdout and stderr piped out into log file. " +
- s"Command will block until the server is started unless
${y("'--no-wait'")} parameter is used."
+ s"Command will block until the server is started unless
${y("'--no-wait'")} parameter is used or timeout is expired."
),
body = cmdStartServer,
params = Seq(
@@ -1116,6 +1116,14 @@ object NCCli extends App {
optional = true,
desc =
s"Instructs command not to wait for the server startup
and return immediately."
+ ),
+ Parameter(
+ id = "timeoutMins",
+ names = Seq("--timeout-mins", "-t"),
+ optional = true,
+ value = Some("3"),
+ desc =
+ s"Timeout in minutes to wait until server is started.
If not specified the default is 3 minutes."
)
),
examples = Seq(
@@ -1124,12 +1132,128 @@ object NCCli extends App {
desc = "Starts local server with default configuration."
),
Example(
- usage = Seq(s"$PROMPT $SCRIPT_NAME start-server
-c=/opt/nlpcraft/nlpcraft.conf"),
+ usage = Seq(s"$PROMPT $SCRIPT_NAME start-server
-c=/opt/nlpcraft/nlpcraft.conf -t=5"),
desc = "Starts local server with alternative configuration
file."
)
)
),
Command(
+ name = "start-probe",
+ group = "1. Server & Probe Commands",
+ synopsis = s"Starts local probe.",
+ desc = Some(
+ s"Probe is started in the external JVM process with both
stdout and stderr piped out into log file. " +
+ s"Command will block until the probe is started unless
${y("'--no-wait'")} parameter is used or timeout is expired."
+ ),
+ body = cmdStartProbe,
+ params = Seq(
+ Parameter(
+ id = "config",
+ names = Seq("--config", "-c"),
+ value = Some("path"),
+ optional = true,
+ desc =
+ s"Configuration absolute file path. Probe will
automatically look for ${y("'nlpcraft.conf'")} " +
+ s"configuration file in the same directory as NLPCraft
JAR file. If the configuration file has " +
+ s"different name or in different location use this
parameter to provide an alternative path. " +
+ s"Note that the server and the probe can use the same
file for their configuration."
+ ),
+ Parameter(
+ id = "cp",
+ names = Seq("--cp", "-p"),
+ value = Some("path"),
+ optional = true,
+ desc =
+ s"Additional JVM classpath component that will be
appended to the default JVM classpath. " +
+ s"Although this configuration property is optional,
when deploying your own models you will " +
+ s"need to provide classpath for all dependencies for
the models this probe will be hosting."
+ ),
+ Parameter(
+ id = "noWait",
+ names = Seq("--no-wait"),
+ optional = true,
+ desc =
+ s"Instructs command not to wait for the probe startup
and return immediately."
+ ),
+ Parameter(
+ id = "timeoutMins",
+ names = Seq("--timeout-mins", "-t"),
+ optional = true,
+ value = Some("3"),
+ desc =
+ s"Timeout to wait until probe is started. If not
specified the default is 3 minutes."
+ )
+ ),
+ examples = Seq(
+ Example(
+ usage = Seq(s"$PROMPT $SCRIPT_NAME start-probe"),
+ desc = "Starts local probe with default configuration."
+ ),
+ Example(
+ usage = Seq(s"$PROMPT $SCRIPT_NAME start-probe
-c=/opt/nlpcraft/nlpcraft.conf -p=/opt/classes"),
+ desc = "Starts local probe with alternative configuration
file."
+ )
+ )
+ ),
+ Command(
+ name = "restart-probe",
+ group = "1. Server & Probe Commands",
+ synopsis = s"Restarts local probe.",
+ desc = Some(
+ s"Probe is restarted in the external JVM process with both
stdout and stderr piped out into log file. " +
+ s"Command will block until the probe is started unless
${y("'--no-wait'")} parameter is used or timeout is expired."
+ ),
+ body = cmdRestartProbe,
+ params = Seq(
+ Parameter(
+ id = "config",
+ names = Seq("--config", "-c"),
+ value = Some("path"),
+ optional = true,
+ desc =
+ s"Configuration absolute file path. Probe will
automatically look for ${y("'nlpcraft.conf'")} " +
+ s"configuration file in the same directory as NLPCraft
JAR file. If the configuration file has " +
+ s"different name or in different location use this
parameter to provide an alternative path. " +
+ s"Note that the server and the probe can use the same
file for their configuration."
+ ),
+ Parameter(
+ id = "cp",
+ names = Seq("--cp", "-p"),
+ value = Some("path"),
+ optional = true,
+ desc =
+ s"Additional JVM classpath component that will be
appended to the default JVM classpath. " +
+ s"Although this configuration property is optional,
when deploying your own models you will " +
+ s"need to provide classpath for all dependencies for
the models this probe will be hosting."
+ ),
+ Parameter(
+ id = "noWait",
+ names = Seq("--no-wait"),
+ optional = true,
+ desc =
+ s"Instructs command not to wait for the probe startup
and return immediately."
+ ),
+ Parameter(
+ id = "timeoutMins",
+ names = Seq("--timeout-mins", "-t"),
+ optional = true,
+ value = Some("3"),
+ desc =
+ s"Timeout to wait until probe is started. If not
specified the default is 3 minutes."
+ )
+ ),
+ examples = Seq(
+ Example(
+ usage = Seq(s"$PROMPT $SCRIPT_NAME restart-probe"),
+ desc = "Starts local probe with default configuration."
+ ),
+ Example(
+ usage = Seq(s"$PROMPT $SCRIPT_NAME restart-probe
-c=/opt/nlpcraft/nlpcraft.conf -p=/opt/classes"),
+ desc = "Starts local probe with alternative configuration
file."
+ )
+ )
+ ),
+ Command(
name = "restart-server",
group = "1. Server & Probe Commands",
synopsis = s"Restarts local server.",
@@ -1168,15 +1292,23 @@ object NCCli extends App {
optional = true,
desc =
s"Instructs command not to wait for the server startup
and return immediately."
+ ),
+ Parameter(
+ id = "timeoutMins",
+ names = Seq("--timeout-mins", "-t"),
+ optional = true,
+ value = Some("3"),
+ desc =
+ s"Timeout in minutes to wait until server is started.
If not specified the default is 3 minutes."
)
),
examples = Seq(
Example(
- usage = Seq(s"$PROMPT $SCRIPT_NAME start-server"),
+ usage = Seq(s"$PROMPT $SCRIPT_NAME restart-server"),
desc = "Starts local server with default configuration."
),
Example(
- usage = Seq(s"$PROMPT $SCRIPT_NAME start-server
-c=/opt/nlpcraft/nlpcraft.conf"),
+ usage = Seq(s"$PROMPT $SCRIPT_NAME restart-server
-c=/opt/nlpcraft/nlpcraft.conf"),
desc = "Starts local server with alternative configuration
file."
)
)
@@ -1484,8 +1616,8 @@ object NCCli extends App {
private final val START_SRV_CMD = CMDS.find(_.name == "start-server").get
private final val SRV_INFO_CMD = CMDS.find(_.name == "info-server").get
private final val PRB_INFO_CMD = CMDS.find(_.name == "info-probe").get
-// private final val STOP_PRB_CMD = CMDS.find(_.name == "stop-probe").get
-// private final val START_PRB_CMD = CMDS.find(_.name == "start-probe").get
+ private final val STOP_PRB_CMD = CMDS.find(_.name == "stop-probe").get
+ private final val START_PRB_CMD = CMDS.find(_.name == "start-probe").get
/**
*
@@ -1545,6 +1677,16 @@ object NCCli extends App {
val cfgPath = args.find(_.parameter.id == "config")
val igniteCfgPath = args.find(_.parameter.id == "igniteConfig")
val noWait = args.exists(_.parameter.id == "noWait")
+ val timeoutMins = args.find(_.parameter.id == "timeoutMins") match {
+ case Some(arg) ⇒
+ try
+ Integer.parseInt(arg.value.get)
+ catch {
+ case _: Exception ⇒ throw InvalidParameter(cmd,
"timeoutMins")
+ }
+
+ case None ⇒ 3 // Default.
+ }
checkFilePath(cfgPath)
checkFilePath(igniteCfgPath)
@@ -1626,7 +1768,9 @@ object NCCli extends App {
val tbl = new NCAsciiTable()
tbl += (s"${g("stop-server")}", "Stop the server.")
- tbl += (s"${g("info-server")}", "Get server information.")
+ tbl += (s"${g("start-probe")}", "Start the probe.")
+ tbl += (s"${g("stop-probe")}", "Stop the probe.")
+ tbl += (s"${g("info")}", "Get server & probe information.")
tbl += (s"${g("restart-server")}", "Restart the server.")
tbl += (s"${g("ping-server")}", "Ping the server.")
tbl += (s"${g("tail-server")}", "Tail the server log.")
@@ -1674,7 +1818,7 @@ object NCCli extends App {
var beacon: NCCliServerBeacon = null
var online = false
- val endOfWait = currentTime + 3.mins // We try for 3 mins max.
+ val endOfWait = currentTime + timeoutMins.mins
while (currentTime < endOfWait && !online) {
if (progressBar.completed) {
@@ -1716,6 +1860,171 @@ object NCCli extends App {
}
/**
+ * @param cmd Command descriptor.
+ * @param args Arguments, if any, for this command.
+ * @param repl Whether or not running from REPL.
+ */
+ private def cmdStartProbe(cmd: Command, args: Seq[Argument], repl:
Boolean): Unit = {
+ val cfgPath = args.find(_.parameter.id == "config")
+ val noWait = args.exists(_.parameter.id == "noWait")
+ val addCp = args.exists(_.parameter.id == "cp")
+ val timeoutMins = args.find(_.parameter.id == "timeoutMins") match {
+ case Some(arg) ⇒
+ try
+ Integer.parseInt(arg.value.get)
+ catch {
+ case _: Exception ⇒ throw InvalidParameter(cmd,
"timeoutMins")
+ }
+
+ case None ⇒ 3 // Default.
+ }
+
+ checkFilePath(cfgPath)
+
+ // Ensure that there isn't another local probe running.
+ loadProbeBeacon() match {
+ case Some(b) ⇒ throw new IllegalStateException(s"Existing probe
(pid ${c(b.pid)}) detected.")
+ case None ⇒ ()
+ }
+
+ val logTstamp = currentTime
+
+ // Server log redirect.
+ val output = new File(SystemUtils.getUserHome,
s".nlpcraft/probe_log_$logTstamp.txt")
+
+ // Store in REPL state right away.
+ state.probeLog = Some(output)
+
+ val prbPb = new ProcessBuilder(
+ JAVA,
+ "-ea",
+ "-DNLPCRAFT_ANSI_COLOR_DISABLED=true", // No ANSI colors for text
log output to the file.
+ "-cp",
+ s"$JAVA_CP",
+ "org.apache.nlpcraft.NCStart",
+ "-probe",
+ cfgPath match {
+ case Some(path) ⇒ s"-config=${stripQuotes(path.value.get)}"
+ case None ⇒ ""
+ }
+ )
+
+ prbPb.directory(new File(INSTALL_HOME))
+ prbPb.redirectErrorStream(true)
+
+ val bleachPb = new ProcessBuilder(
+ JAVA,
+ "-ea",
+ "-cp",
+ s"$JAVA_CP",
+ "org.apache.nlpcraft.model.tools.cmdline.NCCliAnsiBleach"
+ )
+
+ bleachPb.directory(new File(INSTALL_HOME))
+ bleachPb.redirectOutput(Redirect.appendTo(output))
+
+ try {
+ // Start the 'probe | bleach > server log output' process pipeline.
+ val procs = ProcessBuilder.startPipeline(Seq(prbPb,
bleachPb).asJava)
+
+ val prbPid = procs.get(0).pid()
+
+ // Store mapping file between PID and timestamp (once we have
probe PID).
+ // Note that the same timestamp is used in probe log file.
+ ignoring(classOf[IOException]) {
+ new File(SystemUtils.getUserHome,
s".nlpcraft/.pid_${prbPid}_tstamp_$logTstamp").createNewFile()
+ }
+
+ logln(s"Probe output: ${c(output.getAbsolutePath)}")
+
+ /**
+ *
+ */
+ def showTip(): Unit = {
+ val tbl = new NCAsciiTable()
+
+ tbl += (s"${g("stop-probe")}", "Stop the probe.")
+ tbl += (s"${g("restart-probe")}", "Restart the server.")
+ tbl += (s"${g("info")}", "Get server & probe information.")
+
+ logln(s"Handy commands:\n${tbl.toString}")
+ }
+
+ if (noWait) {
+ logln(s"Probe is starting...")
+
+ showTip()
+ }
+ else {
+ val progressBar = new NCAnsiProgressBar(
+ term.writer(),
+ NUM_PRB_SERVICES,
+ 15,
+ true,
+ // ANSI is NOT disabled & we ARE NOT running from IDEA or
Eclipse...
+ NCAnsi.isEnabled && IS_SCRIPT
+ )
+
+ log(s"Probe is starting ")
+
+ progressBar.start()
+
+ // Tick progress bar "almost" right away to indicate the
progress start.
+ new Thread(() => {
+ Thread.sleep(1.secs)
+
+ progressBar.ticked()
+ })
+ .start()
+
+ val tailer = Tailer.create(
+ state.probeLog.get,
+ new TailerListenerAdapter {
+ override def handle(line: String): Unit = {
+ if (TAILER_PTRN.matcher(line).matches())
+ progressBar.ticked()
+ }
+ },
+ 500.ms
+ )
+
+ var beacon: NCCliProbeBeacon = null
+ var online = false
+ val endOfWait = currentTime + timeoutMins.mins
+
+ while (currentTime < endOfWait && !online) {
+ if (progressBar.completed) {
+ // First, load the beacon, if any.
+ if (beacon == null)
+ beacon = loadProbeBeacon().orNull
+ }
+
+ if (!online)
+ Thread.sleep(2.secs) // Check every 2 secs.
+ }
+
+ tailer.stop()
+
+ progressBar.stop()
+
+ if (!online) {
+ logln(r(" [Error]"))
+ error(s"Timed out starting probe, check output for
errors.")
+ }
+ else {
+ logln(g(" [OK]"))
+ logProbeInfo(beacon)
+
+ showTip()
+ }
+ }
+ }
+ catch {
+ case e: Exception ⇒ error(s"Probe failed to start:
${y(e.getLocalizedMessage)}")
+ }
+ }
+
+ /**
*
* @return
*/
@@ -2057,6 +2366,18 @@ object NCCli extends App {
* @param args Arguments, if any, for this command.
* @param repl Whether or not executing from REPL.
*/
+ private def cmdRestartProbe(cmd: Command, args: Seq[Argument], repl:
Boolean): Unit = {
+ if (loadProbeBeacon().isDefined)
+ STOP_PRB_CMD.body(STOP_PRB_CMD, Seq.empty, repl)
+
+ START_PRB_CMD.body(START_PRB_CMD, args, repl)
+ }
+
+ /**
+ * @param cmd Command descriptor.
+ * @param args Arguments, if any, for this command.
+ * @param repl Whether or not executing from REPL.
+ */
private def cmdStopServer(cmd: Command, args: Seq[Argument], repl:
Boolean): Unit =
loadServerBeacon() match {
case Some(beacon) ⇒