lila/modules/relay/src/main/RelaySync.scala

129 lines
4.1 KiB
Scala
Raw Normal View History

2017-09-19 20:24:59 -06:00
package lila.relay
2017-09-20 13:35:28 -06:00
import chess.format.pgn.Tag
2017-10-01 16:07:55 -06:00
import lila.common.LilaException
2017-09-20 13:35:28 -06:00
import lila.socket.Socket.Uid
import lila.study._
2017-10-01 16:07:55 -06:00
import scala.util.{ Try, Success, Failure }
2017-09-19 20:24:59 -06:00
private final class RelaySync(
2017-09-20 13:35:28 -06:00
studyApi: StudyApi,
chapterRepo: ChapterRepo
) {
2017-09-19 20:24:59 -06:00
import RelaySync._
def apply(relay: Relay, multiPgn: MultiPgn): Funit = studyApi byId relay.studyId flatMap {
2017-09-20 13:35:28 -06:00
_ ?? { study =>
2017-10-01 16:07:55 -06:00
for {
chapters <- chapterRepo orderedByStudy study.id
games <- multiGamePgnToGames(multiPgn, logger.branch(relay.toString)).future
_ <- lila.common.Future.traverseSequentially(games) { game =>
2017-10-01 16:15:14 -06:00
chapters.find(_.tags(idTag) has game.id) match {
2017-09-20 13:35:28 -06:00
case Some(chapter) => updateChapter(study, chapter, game)
case None => createChapter(study, game)
}
2017-10-01 16:07:55 -06:00
}
} yield ()
2017-09-20 13:35:28 -06:00
}
2017-09-19 20:24:59 -06:00
}
2017-09-20 13:35:28 -06:00
private def updateChapter(study: Study, chapter: Chapter, game: RelayGame): Funit = {
game.root.mainline.foldLeft(Path.root -> none[Node]) {
case ((parentPath, None), gameNode) =>
val path = parentPath + gameNode
chapter.root.nodeAt(path) match {
case None => parentPath -> gameNode.some
case Some(existing) =>
gameNode.clock.filter(c => !existing.clock.has(c)) ?? { c =>
studyApi.doSetClock(
userId = chapter.ownerId,
study = study,
position = Position(chapter, path),
clock = c.some,
uid = socketUid
)
}
path -> none
}
2017-09-20 13:35:28 -06:00
case (found, _) => found
} match {
2017-10-01 14:49:10 -06:00
// fix mainline, and call it a day
case (path, _) if !Path.isMainline(chapter.root, path) => studyApi.promote(
userId = chapter.ownerId,
studyId = study.id,
position = Position(chapter, path).ref,
toMainline = true,
uid = socketUid
)
case (path, None) => funit // no new nodes were found
2017-09-29 14:58:09 -06:00
case (path, Some(node)) => // append new nodes to the chapter
2017-09-20 13:35:28 -06:00
lila.common.Future.fold(node.mainline)(Position(chapter, path)) {
case (position, n) => studyApi.doAddNode(
userId = position.chapter.ownerId,
study = study,
position = position,
node = n,
uid = socketUid,
opts = moveOpts.copy(clock = n.clock)
) flatten s"Can't add relay node $position $node"
} void
}
2017-09-19 20:24:59 -06:00
}
2017-09-20 13:35:28 -06:00
private def createChapter(study: Study, game: RelayGame): Funit =
chapterRepo.nextOrderByStudy(study.id) flatMap { order =>
val chapter = Chapter.make(
studyId = study.id,
name = Chapter.Name(s"${game.whiteName} - ${game.blackName}"),
setup = Chapter.Setup(
none,
game.tags.variant | chess.variant.Variant.default,
chess.Color.White
),
root = game.root,
tags = game.tags + Tag(idTag, game.id),
order = order,
ownerId = study.ownerId,
practice = false,
gamebook = false,
conceal = none
)
studyApi.doAddChapter(study, chapter, sticky = false, uid = socketUid)
}
2017-10-01 16:07:55 -06:00
private def multiGamePgnToGames(multiPgn: MultiPgn, logger: lila.log.Logger): Try[List[RelayGame]] =
multiPgn.value.foldLeft[Try[List[RelayGame]]](Success(List.empty)) {
case (Success(acc), pgn) => for {
res <- PgnImport(pgn, Nil).fold(
err => Failure(LilaException(err)),
Success.apply
2017-09-20 13:35:28 -06:00
)
2017-10-01 16:07:55 -06:00
white <- res.tags(_.White) toTry LilaException("Missing PGN White tag")
black <- res.tags(_.Black) toTry LilaException("Missing PGN Black tag")
} yield RelayGame(
tags = res.tags,
root = res.root,
whiteName = RelayGame.PlayerName(white),
blackName = RelayGame.PlayerName(black)
) :: acc
case (acc, _) => acc
}.map(_.reverse)
2017-09-20 13:35:28 -06:00
private val moveOpts = MoveOpts(
write = true,
sticky = false,
promoteToMainline = true,
clock = none
)
private val socketUid = Uid("")
private val idTag = "RelayId"
2017-09-19 20:24:59 -06:00
}
private object RelaySync {
2017-10-01 16:07:55 -06:00
case class MultiPgn(value: List[String]) extends AnyVal
}