scala.tools.nsc.fsc.SocketServer.scala Maven / Gradle / Ivy
The newest version!
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.tools.nsc.fsc
import scala.tools.util.SystemExit
import java.io.{BufferedReader, PrintStream, PrintWriter}
import java.net.{ServerSocket, SocketException, SocketTimeoutException}
import scala.annotation.tailrec
trait CompileOutputCommon {
def verbose: Boolean
def info(msg: String) = if (verbose) echo(msg)
def echo(msg: String) = printlnFlush(msg, Console.out)
def warn(msg: String) = printlnFlush(msg, Console.err)
def fatal(msg: String) = { warn(msg) ; throw SystemExit(1) }
private def printlnFlush(msg: String, out: PrintStream) = {
out.println(msg)
out.flush()
}
}
/** The abstract class SocketServer implements the server
* communication for the fast Scala compiler.
*
* @author Martin Odersky
*/
abstract class SocketServer(fixPort: Int = 0) extends CompileOutputCommon {
def shutdown: Boolean
def session(): Unit
def timeout(): Unit = () // called after a timeout is detected for subclasses to cleanup
// a hook for subclasses
protected def createServerSocket(): ServerSocket = new ServerSocket(fixPort)
var in: BufferedReader = _
var out: PrintWriter = _
val BufferSize = 10240
lazy val serverSocket = createServerSocket()
lazy val port = serverSocket.getLocalPort()
// Default to 30 minute idle timeout, settable with -max-idle
protected var idleMinutes = 30
private var savedTimeout = 0
private val acceptBox = new Socket.Box(() => {
// update the timeout if it has changed
if (savedTimeout != idleMinutes) {
savedTimeout = idleMinutes
setTimeoutOnSocket(savedTimeout)
}
new Socket(serverSocket.accept())
})
private def setTimeoutOnSocket(mins: Int) = {
try {
serverSocket setSoTimeout (mins * 60 * 1000)
info("Set socket timeout to " + mins + " minutes.")
true
}
catch {
case ex: SocketException =>
warn("Failed to set socket timeout: " + ex)
false
}
}
def doSession(clientSocket: Socket) = {
clientSocket.applyReaderAndWriter { (in, out) =>
this.in = in
this.out = out
val bufout = clientSocket.bufferedOutput(BufferSize)
try scala.Console.withOut(bufout)(session())
finally bufout.close()
}
}
def run(): Unit = {
info("Starting SocketServer run() loop.")
@tailrec
def loop(): Unit = {
acceptBox.either match {
case Right(clientSocket) =>
try doSession(clientSocket)
finally clientSocket.close()
case Left(_: SocketTimeoutException) =>
warn("Idle timeout exceeded on port %d; exiting" format port)
timeout()
return
case _ =>
warn(s"Accept on port $port failed")
}
if (!shutdown)
loop()
}
try loop()
catch { case ex: SocketException => fatal("Compile server caught fatal exception: " + ex) }
finally serverSocket.close()
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy