Better error message if socket is taken

We need to communicate the error states in the thread, so I added a `Future[Unit]` called `ready`.

If something goes wrong during the startup, like if the port is already taken, this can be used to communicate back to the main thread, and display the error accordingly.
This commit is contained in:
Eugene Yokota 2017-04-12 18:31:50 -04:00
parent 6834def7b8
commit 0e8459ad66
2 changed files with 37 additions and 14 deletions

View File

@ -8,9 +8,13 @@ package server
import java.net.{ SocketTimeoutException, InetAddress, ServerSocket, Socket }
import java.util.concurrent.atomic.AtomicBoolean
import sbt.util.Logger
import sbt.internal.util.ErrorHandling
import scala.concurrent.{ Future, Promise }
import scala.util.{ Try, Success, Failure }
private[sbt] sealed trait ServerInstance {
def shutdown(): Unit
def ready: Future[Unit]
}
private[sbt] object Server {
@ -20,23 +24,31 @@ private[sbt] object Server {
// val lock = new AnyRef {}
// val clients: mutable.ListBuffer[ClientConnection] = mutable.ListBuffer.empty
val running = new AtomicBoolean(true)
val running = new AtomicBoolean(false)
val p: Promise[Unit] = Promise[Unit]()
val ready: Future[Unit] = p.future
val serverThread = new Thread("sbt-socket-server") {
override def run(): Unit = {
val serverSocket = new ServerSocket(port, 50, InetAddress.getByName(host))
serverSocket.setSoTimeout(5000)
log.info(s"sbt server started at $host:$port")
while (running.get()) {
try {
val socket = serverSocket.accept()
onIncomingSocket(socket)
} catch {
case _: SocketTimeoutException => // its ok
Try {
ErrorHandling.translate(s"server failed to start on $host:$port. ") {
new ServerSocket(port, 50, InetAddress.getByName(host))
}
} match {
case Failure(e) => p.failure(e)
case Success(serverSocket) =>
serverSocket.setSoTimeout(5000)
log.info(s"sbt server started at $host:$port")
running.set(true)
p.success(())
while (running.get()) {
try {
val socket = serverSocket.accept()
onIncomingSocket(socket)
} catch {
case _: SocketTimeoutException => // its ok
}
}
}
}
}

View File

@ -12,6 +12,9 @@ import scala.annotation.tailrec
import BasicKeys.serverPort
import java.net.Socket
import sjsonnew.JsonFormat
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import scala.util.{ Success, Failure }
/**
* The command exchange merges multiple command channels (e.g. network and console),
@ -81,7 +84,15 @@ private[sbt] final class CommandExchange {
server match {
case Some(x) => // do nothing
case _ =>
server = Some(Server.start("127.0.0.1", port, onIncomingSocket, s.log))
val x = Server.start("127.0.0.1", port, onIncomingSocket, s.log)
Await.ready(x.ready, Duration("10s"))
x.ready.value match {
case Some(Success(_)) =>
case Some(Failure(e)) =>
s.log.error(e.toString)
case None => // this won't happen because we awaited
}
server = Some(x)
}
s
}