diff --git a/app/controllers/Study.scala b/app/controllers/Study.scala index 6a9e37603f762..e3d7e00c1aacd 100644 --- a/app/controllers/Study.scala +++ b/app/controllers/Study.scala @@ -16,7 +16,7 @@ import lila.core.study.Order import lila.study.JsonView.JsData import lila.study.PgnDump.WithFlags import lila.study.Study.WithChapter -import lila.study.actorApi.{ BecomeStudyAdmin, Who } +import lila.study.{ BecomeStudyAdmin, Who } import lila.study.{ Chapter, Orders, Settings, Study as StudyModel, StudyForm } import lila.tree.Node.partitionTreeJsonWriter import com.fasterxml.jackson.core.JsonParseException diff --git a/modules/practice/src/main/Env.scala b/modules/practice/src/main/Env.scala index 894ac94cd8dfa..7feda25a58c4e 100644 --- a/modules/practice/src/main/Env.scala +++ b/modules/practice/src/main/Env.scala @@ -21,6 +21,6 @@ final class Env( def getStudies: lila.core.practice.GetStudies = api.structure.getStudies - lila.common.Bus.subscribeFun("study") { case lila.study.actorApi.SaveStudy(study) => + lila.common.Bus.subscribeFun("study") { case lila.study.SaveStudy(study) => api.structure.onSave(study) } diff --git a/modules/relay/src/main/Env.scala b/modules/relay/src/main/Env.scala index 84efd8e52a0f0..4cc805748fd10 100644 --- a/modules/relay/src/main/Env.scala +++ b/modules/relay/src/main/Env.scala @@ -144,19 +144,19 @@ final class Env( "study" -> { case lila.core.study.RemoveStudy(studyId) => api.onStudyRemove(studyId) }, - "relayToggle" -> { case lila.study.actorApi.RelayToggle(id, v, who) => + "relayToggle" -> { case lila.study.RelayToggle(id, v, who) => studyApi .isContributor(id, who.u) .foreach: _.so(api.requestPlay(id.into(RelayRoundId), v, "manual toggle")) }, - "kickStudy" -> { case lila.study.actorApi.Kick(studyId, userId, who) => + "kickStudy" -> { case lila.study.Kick(studyId, userId, who) => roundRepo.tourIdByStudyId(studyId).flatMapz(api.kickBroadcast(userId, _, who)) }, - "adminStudy" -> { case lila.study.actorApi.BecomeStudyAdmin(studyId, me) => + "adminStudy" -> { case lila.study.BecomeStudyAdmin(studyId, me) => api.becomeStudyAdmin(studyId, me) }, - "isOfficialRelay" -> { case lila.study.actorApi.IsOfficialRelay(studyId, promise) => + "isOfficialRelay" -> { case lila.study.IsOfficialRelay(studyId, promise) => promise.completeWith(api.isOfficial(studyId.into(RelayRoundId))) } ) diff --git a/modules/relay/src/main/RelayPlayerEnrich.scala b/modules/relay/src/main/RelayPlayerEnrich.scala index 9baefdfa247c4..f79fc3d72ae10 100644 --- a/modules/relay/src/main/RelayPlayerEnrich.scala +++ b/modules/relay/src/main/RelayPlayerEnrich.scala @@ -204,6 +204,6 @@ private final class RelayPlayerEnrich( chapterId = chapter.id, tags = enriched, newName = newName.filter(_ != chapter.name) - )(lila.study.actorApi.Who(chapter.ownerId, Sri(""))) + )(lila.study.Who(chapter.ownerId, Sri(""))) .runWith(Sink.ignore) yield () diff --git a/modules/relay/src/main/RelaySync.scala b/modules/relay/src/main/RelaySync.scala index ad8f0a5643824..8b56af0aa98c8 100644 --- a/modules/relay/src/main/RelaySync.scala +++ b/modules/relay/src/main/RelaySync.scala @@ -6,6 +6,7 @@ import chess.format.pgn.{ Tag, Tags } import lila.core.socket.Sri import lila.study.* import lila.tree.Branch +import lila.study.AddNode final private class RelaySync( studyApi: StudyApi, @@ -91,20 +92,19 @@ final private class RelaySync( studyId = study.id, position = Position(chapter, path).ref, toMainline = true - )(by) >> chapterRepo.setRelayPath(chapter.id, path) + )(using by) >> chapterRepo.setRelayPath(chapter.id, path) _ <- newNode match case Some(newNode) => newNode.mainline .foldM(Position(chapter, path).ref): (position, n) => - studyApi - .addNode( - studyId = study.id, - position = position, - node = n, - opts = moveOpts, - relay = makeRelayFor(game, position.path + n.id).some - )(by) - .inject(position + n) + val node = AddNode( + studyId = study.id, + positionRef = position, + node = n, + opts = moveOpts, + relay = makeRelayFor(game, position.path + n.id).some + )(using by) + studyApi.addNode(node).inject(position + n) case None => // the chapter already has all the game moves, // but its relayPath might be out of sync. This can happen if the broadcast @@ -121,13 +121,14 @@ final private class RelaySync( game.root.children .nodeAt(gameMainlinePath) .so: lastMainlineNode => - studyApi.addNode( - studyId = study.id, - position = Position(chapter, gameMainlinePath.parent).ref, - node = lastMainlineNode, - opts = moveOpts, - relay = makeRelayFor(game, gameMainlinePath).some - )(by) + studyApi.addNode: + AddNode( + studyId = study.id, + positionRef = Position(chapter, gameMainlinePath.parent).ref, + node = lastMainlineNode, + opts = moveOpts, + relay = makeRelayFor(game, gameMainlinePath).some + )(using by) yield newNode.so(_.mainline.size) private def updateChapterTags( @@ -212,7 +213,7 @@ final private class RelaySync( ) private val sri = Sri("") - private def who(userId: UserId) = actorApi.Who(userId, sri) + private def who(userId: UserId) = Who(userId, sri) private def vs(tags: Tags) = s"${tags(_.White) | "?"} - ${tags(_.Black) | "?"}" diff --git a/modules/study/src/main/Env.scala b/modules/study/src/main/Env.scala index c12c7b968433f..b0a9be849aac4 100644 --- a/modules/study/src/main/Env.scala +++ b/modules/study/src/main/Env.scala @@ -65,7 +65,7 @@ final class Env( private lazy val chapterMaker = wire[ChapterMaker] - private lazy val explorerGame = wire[ExplorerGame] + private lazy val explorerGame = wire[ExplorerGameApi] private lazy val studyMaker = wire[StudyMaker] diff --git a/modules/study/src/main/ExplorerGame.scala b/modules/study/src/main/ExplorerGame.scala index 8666062d10c6d..f4c069093deab 100644 --- a/modules/study/src/main/ExplorerGame.scala +++ b/modules/study/src/main/ExplorerGame.scala @@ -6,7 +6,7 @@ import chess.format.{ Fen, UciPath } import lila.tree.Node.Comment import lila.tree.{ Branch, Node, Root } -final private class ExplorerGame( +final private class ExplorerGameApi( explorer: lila.core.game.Explorer, namer: lila.core.game.Namer, lightUserApi: lila.core.user.LightUserApi, diff --git a/modules/study/src/main/JsonView.scala b/modules/study/src/main/JsonView.scala index 2faec52644254..73e31f3b88a97 100644 --- a/modules/study/src/main/JsonView.scala +++ b/modules/study/src/main/JsonView.scala @@ -218,5 +218,5 @@ object JsonView: private[study] given Writes[Chapter.ServerEval] = Json.writes - private[study] given OWrites[actorApi.Who] = OWrites: w => + private[study] given OWrites[Who] = OWrites: w => Json.obj("u" -> w.u, "s" -> w.sri) diff --git a/modules/study/src/main/StudyApi.scala b/modules/study/src/main/StudyApi.scala index 21197f0e144f5..b37182b242d59 100644 --- a/modules/study/src/main/StudyApi.scala +++ b/modules/study/src/main/StudyApi.scala @@ -13,8 +13,6 @@ import lila.core.timeline.{ Propagate, StudyLike } import lila.tree.Branch import lila.tree.Node.{ Comment, Gamebook, Shapes } -import actorApi.Who - final class StudyApi( studyRepo: StudyRepo, chapterRepo: ChapterRepo, @@ -22,7 +20,7 @@ final class StudyApi( studyMaker: StudyMaker, chapterMaker: ChapterMaker, inviter: StudyInvite, - explorerGameHandler: ExplorerGame, + explorerGameHandler: ExplorerGameApi, topicApi: StudyTopicApi, lightUserApi: lila.core.user.LightUserApi, chatApi: lila.core.chat.ChatApi, @@ -225,27 +223,21 @@ final class StudyApi( yield sendTo(study.id)(_.setPath(position, who)) case _ => funit - def addNode( - studyId: StudyId, - position: Position.Ref, - node: Branch, - opts: MoveOpts, - relay: Option[Chapter.Relay] = None - )(who: Who): Funit = - sequenceStudyWithChapter(studyId, position.chapterId): + def addNode(args: AddNode): Funit = + import args.{ *, given } + sequenceStudyWithChapter(studyId, positionRef.chapterId): case Study.WithChapter(study, chapter) => Contribute(who.u, study): - doAddNode(study, Position(chapter, position.path), node, opts, relay)(who) + doAddNode(args, study, Position(chapter, positionRef.path)) .flatMapz { _() } private def doAddNode( + args: AddNode, study: Study, - position: Position, - rawNode: Branch, - opts: MoveOpts, - relay: Option[Chapter.Relay] - )(who: Who): Fu[Option[() => Funit]] = - val singleNode = rawNode.withoutChildren + position: Position + ): Fu[Option[() => Funit]] = + import args.{ *, given } + val singleNode = args.node.withoutChildren def failReload() = reloadSriBecauseOf(study, who.sri, position.chapter.id) if position.chapter.isOverweight then logger.info(s"Overweight chapter ${study.id}/${position.chapter.id}") @@ -272,7 +264,7 @@ final class StudyApi( isMainline = newPosition.path.isMainline(chapter.root) promoteToMainline = opts.promoteToMainline && !isMainline yield promoteToMainline.option: () => - promote(study.id, position.ref + node, toMainline = true)(who) + promote(study.id, position.ref + node, toMainline = true) } } @@ -326,7 +318,7 @@ final class StudyApi( yield onChapterChange(study.id, chapter.id, who) // rewrites the whole chapter because of `forceVariation`. Very inefficient. - def promote(studyId: StudyId, position: Position.Ref, toMainline: Boolean)(who: Who): Funit = + def promote(studyId: StudyId, position: Position.Ref, toMainline: Boolean)(using who: Who): Funit = sequenceStudyWithChapter(studyId, position.chapterId): case Study.WithChapter(study, chapter) => Contribute(who.u, study): @@ -441,7 +433,7 @@ final class StudyApi( reloadSriBecauseOf(sc.study, who.sri, position.chapterId) fufail(s"Invalid setClock $position $clock") - def setTag(studyId: StudyId, setTag: actorApi.SetTag)(who: Who) = + def setTag(studyId: StudyId, setTag: SetTag)(who: Who) = sequenceStudyWithChapter(studyId, setTag.chapterId): case Study.WithChapter(study, chapter) => Contribute(who.u, study): @@ -545,7 +537,7 @@ final class StudyApi( reloadSriBecauseOf(study, who.sri, chapter.id) fufail(s"Invalid setGamebook $studyId $position") - def explorerGame(studyId: StudyId, data: actorApi.ExplorerGame)(who: Who) = + def explorerGame(studyId: StudyId, data: ExplorerGame)(who: Who) = sequenceStudyWithChapter(studyId, data.position.chapterId): case Study.WithChapter(study, chapter) => Contribute(who.u, study): diff --git a/modules/study/src/main/StudySocket.scala b/modules/study/src/main/StudySocket.scala index a53099cee2154..34c18c50cc60c 100644 --- a/modules/study/src/main/StudySocket.scala +++ b/modules/study/src/main/StudySocket.scala @@ -13,8 +13,6 @@ import lila.tree.Branch import lila.tree.Node.{ Comment, Gamebook, Shape, Shapes } import lila.tree.Node.minimalNodeJsonWriter -import actorApi.Who - final private class StudySocket( api: StudyApi, jsonView: JsonView, @@ -75,13 +73,13 @@ final private class StudySocket( AnaMove .parse(o) .foreach: move => - applyWho(moveOrDrop(studyId, move, MoveOpts.parse(o))) + applyWho(moveOrDrop(studyId, move, MoveOpts.parse(o))(using _)) case "anaDrop" => AnaDrop .parse(o) .foreach: drop => - applyWho(moveOrDrop(studyId, drop, MoveOpts.parse(o))) + applyWho(moveOrDrop(studyId, drop, MoveOpts.parse(o))(using _)) case "deleteNode" => reading[AtPosition](o): position => @@ -96,7 +94,7 @@ final private class StudySocket( (o \ "d" \ "toMainline") .asOpt[Boolean] .foreach: toMainline => - applyWho(api.promote(studyId, position.ref, toMainline)) + applyWho(api.promote(studyId, position.ref, toMainline)(using _)) case "forceVariation" => reading[AtPosition](o): position => @@ -114,7 +112,7 @@ final private class StudySocket( .foreach: username => applyWho: w => api.kick(studyId, username.id, w.myId) - Bus.publish(actorApi.Kick(studyId, username.id, w.myId), "kickStudy") + Bus.publish(Kick(studyId, username.id, w.myId), "kickStudy") case "leave" => who.foreach: w => @@ -177,7 +175,7 @@ final private class StudySocket( applyWho(api.editStudy(studyId, data)) case "setTag" => - reading[actorApi.SetTag](o): setTag => + reading[SetTag](o): setTag => applyWho(api.setTag(studyId, setTag)) case "setComment" => @@ -216,7 +214,7 @@ final private class StudySocket( applyWho(api.setTopics(studyId, topics)) case "explorerGame" => - reading[actorApi.ExplorerGame](o): data => + reading[ExplorerGame](o): data => applyWho(api.explorerGame(studyId, data)) case "requestAnalysis" => @@ -235,7 +233,7 @@ final private class StudySocket( case "relaySync" => applyWho: w => - Bus.publish(actorApi.RelayToggle(studyId, ~(o \ "d").asOpt[Boolean], w), "relayToggle") + Bus.publish(RelayToggle(studyId, ~(o \ "d").asOpt[Boolean], w), "relayToggle") case t => logger.warn(s"Unhandled study socket message: $t") @@ -246,18 +244,18 @@ final private class StudySocket( _ => _ => none, // the "talk" event is handled by the study API localTimeout = Some { (roomId, modId, suspectId) => api.isContributor(roomId, modId) >>& api.isMember(roomId, suspectId).not >>& - Bus.ask("isOfficialRelay") { actorApi.IsOfficialRelay(roomId, _) }.not + Bus.ask("isOfficialRelay") { IsOfficialRelay(roomId, _) }.not }, chatBusChan = _.study ) - private def moveOrDrop(studyId: StudyId, m: AnaAny, opts: MoveOpts)(who: Who) = + private def moveOrDrop(studyId: StudyId, m: AnaAny, opts: MoveOpts)(using Who) = m.branch.foreach: branch => if branch.ply < Node.MAX_PLIES then m.chapterId .ifTrue(opts.write) .foreach: chapterId => - api.addNode(studyId, Position.Ref(chapterId, m.path), branch, opts)(who) + api.addNode(AddNode(studyId, Position.Ref(chapterId, m.path), branch, opts)) private lazy val send = socketKit.send("study-out") @@ -458,9 +456,9 @@ object StudySocket: given Reads[ChapterMaker.EditData] = Json.reads given Reads[ChapterMaker.DescData] = Json.reads given studyDataReads: Reads[Study.Data] = Json.reads - given Reads[actorApi.SetTag] = Json.reads + given Reads[SetTag] = Json.reads given Reads[Gamebook] = Json.reads - given Reads[actorApi.ExplorerGame] = Json.reads + given Reads[ExplorerGame] = Json.reads object Out: def getIsPresent(reqId: Int, studyId: StudyId, userId: UserId) = diff --git a/modules/study/src/main/actorApi.scala b/modules/study/src/main/model.scala similarity index 78% rename from modules/study/src/main/actorApi.scala rename to modules/study/src/main/model.scala index 1378b69ac1131..abba07c496f34 100644 --- a/modules/study/src/main/actorApi.scala +++ b/modules/study/src/main/model.scala @@ -1,7 +1,7 @@ package lila.study -package actorApi import chess.format.UciPath +import lila.tree.Branch case class SaveStudy(study: Study) case class SetTag(chapterId: StudyChapterId, name: String, value: String): @@ -16,3 +16,11 @@ case class RelayToggle(studyId: StudyId, v: Boolean, who: Who) case class Kick(studyId: StudyId, userId: UserId, who: MyId) case class BecomeStudyAdmin(studyId: StudyId, me: Me) case class IsOfficialRelay(studyId: StudyId, promise: Promise[Boolean]) + +case class AddNode( + studyId: StudyId, + positionRef: Position.Ref, + node: Branch, + opts: MoveOpts, + relay: Option[Chapter.Relay] = None +)(using val who: Who)