All Downloads are FREE. Search and download functionalities are using the official Maven repository.

almond.launcher.LauncherOutputHandler.scala Maven / Gradle / Ivy

The newest version!
package almond.launcher

import almond.interpreter.api.OutputHandler
import almond.interpreter.util.DisplayDataOps._

import java.util.concurrent.LinkedBlockingQueue
import almond.interpreter.Message
import almond.protocol.RawJson
import almond.protocol.Execute
import cats.effect.unsafe.IORuntime
import scala.util.control.NonFatal
import almond.channels.Connection
import almond.channels.Channel

object LauncherOutputHandler {

  private def stdoutPoisonPill: String = null

  private sealed abstract class Value             extends Product with Serializable
  private final case class Stdout(stdout: String) extends Value
  private final case class Stderr(stderr: String) extends Value
  private final case class Display(data: almond.interpreter.api.DisplayData) extends Value
  private final case class UpdateDisplay(updateData: almond.interpreter.api.DisplayData)
      extends Value

}

class LauncherOutputHandler(
  firstMessage: Message[RawJson],
  conn: Connection
) extends OutputHandler {
  import LauncherOutputHandler._
  def done(): Unit = {
    stdout(stdoutPoisonPill)
    thread.join()
  }
  private val poisonPill = Stdout(stdoutPoisonPill)
  private val queue      = new LinkedBlockingQueue[Value]
  private val thread: Thread =
    new Thread("publish-queue") {
      setDaemon(true)
      override def run(): Unit = {
        var value: Value = null
        while ({
          value = queue.take()
          value != poisonPill
        }) {
          val msg0 = value match {
            case Stderr(stdErrMsg) =>
              firstMessage.publish(
                Execute.streamType,
                Execute.Stream("stderr", stdErrMsg),
                ident = Some("stderr")
              ).asRawMessage
            case Stdout(stdOutMsg) =>
              firstMessage.publish(
                Execute.streamType,
                Execute.Stream("stdout", stdOutMsg),
                ident = Some("stdout")
              ).asRawMessage
            case Display(data) =>
              val content = Execute.DisplayData(
                data.jsonData,
                data.jsonMetadata,
                Execute.DisplayData.Transient(data.idOpt)
              )
              firstMessage.publish(
                Execute.displayDataType,
                content,
                ident = Some(Execute.displayDataType.messageType)
              ).asRawMessage
            case UpdateDisplay(data) =>
              val content = Execute.DisplayData(
                data.jsonData,
                data.jsonMetadata,
                Execute.DisplayData.Transient(data.idOpt)
              )
              firstMessage.publish(
                Execute.updateDisplayDataType,
                content,
                ident = Some(Execute.updateDisplayDataType.messageType)
              ).asRawMessage
          }
          try
            conn
              .send(Channel.Publish, msg0)
              .unsafeRunSync()(IORuntime.global)
          catch {
            case NonFatal(e) =>
              throw new Exception(e)
          }
        }
      }
    }
  thread.start()
  def stdout(s: String): Unit =
    queue.add(Stdout(s))
  def stderr(s: String): Unit =
    queue.add(Stderr(s))
  def display(displayData: almond.interpreter.api.DisplayData): Unit =
    queue.add(Display(displayData))
  def updateDisplay(displayData: almond.interpreter.api.DisplayData): Unit =
    queue.add(UpdateDisplay(displayData))
  def canOutput(): Boolean = true

  def messageIdOpt: Option[String] = None
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy