This is an automated email from the ASF dual-hosted git repository.
aradzinski pushed a commit to branch NLPCRAFT-108
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
The following commit(s) were added to refs/heads/NLPCRAFT-108 by this push:
new ee4fcae WIP.
ee4fcae is described below
commit ee4fcaef3d991de74632d40342460567c4d50b77
Author: Aaron Radzinski <[email protected]>
AuthorDate: Sun Oct 4 23:03:49 2020 -0700
WIP.
---
.../nlpcraft/common/ansi/NCAnsiProgressBar.scala | 140 ++++++++++++++++
.../nlpcraft/common/ansi/NCAnsiSpinner.scala | 72 ++++----
.../scala/org/apache/nlpcraft/common/package.scala | 75 +++++++++
.../org/apache/nlpcraft/common/util/NCUtils.scala | 81 ---------
.../nlpcraft/model/tools/cmdline/NCCli.scala | 185 ++++++++++++---------
.../nlpcraft/server/probe/NCProbeManager.scala | 2 +-
6 files changed, 366 insertions(+), 189 deletions(-)
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiProgressBar.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiProgressBar.scala
new file mode 100644
index 0000000..73659b2
--- /dev/null
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiProgressBar.scala
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nlpcraft.common.ansi
+
+import java.io.PrintWriter
+
+import NCAnsi._
+import org.apache.nlpcraft.common.ansi.NCAnsiProgressBar._
+
+/**
+ * Forward-only, bound ANSI-based progress bar.
+ *
+ * @param out
+ * @param totalTicks Number of ticks to complete.
+ * @param dispSize Visual size of the progress bar.
+ * @param clearOnComplete
+ * @param useAnsi
+ */
+class NCAnsiProgressBar(
+ out: PrintWriter,
+ totalTicks: Int,
+ dispSize: Int,
+ clearOnComplete: Boolean = true,
+ useAnsi: Boolean = true) {
+ require(dispSize <= totalTicks)
+
+ @volatile private var tick = 0
+
+ //noinspection ZeroIndexToHead
+ private final val PB_LEFT = s"$ansiBlueFg${CHAR_SET(0)}$ansiReset"
+ private final val PB_RIGHT = s"$ansiBlueFg${CHAR_SET(3)}$ansiReset"
+ private final val PB_EMPTY =s"$ansiWhiteFg${CHAR_SET(2)}$ansiReset"
+ private final val PB_FULL = s"$ansiRedFg$ansiBold${CHAR_SET(1)}$ansiReset"
+
+ /**
+ *
+ */
+ private def clean(): Unit = {
+ out.print(ansiCursorLeft * (dispSize + 2))
+ out.print(ansiClearLineAfter)
+ out.flush()
+ }
+
+ /**
+ * Starts progress bar.
+ */
+ def start(): Unit = {
+ tick = 0
+
+ if (useAnsi) {
+ // Hide cursor to avoid blinking.
+ out.print(ansiCursorHide)
+
+ out.print(PB_LEFT)
+ out.print(PB_EMPTY * dispSize)
+ out.print(PB_RIGHT)
+
+ out.flush()
+ }
+ }
+
+ /**
+ * Ticks progress bar one tick at a time.
+ */
+ def ticked(): Unit = {
+ tick += 1
+
+ if (useAnsi) {
+ clean()
+
+ val bar = Math.round((tick.toFloat / totalTicks.toFloat) *
dispSize)
+
+ out.print(PB_LEFT)
+ for (i ← 0 until dispSize)
+ out.print(if (i < bar) PB_FULL else PB_EMPTY)
+ out.print(PB_RIGHT)
+ out.flush()
+ }
+ else if (tick % (totalTicks / dispSize) == 0) {
+ out.print(NON_ANSI_CHAR)
+ out.flush()
+ }
+ }
+
+ /**
+ * Whether progress is complete.
+ *
+ * @return
+ */
+ def completed: Boolean =
+ tick == totalTicks
+
+ /**
+ * Stops progress bar.
+ */
+ def stop(): Unit = {
+ if (useAnsi && clearOnComplete) {
+ clean()
+
+ // Show cursor.
+ out.print(ansiCursorShow)
+ out.flush()
+ }
+ }
+}
+
+/**
+ *
+ */
+object NCAnsiProgressBar{
+ // Set of UNICODE charsets options for the progress bar.
+ private final val PB_CHAR_SETS = Seq(
+ Seq('[', '=', '.', ']'),
+ Seq('/', '▰', '▱', '/'),
+ Seq('[', '▰', '▱', ']'),
+ Seq('[', '◼', '◽', ']'),
+ Seq('[', '█', '_', ']'),
+ Seq('⟮', '▰', '.', '⟯')
+ )
+
+ private final val NON_ANSI_CHAR = '='
+
+ // Active charset to use.
+ private val CHAR_SET = PB_CHAR_SETS(5)
+}
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiSpinner.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiSpinner.scala
index b1ae4bb..fe8733c 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiSpinner.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/ansi/NCAnsiSpinner.scala
@@ -18,38 +18,23 @@
package org.apache.nlpcraft.common.ansi
import java.io.PrintWriter
-import java.util.Random
import NCAnsi._
import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.common.ansi.NCAnsiSpinner.RND
+import org.apache.nlpcraft.common.ansi.NCAnsiSpinner._
/**
+ * ANSI-based hourglass spinner.
*
+ * @param out
+ * @param useAnsi
*/
-class NCAnsiSpinner(out: PrintWriter, ansiColor: String = ansiCyanFg, useAnsi:
Boolean = true) {
- @volatile var thread: Thread = _
-
- final val SPIN_CHAR_SETS = Seq(
- Seq('-', '\\', '|', '/'),
- Seq('.', 'o', 'O', '@', '*'),
- Seq('←', '↖', '↑', '↗', '→', '↘', '↓', '↙'),
- Seq('▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃',
'▁'),
- Seq('▖', '▘', '▝', '▗'),
- Seq('┤', '┘', '┴', '└', '├', '┌', '┬', '┐'),
- Seq('◢', '◣', '◤', '◥'),
- Seq('◰', '◳', '◲', '◱'),
- Seq('◴', '◷', '◶', '◵'),
- Seq('◐', '◓', '◑', '◒'),
- Seq('◡', '⊙', '◠', '⊙'),
- Seq('⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'),
- Seq('⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈')
- )
-
- private var suffix = ""
- private var prefix = ""
- private var lastLength = 0
- private var frame = 0
+class NCAnsiSpinner(out: PrintWriter, useAnsi: Boolean = true) {
+ @volatile private var thread: Thread = _
+ @volatile private var suffix = ""
+ @volatile private var prefix = ""
+ @volatile private var lastLength = 0
+ @volatile private var frame = 0
/**
*
@@ -75,7 +60,7 @@ class NCAnsiSpinner(out: PrintWriter, ansiColor: String =
ansiCyanFg, useAnsi: B
}
/**
- *
+ * Starts spinner.
*/
def start(): Unit =
if (useAnsi) {
@@ -83,8 +68,6 @@ class NCAnsiSpinner(out: PrintWriter, ansiColor: String =
ansiCyanFg, useAnsi: B
frame = 0
lastLength = 0
- val chars = SPIN_CHAR_SETS(RND.nextInt(SPIN_CHAR_SETS.size))
-
// Hide cursor to avoid blinking.
out.print(ansiCursorHide)
out.flush()
@@ -93,24 +76,26 @@ class NCAnsiSpinner(out: PrintWriter, ansiColor: String =
ansiCyanFg, useAnsi: B
if (frame > 0)
clean()
- out.print(s"$prefix$ansiColor${chars(frame %
chars.size)}$ansiReset$suffix")
+ out.print(s"$prefix$ansiCyanFg${CHAR_SET(frame %
CHAR_SET.size)}$ansiReset$suffix")
out.flush()
lastLength = U.stripAnsi(prefix).length + 1 +
U.stripAnsi(suffix).length
frame += 1
- Thread.sleep(200)
+ Thread.sleep(CHAR_SET.size.fps) // Full rotation per
second.
}
}
thread.start()
}
- else
+ else {
out.print("... ")
+ out.flush()
+ }
/**
- *
+ * Stops spinner.
*/
def stop(): Unit = {
U.stopThread(thread)
@@ -125,6 +110,27 @@ class NCAnsiSpinner(out: PrintWriter, ansiColor: String =
ansiCyanFg, useAnsi: B
}
}
+/**
+ *
+ */
object NCAnsiSpinner {
- private val RND = new Random()
+ // Set of UNICODE charset options for the spinner.
+ private final val SPIN_CHAR_SETS = Seq(
+ Seq('-', '\\', '|', '/'),
+ Seq('.', 'o', 'O', '@', '*'),
+ Seq('←', '↖', '↑', '↗', '→', '↘', '↓', '↙'),
+ Seq('▁', '▂', '▃', '▄', '▅', '▆', '▇', '█', '▇', '▆', '▅', '▄', '▃',
'▁'),
+ Seq('▖', '▘', '▝', '▗'),
+ Seq('┤', '┘', '┴', '└', '├', '┌', '┬', '┐'),
+ Seq('◢', '◣', '◤', '◥'),
+ Seq('◰', '◳', '◲', '◱'),
+ Seq('◴', '◷', '◶', '◵'),
+ Seq('◐', '◓', '◑', '◒'),
+ Seq('◡', '⊙', '◠', '⊙'),
+ Seq('⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'),
+ Seq('⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈')
+ )
+
+ // An active charset to use.
+ private final val CHAR_SET = SPIN_CHAR_SETS.head
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/package.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/package.scala
index fadf539..d266c4b 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/package.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/package.scala
@@ -64,6 +64,81 @@ package object common {
def bo(s: Any): String = s"$ansiBold${s.toString}$ansiReset"
/**
+ * Pimps integers with KB, MB, GB units of measure.
+ *
+ * @param v Integer value.
+ */
+ implicit class IntMemoryUnits(v: Int) {
+ def TB: Int = v * 1024 * 1024 * 1024 * 1024
+ def GB: Int = v * 1024 * 1024 * 1024
+ def MB: Int = v * 1024 * 1024
+ def KB: Int = v * 1024
+ def tb: Int = TB
+ def gb: Int = GB
+ def mb: Int = MB
+ def kb: Int = KB
+ }
+
+ /**
+ * Pimps longs with KB, MB, GB units of measure.
+ *
+ * @param v Long value.
+ */
+ implicit class LongMemoryUnits(v: Long) {
+ def TB: Long = v * 1024 * 1024 * 1024 * 1024
+ def GB: Long = v * 1024 * 1024 * 1024
+ def MB: Long = v * 1024 * 1024
+ def KB: Long = v * 1024
+ def tb: Long = TB
+ def gb: Long = GB
+ def mb: Long = MB
+ def kb: Long = KB
+ }
+
+
+ /**
+ * Pimps integers with time units.
+ *
+ * @param v Integer value.
+ */
+ implicit class IntTimeUnits(v: Int) {
+ def MSECS: Int = v
+ def MS: Int = v
+ def SECS: Int = v * 1000
+ def MINS: Int = v * 1000 * 60
+ def HOURS: Int = v * 1000 * 60 * 60
+ def DAYS: Int = v * 1000 * 60 * 60 * 24
+ def FPS: Int = 1000 / v
+ def ms: Int = MS
+ def secs: Int = SECS
+ def mins: Int = MINS
+ def hours: Int = HOURS
+ def days: Int = DAYS
+ def fps: Int = 1000 / v
+ }
+
+ /**
+ * Pimps long with time units.
+ *
+ * @param v Long value.
+ */
+ implicit class LongTimeUnits(v: Long) {
+ def MSECS: Long = v
+ def MS: Long = v
+ def SECS: Long = v * 1000
+ def MINS: Long = v * 1000 * 60
+ def HOURS: Long = v * 1000 * 60 * 60
+ def DAYS: Long = v * 1000 * 60 * 60 * 24
+ def FPS: Long = 1000 / v
+ def ms: Long = MS
+ def secs: Long = SECS
+ def mins: Long = MINS
+ def hours: Long = HOURS
+ def days: Long = DAYS
+ def fps: Long = 1000 / v
+ }
+
+ /**
*
* @param f
* @tparam T
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
index 4e37c20..1742da9 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/common/util/NCUtils.scala
@@ -1053,87 +1053,6 @@ object NCUtils extends LazyLogging {
IOUtils.toString(new GIS(new
ByteArrayInputStream(Base64.decodeBase64(zipStr))), Charset.defaultCharset())
/**
- * Pimps integers with KB, MB, GB units of measure.
- *
- * @param v Integer value.
- */
- implicit class IntMemoryUnits(v: Int) {
- def TB: Int = v * 1024 * 1024 * 1024 * 1024
- def GB: Int = v * 1024 * 1024 * 1024
- def MB: Int = v * 1024 * 1024
- def KB: Int = v * 1024
- def tb: Int = TB
- def gb: Int = GB
- def mb: Int = MB
- def kb: Int = KB
- }
-
- /**
- * Pimps longs with KB, MB, GB units of measure.
- *
- * @param v Long value.
- */
- implicit class LongMemoryUnits(v: Long) {
- def TB: Long = v * 1024 * 1024 * 1024 * 1024
- def GB: Long = v * 1024 * 1024 * 1024
- def MB: Long = v * 1024 * 1024
- def KB: Long = v * 1024
- def tb: Long = TB
- def gb: Long = GB
- def mb: Long = MB
- def kb: Long = KB
- }
-
-
- /**
- * Pimps integers with time units.
- *
- * @param v Integer value.
- */
- implicit class IntTimeUnits(v: Int) {
- def MSECS: Int = v
- def MS: Int = v
- def SECS: Int = v * 1000
- def MINS: Int = v * 1000 * 60
- def HOURS: Int = v * 1000 * 60 * 60
- def DAYS: Int = v * 1000 * 60 * 60 * 24
- def ms: Int = MS
- def secs: Int = SECS
- def mins: Int = MINS
- def hours: Int = HOURS
- def days: Int = DAYS
- }
-
- /**
- * Pimps long with time units.
- *
- * @param v Long value.
- */
- implicit class LongTimeUnits(v: Long) {
- def MSECS: Long = v
-
- def MS: Long = v
-
- def SECS: Long = v * 1000
-
- def MINS: Long = v * 1000 * 60
-
- def HOURS: Long = v * 1000 * 60 * 60
-
- def DAYS: Long = v * 1000 * 60 * 60 * 24
-
- def ms: Long = MS
-
- def secs: Long = SECS
-
- def mins: Long = MINS
-
- def hours: Long = HOURS
-
- def days: Long = DAYS
- }
-
- /**
* Sleeps number of milliseconds properly handling exceptions.
*
* @param delay Number of milliseconds to sleep.
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 dcf8811..9363703 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
@@ -17,8 +17,6 @@
package org.apache.nlpcraft.model.tools.cmdline
-import java.io.{File, FileInputStream, IOException, ObjectInputStream}
-
import com.google.gson._
import javax.net.ssl.SSLException
import org.apache.commons.lang3.SystemUtils
@@ -30,7 +28,7 @@ import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.HttpClients
import org.apache.nlpcraft.common.ascii.NCAsciiTable
import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.common.ansi.{NCAnsi, NCAnsiSpinner}
+import org.apache.nlpcraft.common.ansi.{NCAnsi, NCAnsiProgressBar,
NCAnsiSpinner}
import org.apache.nlpcraft.common.ansi.NCAnsi._
import org.apache.nlpcraft.common.version.NCVersion
import java.lang.ProcessBuilder.Redirect
@@ -38,9 +36,10 @@ import java.lang.management.ManagementFactory
import java.text.DateFormat
import java.util
import java.util.Date
-import java.util.regex.PatternSyntaxException
+import java.io._
+import java.util.regex.{Pattern, PatternSyntaxException}
-import org.apache.nlpcraft.common.util.NCUtils.IntTimeUnits
+import org.apache.commons.io.input.{Tailer, TailerListenerAdapter}
import org.jline.reader.Completer
import org.jline.reader.impl.DefaultParser
import org.jline.terminal.{Terminal, TerminalBuilder}
@@ -63,8 +62,18 @@ import scala.util.control.Exception.ignoring
object NCCli extends App {
private final val NAME = "Apache NLPCraft CLI"
+ //noinspection RegExpRedundantEscape\
+ private final val TAILER_PTRN = Pattern.compile("^.*NC[a-zA-Z0-9]+ started
\\[[\\d]+ms\\]$")
+
+ // Number of server services that need to be started.
+ // Used for progress bar functionality.
+ // +==================================================================+
+ // | MAKE SURE TO UPDATE THIS VAR WHEN NUMBER OF SERVICES IS CHANGED. |
+ // +==================================================================+
+ private final val NUM_SRV_SERVICES = 30
+
private final val SRV_BEACON_PATH = ".nlpcraft/server_beacon"
- private final val HIST_PATH = ".nlpcraft/cli_history"
+ private final val HIST_PATH = ".nlpcraft/.cli_history"
private final lazy val VER = NCVersion.getCurrent
private final lazy val JAVA = U.sysEnv("NLPCRAFT_CLI_JAVA").getOrElse(new
File(SystemUtils.getJavaHome,s"bin/java${if (SystemUtils.IS_OS_UNIX) "" else
".exe"}").getAbsolutePath)
@@ -88,12 +97,13 @@ object NCCli extends App {
case class SplitError(index: Int) extends Exception
- case class State(
- var isServer: Boolean,
- var accessToken: Option[String]
+ case class ReplState(
+ var isServerOnline: Boolean = false,
+ var accessToken: Option[String] = None,
+ var serverOutput: Option[File] = None
)
- private val state = State(isServer = false, None)
+ private val replState = ReplState()
// Single CLI command.
case class Command(
@@ -215,15 +225,6 @@ object NCCli extends App {
s"provide an alternative path."
),
Parameter(
- id = "output",
- names = Seq("--output-path", "-o"),
- value = Some("path"),
- optional = true,
- desc =
- "File path for both REST server stdout and stderr
output. If not provided, the REST server" +
- s"output will be piped into
${y("${USER_HOME}/.nlpcraft/server-output-xxx.txt")}' file."
- ),
- Parameter(
id = "noWait",
names = Seq("--no-wait"),
optional = true,
@@ -469,19 +470,24 @@ 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 output = args.find(_.parameter.id == "output") match {
- case Some(arg) ⇒ new File(stripQuotes(arg.value.get))
- case None ⇒ new File(SystemUtils.getUserHome,
s".nlpcraft/server-output-$currentTime.txt")
- }
checkFilePath(cfgPath)
checkFilePath(igniteCfgPath)
+ // Ensure that there isn't another local server running.
loadServerBeacon() match {
case Some(b) ⇒ throw new IllegalStateException(s"Existing local
server (pid ${c(b.pid)}) detected.")
case None ⇒ ()
}
+ val logTstamp = currentTime
+
+ // Server log redirect.
+ val output = new File(SystemUtils.getUserHome,
s".nlpcraft/server_log_$logTstamp.txt")
+
+ // Store in REPL state right away.
+ replState.serverOutput = Some(output)
+
val srvPb = new ProcessBuilder(
JAVA,
"-ea",
@@ -525,59 +531,98 @@ object NCCli extends App {
bleachPb.redirectOutput(Redirect.appendTo(output))
try {
- // Start the 'server | bleach' process pipeline.
- ProcessBuilder.startPipeline(Seq(srvPb, bleachPb).asJava)
+ // Start the 'server | bleach > server log output' process
pipeline.
+ val procs = ProcessBuilder.startPipeline(Seq(srvPb,
bleachPb).asJava)
+
+ val srvPid = procs.get(0).pid()
+
+ // Store mapping file between PID and timestamp (once we have
server PID).
+ // Note that the same timestamp is used in server log file.
+ ignoring(classOf[IOException]) {
+ new File(SystemUtils.getUserHome,
s".nlpcraft/.pid_${srvPid}_tstamp_$logTstamp").createNewFile()
+ }
+
+ logln(s"Server output ⇒ ${c(output.getAbsolutePath)}")
- logln(s"Server output > ${c(output.getAbsolutePath)}")
+ /**
+ *
+ */
+ def showTip(): Unit = {
+ val tbl = new NCAsciiTable()
+
+ tbl += (s"${g("stop-server")}", "Stop the server.")
+ tbl += (s"${g("get-server")}", "Get server information.")
+ tbl += (s"${g("restart-server")}", "Restart the server.")
+ tbl += (s"${g("less-server")}", "Tail server log.")
+ tbl += (s"${g("ping-server")}", "Ping the server.")
+
+ logln(s"Handy commands:\n${tbl.toString}")
+ }
- if (noWait)
+ if (noWait) {
logln(s"Server is starting...")
+
+ showTip()
+ }
else {
+ val progressBar = new NCAnsiProgressBar(
+ term.writer(),
+ NUM_SRV_SERVICES,
+ 15,
+ true,
+ // ANSI is NOT disabled & we ARE NOT running from IDEA or
Eclipse...
+ NCAnsi.isEnabled && IS_SCRIPT
+ )
+
log(s"Server is starting ")
- var beacon = loadServerBeacon().orNull
- var online = false
- val spinner = mkSpinner()
- val timeout = currentTime + 5.mins
- val warnTimeout = currentTime + 60.secs
+ progressBar.start()
+
+ U.mkThread("server-start-progress-bar") { _ ⇒
+ Tailer.create(
+ replState.serverOutput.get,
+ new TailerListenerAdapter {
+ override def handle(line: String): Unit =
+ if (TAILER_PTRN.matcher(line).matches())
+ progressBar.ticked()
+ },
+ 500.ms
+ )
+ }
+ .start()
- spinner.start()
+ var beacon: NCCliServerBeacon = null
+ var online = false
+ val endOfWait = currentTime + 3.mins // We try for 3 mins max.
- while (currentTime < timeout && !online) {
- if (beacon == null)
- beacon = loadServerBeacon().orNull
- else
- online = Try(restHealth("http://" +
beacon.restEndpoint) == 200).getOrElse(false)
+ while (currentTime < endOfWait && !online) {
+ if (progressBar.completed) {
+ // First, load the beacon, if any.
+ if (beacon == null)
+ beacon = loadServerBeacon().orNull
- if (!online) {
- if (currentTime > warnTimeout)
- // Warn if it's taking too long.
- spinner.setSuffix(s" ${r("(taking too long - check
logs)")}")
+ // Once beacon is loaded, ensure that REST endpoint is
live.
+ if (beacon != null)
+ online = Try(restHealth("http://" +
beacon.restEndpoint) == 200).getOrElse(false)
+ }
+ if (!online)
Thread.sleep(2.secs) // Check every 2 secs.
- }
}
- spinner.stop()
+ progressBar.stop()
if (!online) {
- logln()
- error(s"Cannot detect live server.")
- error(s"Check output for errors:
${c(output.getAbsolutePath)}")
+ logln(r(" [Error]"))
+ error(s"Failed to start server, check output for errors.")
}
else {
- logln(g("OK"))
+ logln(g(" [OK]"))
logln(mkServerBeaconTable(beacon).toString)
+
+ showTip()
}
}
-
- val tbl = new NCAsciiTable()
-
- tbl += (s"${g("stop-server")}", "Stop the server.")
- tbl += (s"${g("ping-server")}", "Ping the server.")
- tbl += (s"${g("get-server")}", "Get server information.")
-
- logln(s"Handy commands:\n${tbl.toString}")
}
catch {
case e: Exception ⇒ error(s"Server failed to start:
${y(e.getLocalizedMessage)}")
@@ -585,18 +630,6 @@ object NCCli extends App {
}
/**
- * Makes default spinner.
- *
- * @return
- */
- private def mkSpinner() = new NCAnsiSpinner(
- term.writer(),
- ansiCyanFg,
- // ANSI is NOT disabled & we ARE NOT running from IDEA or Eclipse...
- NCAnsi.isEnabled && IS_SCRIPT
- )
-
- /**
*
* @return
*/
@@ -630,7 +663,11 @@ object NCCli extends App {
while (i < num) {
log(s"(${i + 1} of $num) pinging REST server at ${b(endpoint)} ")
- val spinner = mkSpinner()
+ val spinner = new NCAnsiSpinner(
+ term.writer(),
+ // ANSI is NOT disabled & we ARE NOT running from IDEA or
Eclipse...
+ NCAnsi.isEnabled && IS_SCRIPT
+ )
spinner.start()
@@ -704,7 +741,7 @@ object NCCli extends App {
case _: Exception ⇒ None
}
- state.isServer = beacon.isDefined
+ replState.isServerOnline = beacon.isDefined
beacon
}
@@ -732,7 +769,7 @@ object NCCli extends App {
logln(s"Local REST server (pid ${c(pid)}) has been
stopped.")
// Update state right away.
- state.isServer = false
+ replState.isServerOnline = false
} else
error(s"Failed to stop the local REST server (pid
${c(pid)}).")
@@ -1040,8 +1077,8 @@ object NCCli extends App {
while (!exit) {
val rawLine = try {
- val srvStr = bo(s"${if (state.isServer) s"ON " else s"OFF "}")
- val acsTokStr = bo(s"${state.accessToken.getOrElse("")} ")
+ val srvStr = bo(s"${if (replState.isServerOnline) s"ON " else
s"OFF "}")
+ val acsTokStr = bo(s"${replState.accessToken.getOrElse("")} ")
reader.printAbove("\n" + rb(w(s" server: $srvStr")) + wb(k(s"
acsTok: $acsTokStr")))
reader.readLine(s"${g("\u25b6")} ")
@@ -1146,7 +1183,7 @@ object NCCli extends App {
*/
private def unknownCommand(cmd: String): Unit = {
error(s"Unknown command: ${y(cmd)}")
- error(s"Use '${c("help")}' command to read the manual.")
+ error(s"Type '${c("help")}' to read the manual.")
}
/**
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala
index aad300e..bb19c26 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/server/probe/NCProbeManager.scala
@@ -360,7 +360,7 @@ object NCProbeManager extends NCService {
srv.bind(new InetSocketAddress(host, port))
- logger.info(s"$name connection is on '$host:$port'")
+ logger.trace(s"$name connection is on '$host:$port'")
srv.setSoTimeout(Config.soTimeoutMs)