2017-09-19 20:24:59 -06:00
|
|
|
package lila.relay
|
|
|
|
|
2017-10-05 15:48:14 -06:00
|
|
|
import org.joda.time.DateTime
|
|
|
|
|
2017-10-06 17:33:33 -06:00
|
|
|
import chess.format.pgn.{ Tag, Tags }
|
2017-10-01 21:39:25 -06:00
|
|
|
import lila.common.{ LilaException, Chronometer }
|
2017-09-20 13:35:28 -06:00
|
|
|
import lila.socket.Socket.Uid
|
|
|
|
import lila.study._
|
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
|
|
|
|
2017-10-04 23:59:35 -06:00
|
|
|
private type NbMoves = Int
|
|
|
|
|
|
|
|
def apply(relay: Relay, games: RelayGames): Fu[NbMoves] = 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
|
2017-10-04 23:59:35 -06:00
|
|
|
movesPerGame <- lila.common.Future.traverseSequentially(games) { game =>
|
2017-10-05 11:28:07 -06:00
|
|
|
chapters.find(game.is) match {
|
2017-09-20 13:35:28 -06:00
|
|
|
case Some(chapter) => updateChapter(study, chapter, game)
|
2017-10-01 17:25:44 -06:00
|
|
|
case None => createChapter(study, game) flatMap { chapter =>
|
2017-10-04 23:59:35 -06:00
|
|
|
chapters.find(_.isEmptyInitial).ifTrue(chapter.order == 2).?? { initial =>
|
2017-10-01 17:25:44 -06:00
|
|
|
studyApi.deleteChapter(study.ownerId, study.id, initial.id, socketUid)
|
2017-10-04 23:59:35 -06:00
|
|
|
} inject chapter.root.mainline.size
|
2017-10-01 17:25:44 -06:00
|
|
|
}
|
2017-09-20 13:35:28 -06:00
|
|
|
}
|
2017-10-01 16:07:55 -06:00
|
|
|
}
|
2017-10-04 23:59:35 -06:00
|
|
|
nbMoves = movesPerGame.foldLeft(0)(_ + _)
|
|
|
|
} yield nbMoves
|
2017-09-20 13:35:28 -06:00
|
|
|
}
|
2017-09-19 20:24:59 -06:00
|
|
|
}
|
|
|
|
|
2017-10-05 19:13:29 -06:00
|
|
|
private def updateChapter(study: Study, chapter: Chapter, game: RelayGame): Fu[NbMoves] =
|
2017-10-06 17:33:33 -06:00
|
|
|
updateChapterTags(study, chapter, game) >>
|
2017-10-05 19:13:29 -06:00
|
|
|
updateChapterTree(study, chapter, game)
|
|
|
|
|
|
|
|
private def updateChapterTree(study: Study, chapter: Chapter, game: RelayGame): Fu[NbMoves] = {
|
2017-09-20 13:35:28 -06:00
|
|
|
game.root.mainline.foldLeft(Path.root -> none[Node]) {
|
|
|
|
case ((parentPath, None), gameNode) =>
|
|
|
|
val path = parentPath + gameNode
|
2017-09-20 13:53:52 -06:00
|
|
|
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
|
2017-10-04 23:59:35 -06:00
|
|
|
) inject 0
|
|
|
|
case (path, None) => fuccess(0) // 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,
|
2017-10-05 00:30:40 -06:00
|
|
|
rawNode = n,
|
2017-09-20 13:35:28 -06:00
|
|
|
uid = socketUid,
|
2017-10-05 15:48:14 -06:00
|
|
|
opts = moveOpts.copy(clock = n.clock),
|
2017-10-05 17:22:29 -06:00
|
|
|
relay = Chapter.Relay(
|
|
|
|
path = position.path + n,
|
|
|
|
lastMoveAt = DateTime.now.some
|
|
|
|
).some
|
2017-09-20 13:35:28 -06:00
|
|
|
) flatten s"Can't add relay node $position $node"
|
2017-10-04 23:59:35 -06:00
|
|
|
} inject node.mainline.size
|
2017-09-20 13:35:28 -06:00
|
|
|
}
|
2017-09-19 20:24:59 -06:00
|
|
|
}
|
2017-09-20 13:35:28 -06:00
|
|
|
|
2017-10-06 17:33:33 -06:00
|
|
|
private def updateChapterTags(study: Study, chapter: Chapter, game: RelayGame): Funit = {
|
|
|
|
val gameTags = game.tags.value.foldLeft(Tags(Nil)) {
|
|
|
|
case (newTags, tag) =>
|
|
|
|
if (!chapter.tags(_ => tag.name).has(tag.value)) newTags + tag
|
|
|
|
else newTags
|
|
|
|
}
|
|
|
|
val tags = game.end
|
|
|
|
.ifFalse(gameTags(_.Result).isDefined)
|
|
|
|
.filterNot(end => chapter.tags(_.Result).??(end.resultText ==))
|
|
|
|
.fold(gameTags) { end =>
|
|
|
|
gameTags + Tag(_.Result, end.resultText)
|
|
|
|
}
|
|
|
|
lila.common.Future.traverseSequentially(tags.value) { tag =>
|
|
|
|
studyApi.setTag(
|
|
|
|
userId = chapter.ownerId,
|
|
|
|
studyId = study.id,
|
|
|
|
lila.study.actorApi.SetTag(chapter.id, tag.name.name, tag.value),
|
|
|
|
uid = socketUid
|
|
|
|
)
|
|
|
|
}.void
|
|
|
|
}
|
|
|
|
|
2017-10-01 17:25:44 -06:00
|
|
|
private def createChapter(study: Study, game: RelayGame): Fu[Chapter] =
|
2017-09-20 13:35:28 -06:00
|
|
|
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,
|
2017-10-05 11:28:07 -06:00
|
|
|
tags = game.tags,
|
2017-09-20 13:35:28 -06:00
|
|
|
order = order,
|
|
|
|
ownerId = study.ownerId,
|
|
|
|
practice = false,
|
|
|
|
gamebook = false,
|
2017-10-07 06:14:25 -06:00
|
|
|
conceal = none,
|
|
|
|
relay = Chapter.Relay(
|
|
|
|
path = game.root.mainlinePath,
|
|
|
|
lastMoveAt = DateTime.now.some
|
|
|
|
).some
|
2017-09-20 13:35:28 -06:00
|
|
|
)
|
2017-10-01 17:25:44 -06:00
|
|
|
studyApi.doAddChapter(study, chapter, sticky = false, uid = socketUid) inject chapter
|
2017-09-20 13:35:28 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
private val moveOpts = MoveOpts(
|
|
|
|
write = true,
|
|
|
|
sticky = false,
|
|
|
|
promoteToMainline = true,
|
|
|
|
clock = none
|
|
|
|
)
|
|
|
|
|
|
|
|
private val socketUid = Uid("")
|
2017-09-19 20:24:59 -06:00
|
|
|
}
|