|
|
package wow.doge.mygame.subsystems.moddingsystem import java.io.FileNotFoundException import java.nio.file.NoSuchFileException
import scala.collection.View import scala.collection.immutable.ArraySeq import scala.util.Try
import cats.implicits._ import io.circe._ import io.circe.generic.semiauto._ import io.circe.parser._ import monix.bio.IO import monix.bio.UIO import monix.reactive.Consumer import monix.reactive.Observable import wow.doge.mygame.utils.IOUtils import io.circe.generic.JsonCodec
@JsonCodec final case class Test1(hello1: String, hello2: String) @JsonCodec final case class Test2(hello1: String) final case class Plugin(name: String, priority: Int) object Plugin { // @annotation.nowarn(
// "msg=Block result was adapted via implicit conversion"
// )
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder }
object ModdingSystem { sealed trait Error extends Serializable with Product final case class CouldNotDecode(cause: String) extends Error final case class ParseFailure(cause: String) extends Error final case class FileNotFound(fileName: String) extends Error case object GenericError extends Error
def readPluginsList(dir: os.Path): Try[Either[Error, ArraySeq[Plugin]]] = Try( parse(os.read(dir / "plugins.json")) .map( _.as[ArraySeq[Plugin]] .leftMap(e => CouldNotDecode(e.getMessage())) ) .leftMap((e: ParsingFailure) => ParseFailure(e.message)) .flatten ) // .toValidated
def findPluginFiles(dir: os.Path): View[os.Path] = os.list(dir) .view .filter(f => f.ext == "json" && f.baseName.endsWith("plugin"))
def findAndReadPluginFiles( dir: os.Path, plugins: ArraySeq[Plugin] ) = plugins .sortBy(_.priority) .view .map(p => p -> Either .catchNonFatal { val path = dir / os.RelPath(p.name + ".plugin.json") os.read(path) } .leftMap { case _: FileNotFoundException => FileNotFound(p.name) case _: NoSuchFileException => FileNotFound(p.name) case e => GenericError } ) .partitionMap { case (p, either) => either match { case Left(value) => Left(p -> value) case Right(value) => Right(p -> value) } }
def readPluginFiles(filePaths: View[os.Path]) = { filePaths.map(path => os.read(path)) }
def parsePluginFiles(files: View[(Plugin, String)]) = files .map { case (p, s) => p -> parse(s) } .partitionMap { case (p, Left(value)) => Left(p -> value) case (p, Right(value)) => Right(p -> value) }
def foldMerge(iterable: Iterable[Json]) = iterable.foldLeft(Json.fromString("empty")) { case (json, io.circe.Json.Null) => json //ignore null values
case (json, value) => json.deepMerge(value) }
def mergePluginData(plugins: View[(Plugin, Json)]) = { foldMerge(plugins.map { case (p, json) => json }) }
def mergePluginDataConsumer = Consumer.foldLeft[Json, Json](Json.fromString("empty")) { case (json, io.circe.Json.Null) => json case (json, that) => json.deepMerge(that) }
def loadBalancedPluginDataMerger = Consumer .loadBalance(parallelism = 2, mergePluginDataConsumer) .map(foldMerge)
// def test =
// for {
// filePaths <- Task(findPluginFiles(os.pwd))
// files <- Task(readPluginFiles(filePaths))
// (failures, successes) <- Task(parsePluginFiles(files))
// merged <- Task(mergePluginData(successes))
// _ <- Task {
// println(s"Successes = ${successes.to(Seq)}")
// println(s"Failure = ${failures.to(Seq)}")
// println(s"Merged = $merged")
// }
// } yield ()
def test(wd: os.Path = os.pwd) = for { plugins <- IO.fromTryEither(readPluginsList(wd)) (readFailures, readSuccesses) <- UIO(findAndReadPluginFiles(wd, plugins)) (parseFailures, parseSuccesses) <- UIO(parsePluginFiles(readSuccesses)) // res <- UIO(mergePluginData(parseSuccesses))
res <- IOUtils .toIO( Observable .fromIterable(parseSuccesses) .map { case (p, json) => json } .consumeWith(loadBalancedPluginDataMerger) ) .onErrorHandle(e => GenericError) _ <- UIO { println(s"Read Successes = ${readSuccesses.to(Seq)}") println(s"Read Failures = ${readFailures.to(Seq)}") println(s"Parse Successes = ${parseSuccesses.to(Seq)}") println(s"Parse Failures = ${parseFailures.to(Seq)}") println(s"Merged = $res") } } yield ()
// monix.eval.Task.deferAction(implicit s =>
// ModdingSystem
// .test()
// .leftMap(e => new Throwable(e.toString()))
// .to[monix.eval.Task]
// )
// def test3(wd: os.Path = os.pwd) = {
// (readPluginsList(os.pwd).toValidatedNec)
// }
}
|