package wow.doge.mygame.state import akka.actor.typed.scaladsl.Behaviors import ammonite.Main import akka.actor.typed.ActorRef import com.jme3.app.state.AppState import ammonite.runtime.Storage.Folder import ammonite.main.Defaults import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.ActorContext import ammonite.util.Res.Success import javax.script.ScriptEngine import javax.script.ScriptEngineManager import scala.util.Try import cats.implicits._ object ScriptActor { sealed trait Result final case class AppStateResult(state: AppState) extends Result final case class Error(reason: String) extends Result sealed trait Command final case class Compile(path: os.Path, sender: ActorRef[Result]) extends Command final case class CompileAny( path: os.Path, result: ActorRef[Either[Error, Any]] ) extends Command def defaultScalaRunner() = ammonite .Main( storageBackend = new Folder( // os.pwd / "target" Defaults.ammoniteHome, isRepl = false ) ) def defaultKotlinRunner(): ScriptEngine = { val manager = new ScriptEngineManager() val engine = manager.getEngineByExtension("main.kts") engine } def apply( scalaRunner: Main = defaultScalaRunner(), kotlinRunner: ScriptEngine = defaultKotlinRunner() // parent: ActorRef[ScriptStoringActor.Command] ): Behavior[ScriptActor.Command] = Behaviors.setup(ctx => new ScriptActor(scalaRunner, kotlinRunner, ctx).receiveMessage ) sealed trait ScriptType case object ScalaType extends ScriptType case object KotlinType extends ScriptType case object GroovyType extends ScriptType def determineScriptType(path: os.Path): Either[Error, ScriptType] = path.toString match { case s if s.endsWith(".sc") => Right(ScalaType) case s if s.endsWith(".main.kts") => Right(KotlinType) case s if s.endsWith(".groovy") => Right(GroovyType) case _ => Left(Error("Unknown script type")) } def runScala(path: os.Path, scalaRunner: ammonite.Main): Either[Error, Any] = scalaRunner .runScript( path, Seq.empty ) ._1 match { case ammonite.util.Res.Exception(t, msg) => Left(Error(msg)) case Success(obj) => Right(obj) case _ => Left(Error("Failed to run script")) } def runKotlin(path: os.Path, kotlinRunner: ScriptEngine): Either[Error, Any] = Try(kotlinRunner.eval(os.read(path))).toEither.leftMap(t => Error(t.getMessage()) ) def runGroovy(path: os.Path): Either[Error, Any] = Left(Error("Not implemented yet")) } class ScriptActor( val scalaRunner: Main, val kotlinRunner: ScriptEngine, // parent: ActorRef[ScriptStoringActor.Command], context: ActorContext[ScriptActor.Command] ) { import ScriptActor._ def receiveMessage: Behavior[Command] = Behaviors.receiveMessage { msg => msg match { case Compile(path, sender) => context.log.debug(s"Received $path") val res = getScript(path) sender ! res Behaviors.same // case CompileScripts(sender, paths) => case CompileAny(path, requester) => context.log.debug(s"Received $path") val res = getScript2(path) context.log.debug(s"result = $res") requester ! res // parent ! ScriptStoringActor.Put(path, res) Behaviors.same } } def getScript(path: os.Path) = { val res = determineScriptType(path) match { case Right(ScalaType) => runScala(path, scalaRunner) case Right(KotlinType) => runKotlin(path, kotlinRunner) case Right(GroovyType) => runGroovy(path) case l @ Left(err) => l } res match { case Left(err) => err case Right(obj) => obj match { case s: MyBaseState => AppStateResult(s) case _ => Error("Class in script does not match known types") } } } def getScript2(path: os.Path): Either[Error, Any] = { val res = determineScriptType(path) match { case Right(ScalaType) => runScala(path, scalaRunner) case Right(KotlinType) => runKotlin(path, kotlinRunner) case Right(GroovyType) => runGroovy(path) case l @ Left(err) => l } // res match { // case Left(err) => err // case Right(obj) => // obj match { // case s: MyBaseState => AppStateResult(s) // case _ => Error("Class in script does not match known types") // } // } res } }