diff --git a/backend/src/main/scala/org/kys/athena/http/routes/LogicEndpoints.scala b/backend/src/main/scala/org/kys/athena/http/routes/LogicEndpoints.scala index 939e8e6..2e4bc3e 100644 --- a/backend/src/main/scala/org/kys/athena/http/routes/LogicEndpoints.scala +++ b/backend/src/main/scala/org/kys/athena/http/routes/LogicEndpoints.scala @@ -11,25 +11,26 @@ import java.net.URLDecoder import java.util.UUID -object LogicEndpoints extends Endpoints { +object LogicEndpoints { // TODO: do something about this mess type Env = Has[CurrentGameModule] with Has[PregameModule] - val currentGameByNameImpl = this.currentGameByName.zServerLogic { case (platform, name, fetchGroups, requestId) => - val fetchGroupsDefault = fetchGroups.getOrElse(false) - val decodedName = URLDecoder.decode(name, "UTF-8") - implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) - - (for { - game <- CurrentGameModule.getCurrentGame(platform, decodedName) - uuidAdded <- - if (fetchGroupsDefault) - CurrentGameModule.getGroupsForGameAsync(platform, game).map(u => game.copy(groupUuid = Some(u))) - else IO.succeed(game) + val currentGameByNameImpl = Endpoints.currentGameByName + .zServerLogic { case (platform, name, fetchGroups, requestId) => + val fetchGroupsDefault = fetchGroups.getOrElse(false) + val decodedName = URLDecoder.decode(name, "UTF-8") + implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) + + (for { + game <- CurrentGameModule.getCurrentGame(platform, decodedName) + uuidAdded <- + if (fetchGroupsDefault) + CurrentGameModule.getGroupsForGameAsync(platform, game).map(u => game.copy(groupUuid = Some(u))) + else IO.succeed(game) } yield uuidAdded).resurrect.flatMapError(ErrorHandler.defaultErrorHandler) } - val currentGameGroupsByNameImpl = this.currentGameGroupsByName.zServerLogic { case (platform, name, requestId) => + val currentGameGroupsByNameImpl = Endpoints.currentGameGroupsByName.zServerLogic { case (platform, name, requestId) => val decodedName = URLDecoder.decode(name, "UTF-8") implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) @@ -39,7 +40,7 @@ object LogicEndpoints extends Endpoints { } yield groups).resurrect.flatMapError(ErrorHandler.defaultErrorHandler) } - val currentGameGroupsByUUIDImpl = this.currentGameGroupsByUUID.zServerLogic { case (uuid, requestId) => + val currentGameGroupsByUUIDImpl = Endpoints.currentGameGroupsByUUID.zServerLogic { case (uuid, requestId) => implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) (for { @@ -47,14 +48,14 @@ object LogicEndpoints extends Endpoints { } yield gg).resurrect.flatMapError(ErrorHandler.defaultErrorHandler) } - val pregameByNameImpl = this.pregameByName.zServerLogic { case (platform, names, fetchGroups, requestId) => + val pregameByNameImpl = Endpoints.pregameByName.zServerLogic { case (platform, names, fetchGroups, requestId) => implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) (for { pg <- PregameModule.getPregameLobby(platform, names) } yield PregameResponse(pg, None)).resurrect.flatMapError(ErrorHandler.defaultErrorHandler) } - val pregameGroupsByNameImpl = this.pregameGroupsByName.zServerLogic { case (platform, names, requestId) => + val pregameGroupsByNameImpl = Endpoints.pregameGroupsByName.zServerLogic { case (platform, names, requestId) => implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) (for { pg <- PregameModule.getPregameLobby(platform, names) @@ -62,7 +63,7 @@ object LogicEndpoints extends Endpoints { } yield groups).resurrect.flatMapError(ErrorHandler.defaultErrorHandler) } - val pregameGroupsByUUIDImpl = this.pregameGameGroupsByUUID.zServerLogic { case (uuid, requestId) => + val pregameGroupsByUUIDImpl = Endpoints.pregameGameGroupsByUUID.zServerLogic { case (uuid, requestId) => implicit val getReqId: String = requestId.fold(UUID.randomUUID().toString)(identity) (for { @@ -70,7 +71,7 @@ object LogicEndpoints extends Endpoints { } yield gg).resurrect.flatMapError(ErrorHandler.defaultErrorHandler) } - val healthzImpl = this.healthz.zServerLogic { _ => + val healthzImpl = Endpoints.healthz.zServerLogic { _ => UIO.succeed("Ok") } diff --git a/build.sbt b/build.sbt index c585a4e..a9fb233 100644 --- a/build.sbt +++ b/build.sbt @@ -129,6 +129,7 @@ lazy val dependencies = new { val js = Def.setting(common.value ++ Seq( "com.raquo" %%% "laminar" % laminarVersion, "com.raquo" %%% "airstream" % airstreamVersion, - "com.raquo" %%% "waypoint" % "0.2.0" + "com.raquo" %%% "waypoint" % "0.2.0", + "com.softwaremill.sttp.tapir" %%% "tapir-sttp-client" % tapirVersion )) } diff --git a/common/src/main/scala/org/kys/athena/http/routes/Endpoints.scala b/common/src/main/scala/org/kys/athena/http/routes/Endpoints.scala index ca3eebf..ea0ab1c 100644 --- a/common/src/main/scala/org/kys/athena/http/routes/Endpoints.scala +++ b/common/src/main/scala/org/kys/athena/http/routes/Endpoints.scala @@ -15,7 +15,7 @@ import sttp.model.StatusCode import java.util.UUID -trait Endpoints { +object Endpoints { private implicit val schemaForPlatform: Schema[Platform] = Schema.string private implicit val schemaForGQTE : Schema[GameQueueTypeEnum] = Schema.string private implicit val schemaForPE : Schema[PositionEnum] = Schema.string diff --git a/frontend/src/main/scala/org/kys/athena/App.scala b/frontend/src/main/scala/org/kys/athena/App.scala index 97f9867..3686286 100644 --- a/frontend/src/main/scala/org/kys/athena/App.scala +++ b/frontend/src/main/scala/org/kys/athena/App.scala @@ -10,29 +10,41 @@ import org.kys.athena.util.CSSUtil import org.kys.athena.components.LandingPage import org.kys.athena.components.common.{AppBar, Footer} import org.kys.athena.components.ongoing.OngoingPage +import org.kys.athena.components.pregame.PregamePage import org.scalajs.dom import urldsl.errors.DummyError -import urldsl.vocabulary.{FromString, Printer} +import urldsl.vocabulary.{FromString, Printer, UrlMatching} object App { + implicit val fs = new FromString[Platform, DummyError] { + override def fromString(str: String): Either[DummyError, Platform] = { + Platform.withNameEither(str).left.map(_ => DummyError.dummyError) + } + } + implicit val pr = new Printer[Platform] { + override def print(t: Platform): String = t.entryName + } + + implicit val ls = new FromString[List[String], DummyError] { + override def fromString(str: String): Either[DummyError, List[String]] = Right(str.split(',').toList) + } + + implicit val sl = new Printer[List[String]] { + override def print(t: List[String]) = t.mkString(",") + } private val routes: List[Route[_ <: PageRoute, _]] = List( Route.static(LandingRoute, root / endOfSegments), + Route.withQuery[PregameRoute, Platform, List[String]]( + encode = p => UrlMatching(p.realm, p.names), + decode = a => PregameRoute(a.path, a.params), + pattern = (root / segment[Platform] / "pregame" / endOfSegments) ? + (param[List[String]]("summoners"))), Route[OngoingRoute, (Platform, String)]( encode = p => (p.realm, p.name), decode = a => OngoingRoute(a._1, a._2), - pattern = { - implicit val fs = new FromString[Platform, DummyError] { - override def fromString(str: String): Either[DummyError, Platform] = { - Platform.withNameEither(str).left.map(_ => DummyError.dummyError) - } - } - implicit val pr = new Printer[Platform] { - override def print(t: Platform): String = t.entryName - } - root / segment[Platform] / segment[String] / endOfSegments - }) + pattern = root / segment[Platform] / segment[String] / endOfSegments) ) private val router = new Router[PageRoute]( @@ -58,6 +70,8 @@ object App { LandingPage.render(windowEvents.onMouseMove) }.collect[OngoingRoute] { page => OngoingPage.render(page, hideSearchBar.writer) + }.collect[PregameRoute] { page => + PregamePage.render(page) } def render(): HtmlElement = { diff --git a/frontend/src/main/scala/org/kys/athena/components/common/SearchBar.scala b/frontend/src/main/scala/org/kys/athena/components/common/SearchBar.scala index 88714ea..7c0ae3d 100644 --- a/frontend/src/main/scala/org/kys/athena/components/common/SearchBar.scala +++ b/frontend/src/main/scala/org/kys/athena/components/common/SearchBar.scala @@ -4,7 +4,7 @@ package org.kys.athena.components.common import com.raquo.laminar.api.L._ import org.kys.athena.App import org.kys.athena.riot.api.dto.common.Platform -import org.kys.athena.routes.OngoingRoute +import org.kys.athena.routes.{OngoingRoute, PregameRoute} import org.kys.athena.util.assets.AssetLoader import org.scalajs.dom import org.scalajs.dom.Event @@ -19,7 +19,14 @@ object SearchBar { Observer[dom.Event](onNext = _ => { (platform.now(), summoner.now()) match { case (_, "") => () - case (p, s) => App.pushState(OngoingRoute(p, s)) + case (p, s) => { + val sums = s.split(',').toList + if (sums.length > 1) { + App.pushState(PregameRoute(p, sums)) + } else { + App.pushState(OngoingRoute(p, s)) + } + } } }) diff --git a/frontend/src/main/scala/org/kys/athena/components/ongoing/OngoingPage.scala b/frontend/src/main/scala/org/kys/athena/components/ongoing/OngoingPage.scala index b7894d4..f52cb79 100644 --- a/frontend/src/main/scala/org/kys/athena/components/ongoing/OngoingPage.scala +++ b/frontend/src/main/scala/org/kys/athena/components/ongoing/OngoingPage.scala @@ -3,7 +3,7 @@ package org.kys.athena.components.ongoing import com.raquo.domtypes.generic.keys.{Style => CStyle} import com.raquo.laminar.api.L._ import com.raquo.laminar.nodes.ReactiveHtmlElement -import org.kys.athena.http.Client._ +import org.kys.athena.http.BackendClient._ import org.kys.athena.http.backend.BackendDataHelpers import org.kys.athena.http.dd.CombinedDD import org.kys.athena.http.errors.{BackendApiError, InternalServerError, NotFoundError} @@ -11,6 +11,7 @@ import org.kys.athena.http.models.current._ import org.kys.athena.http.models.premade.{PlayerGroup, PremadeResponse} import org.kys.athena.components.common import org.kys.athena.components.common.{ChampionIcon, ImgSized, OpggLink, UggLink} +import org.kys.athena.http.DDClient import org.kys.athena.routes.OngoingRoute import org.kys.athena.riot.api.dto.common.{GameQueueTypeEnum, Platform} import org.kys.athena.riot.api.dto.currentgameinfo.BannedChampion @@ -33,7 +34,9 @@ object OngoingPage { def fetchAndWriteDDragon(ddObs: Observer[DataState[CombinedDD]]): IO[BackendApiError, Unit] = { for { dd <- { - ZIO.tupledPar(fetchCachedDDragonChampion(), fetchCachedDDragonRunes(), fetchCachedDDragonSummoners()) + ZIO.tupledPar(DDClient.fetchCachedDDragonChampion(), + DDClient.fetchCachedDDragonRunes(), + DDClient.fetchCachedDDragonSummoners()) .either.map { case Left(ex) => Failed(ex) case Right((c, r, s)) => Ready(CombinedDD(c, r, s)) diff --git a/frontend/src/main/scala/org/kys/athena/components/pregame/PregamePage.scala b/frontend/src/main/scala/org/kys/athena/components/pregame/PregamePage.scala new file mode 100644 index 0000000..5fde7a3 --- /dev/null +++ b/frontend/src/main/scala/org/kys/athena/components/pregame/PregamePage.scala @@ -0,0 +1,114 @@ +package org.kys.athena.components.pregame + +import com.raquo.laminar.api.L._ +import org.kys.athena.http.BackendClient.{fetchPregameGameByName, fetchPregameGroupsByName, fetchPregameGroupsByUUID} +import org.kys.athena.http.DDClient +import org.kys.athena.http.dd.CombinedDD +import org.kys.athena.http.errors.{BackendApiError, InternalServerError} +import org.kys.athena.http.models.pregame.PregameResponse +import org.kys.athena.http.models.premade.PlayerGroup +import org.kys.athena.riot.api.dto.common.Platform +import org.kys.athena.routes.PregameRoute +import org.kys.athena.util.CSSUtil.{paletteContainer, paperCls} +import org.kys.athena.util.{DataState, Failed, Loading, Ready} +import zio.{IO, Runtime, UIO, ZIO} + + +object PregamePage { + @SuppressWarnings(Array("org.wartremover.warts.Product", "org.wartremover.warts.Serializable")) + def fetchAndWriteDDragon(ddObs: Observer[DataState[CombinedDD]]): IO[BackendApiError, Unit] = { + for { + dd <- { + ZIO.tupledPar(DDClient.fetchCachedDDragonChampion(), + DDClient.fetchCachedDDragonRunes(), + DDClient.fetchCachedDDragonSummoners()) + .either.map { + case Left(ex) => Failed(ex) + case Right((c, r, s)) => Ready(CombinedDD(c, r, s)) + } + } + _ <- UIO.effectTotal(ddObs.onNext(dd)) + } yield () + } + + @SuppressWarnings(Array("org.wartremover.warts.Product", "org.wartremover.warts.Serializable")) + def fetchAndWriteGameInfo(platform: Platform, + names: List[String], + ongoingObs: Observer[DataState[PregameResponse]], + groupsObs: Observer[DataState[Set[PlayerGroup]]]): IO[BackendApiError, Unit] = { + for { + _ <- UIO.succeed(ongoingObs.onNext(Loading)) + o <- fetchPregameGameByName(platform, names) + .map(r => Ready(r)) + .catchAll(err => UIO.succeed(Failed(err))) + _ <- UIO.effectTotal(ongoingObs.onNext(o)) + + gr <- (o match { + case Failed(_) => IO.fail(InternalServerError("Fetch for players failed, not fetching groups")) + case _ => { + o.map(_.groupUuid).toOption.flatten + .fold(fetchPregameGroupsByName(platform, names))(uuid => fetchPregameGroupsByUUID(uuid)) + } + }).map(r => Ready(r)) + .catchAll(err => UIO.succeed(Failed(err))) + _ <- UIO.effectTotal(groupsObs.onNext(gr)) + } yield () + } + + + def fetchAndWriteAll(platform: Platform, + names: List[String], + ddObs: Observer[DataState[CombinedDD]], + ongoingObs: Observer[DataState[PregameResponse]], + groupsObs: Observer[DataState[Set[PlayerGroup]]]): IO[BackendApiError, Unit] = { + ZIO.tupledPar(fetchAndWriteDDragon(ddObs), fetchAndWriteGameInfo(platform, names, ongoingObs, groupsObs)).unit + } + + + def render(p: PregameRoute): HtmlElement = { + lazy val ddVar = Var[DataState[CombinedDD]](Loading) + lazy val pregameVar = Var[DataState[PregameResponse]](Loading) + lazy val groupsVar = Var[DataState[Set[PlayerGroup]]](Loading) + + val runtime: Runtime[zio.ZEnv] = Runtime.default + + def refreshGame: Unit = { + runtime.unsafeRunAsync_(fetchAndWriteGameInfo(p.realm, + p.names, + pregameVar.writer, + groupsVar.writer)) + } + def refreshAll: Unit = { + runtime.unsafeRunAsync_(fetchAndWriteAll(p.realm, + p.names, + ddVar.writer, + pregameVar.writer, + groupsVar.writer)) + } + + div( + onMountCallback(_ => refreshAll), + cls := s"flex flex-col items-center justify-center lg:px-12 mx-4 my-2 divide-y divide-gray-500 $paperCls", + backgroundColor := paletteContainer, + span(cls := "text-3xl p-2 text-center", s"Pregame lobby of ${p.names.mkString(", ")}"), + div( + cls := s"flex flex-col lg:flex-row items-center justify-center divide-x divide-gray-500", + children <-- pregameVar.signal.map { + case Loading => List(div()) + case Ready(data) => + data.summoners. map { summoner => + div( + cls := "flex flex-col justify-center items-center", + span(summoner.name), + span(summoner.summonerLevel.toString), + div( + summoner.rankedLeagues.map { rl => + div(rl.leagueId) + } + ) + ) + }.toList + } + )) + } +} diff --git a/frontend/src/main/scala/org/kys/athena/http/BackendClient.scala b/frontend/src/main/scala/org/kys/athena/http/BackendClient.scala new file mode 100644 index 0000000..348d697 --- /dev/null +++ b/frontend/src/main/scala/org/kys/athena/http/BackendClient.scala @@ -0,0 +1,80 @@ +package org.kys.athena.http + +import org.kys.athena.http.errors._ +import org.kys.athena.http.models.current.OngoingGameResponse +import org.kys.athena.http.models.pregame.PregameResponse +import org.kys.athena.http.models.premade.{PlayerGroup, PremadeResponse} +import org.kys.athena.http.routes.Endpoints +import org.kys.athena.riot.api.dto.common.Platform +import org.kys.athena.util.Config +import sttp.client3._ +import sttp.model.Uri +import sttp.tapir.{DecodeResult, Endpoint} +import zio.{IO, UIO} +import sttp.tapir.client.sttp.SttpClientInterpreter + +import java.util.UUID + + +object BackendClient { + + private def liftErrors[T](r: DecodeResult[Either[BackendApiError, T]]): IO[BackendApiError, T] = { + r match { + case _: DecodeResult.Failure => IO.fail(InternalServerError(s"Unknown decoding error")) + case DecodeResult.Value(Left(err)) => IO.fail(err) + case DecodeResult.Value(Right(res)) => IO.succeed(res) + } + } + + private val cb = TaskFetchBackend() + + private def fetchAndLift[T](req: Request[DecodeResult[Either[BackendApiError, T]], Any]) + : IO[BackendApiError, T] = { + UIO.effectTotal(scribe.info(s"Sending request to url=${req.uri}")).zipRight { + cb.send(req).mapError { err => + InternalServerError(s"Failed to fetch response from server, error=${err.getMessage}") + }.flatMap(r => liftErrors(r.body)) + } + } + + private val debug = Config.USE_FAKE_DATA match { + case "true" => true + case _ => false + } + + val serverBaseUrl: Option[Uri] = Some(uri"${Config.BACKEND_API_URL}") + + def interpret[I, E, O](endpoint: Endpoint[I, E, O, Any]): I => Request[DecodeResult[Either[E, O]], Any] = { + SttpClientInterpreter.toRequest(endpoint, serverBaseUrl) + } + + def fetchOngoingGameByName(realm: Platform, name: String): IO[BackendApiError, OngoingGameResponse] = { + val q = interpret(Endpoints.currentGameByName) + fetchAndLift(q((realm, name, Some(true), None))) + } + + def fetchGroupsByUUID(uuid: UUID): IO[BackendApiError, PremadeResponse] = { + val q = interpret(Endpoints.currentGameGroupsByUUID) + fetchAndLift(q((uuid, None))) + } + + def fetchGroupsByName(realm: Platform, name: String): IO[BackendApiError, PremadeResponse] = { + val q = interpret(Endpoints.currentGameGroupsByName) + fetchAndLift(q((realm, name, None))) + } + + def fetchPregameGameByName(realm: Platform, names: List[String]): IO[BackendApiError, PregameResponse] = { + val q = interpret(Endpoints.pregameByName) + fetchAndLift(q((realm, names.toSet, Some(true), None))) + } + + def fetchPregameGroupsByUUID(uuid: UUID): IO[BackendApiError, Set[PlayerGroup]] = { + val q = interpret(Endpoints.pregameGameGroupsByUUID) + fetchAndLift(q((uuid, None))) + } + + def fetchPregameGroupsByName(realm: Platform, names: List[String]): IO[BackendApiError, Set[PlayerGroup]] = { + val q = interpret(Endpoints.pregameGroupsByName) + fetchAndLift(q((realm, names.toSet, None))) + } +} diff --git a/frontend/src/main/scala/org/kys/athena/http/Client.scala b/frontend/src/main/scala/org/kys/athena/http/DDClient.scala similarity index 69% rename from frontend/src/main/scala/org/kys/athena/http/Client.scala rename to frontend/src/main/scala/org/kys/athena/http/DDClient.scala index 2712c32..2d47693 100644 --- a/frontend/src/main/scala/org/kys/athena/http/Client.scala +++ b/frontend/src/main/scala/org/kys/athena/http/DDClient.scala @@ -3,10 +3,7 @@ package org.kys.athena.http import io.circe.generic.auto._ import io.circe.{Decoder, Encoder} import org.kys.athena.http.errors._ -import org.kys.athena.http.models.current.OngoingGameResponse -import org.kys.athena.http.models.premade.PremadeResponse import org.kys.athena.riot.api.RequestError -import org.kys.athena.riot.api.dto.common.Platform import org.kys.athena.riot.api.dto.ddragon.champions.Champions import org.kys.athena.riot.api.dto.ddragon.runes.RuneTree import org.kys.athena.riot.api.dto.ddragon.summonerspells.SummonerSpells @@ -15,12 +12,9 @@ import sttp.client3._ import sttp.client3.circe._ import sttp.model.StatusCode import zio.{IO, UIO} - -import java.util.UUID import scala.concurrent.duration.Duration - -object Client { +object DDClient { private def liftErrors[T](r: Response[Either[RequestError, T]]): IO[BackendApiError, T] = { r.body match { case Left(HttpError(_, statusCode)) => { @@ -78,39 +72,6 @@ object Client { } } - private val debug = Config.USE_FAKE_DATA match { - case "true" => true - case _ => false - } - - def fetchOngoingGameByName(realm: Platform, name: String): IO[BackendApiError, OngoingGameResponse] = { - val url = if (!debug) - uri"${Config.BACKEND_API_URL}/current/by-summoner-name/${realm.entryName}/$name?fetchGroups=true" - else uri"http://localhost:8080/sampleongoing.json" - val q = basicRequest - .get(url) - .response(asJson[OngoingGameResponse]) - fetchAndLift(q) - } - - def fetchGroupsByUUID(uuid: UUID): IO[BackendApiError, PremadeResponse] = { - val url = if (!debug) - uri"${Config.BACKEND_API_URL}/current/by-uuid/${uuid}/groups" - else uri"http://localhost:8080/samplepremades.json" - val q = basicRequest.get(url) - .response(asJson[PremadeResponse]) - fetchAndLift(q) - } - - def fetchGroupsByName(realm: Platform, name: String): IO[BackendApiError, PremadeResponse] = { - val url = if (!debug) - uri"${Config.BACKEND_API_URL}/current/by-summoner-name/${realm.entryName}/$name/groups" - else uri"http://localhost:8080/samplepremades.json" - val q = basicRequest.get(url) - .response(asJson[PremadeResponse]) - fetchAndLift(q) - } - def fetchCachedDDragonChampion(): IO[BackendApiError, Champions] = { val url = uri"${Config.DDRAGON_BASE_URL}${Config.DDRAGON_VERSION}/data/${Config.LOCALE}/champion.json" val q = basicRequest.get(url).response(asJson[Champions]) diff --git a/frontend/src/main/scala/org/kys/athena/routes/package.scala b/frontend/src/main/scala/org/kys/athena/routes/package.scala index af2f325..1a58d62 100644 --- a/frontend/src/main/scala/org/kys/athena/routes/package.scala +++ b/frontend/src/main/scala/org/kys/athena/routes/package.scala @@ -23,5 +23,9 @@ package object routes { override val title: String = s"Athena - $realm/$name" } + final case class PregameRoute(realm: Platform, names: List[String]) extends PageRoute { + override val title: String = "Athena - Pregame Lobby" + } + implicit val codecPage = deriveCodec[PageRoute] } diff --git a/macro/src/main/scala/org/kys/athena/util/assets/AssetLoader.scala b/macro/src/main/scala/org/kys/athena/util/assets/AssetLoader.scala index fe7031e..6cdf001 100644 --- a/macro/src/main/scala/org/kys/athena/util/assets/AssetLoader.scala +++ b/macro/src/main/scala/org/kys/athena/util/assets/AssetLoader.scala @@ -14,7 +14,6 @@ object AssetLoader { def eval[B](tree: Tree): B = c.eval[B](c.Expr[B](c.untypecheck(tree.duplicate))) try { val pathStr = eval[String](path.tree) - println("Evaled to " + pathStr) val expr = c.Expr[String](Literal(Constant(pathStr))) reify { JSImporter.require[String](s"../../src/main/resources" + expr.splice)