diff --git a/modules/common/src/main/mon.scala b/modules/common/src/main/mon.scala index 467e3a3d5d..31b1758a46 100644 --- a/modules/common/src/main/mon.scala +++ b/modules/common/src/main/mon.scala @@ -382,6 +382,7 @@ object mon { } object send { def move(platform: String) = inc(s"push.send.$platform.move")() + def takeback(platform: String) = inc(s"push.send.$platform.takeback")() def corresAlarm(platform: String) = inc(s"push.send.$platform.corresAlarm")() def finish(platform: String) = inc(s"push.send.$platform.finish")() def message(platform: String) = inc(s"push.send.$platform.message")() diff --git a/modules/hub/src/main/actorApi.scala b/modules/hub/src/main/actorApi.scala index c5fb7a9800..65011008e1 100644 --- a/modules/hub/src/main/actorApi.scala +++ b/modules/hub/src/main/actorApi.scala @@ -207,6 +207,7 @@ package round { alarmable: Boolean, unlimited: Boolean ) + case class CorresTakebackEvent(gameId: String) case class SimulMoveEvent( move: MoveEvent, simulId: String, diff --git a/modules/push/src/main/Env.scala b/modules/push/src/main/Env.scala index 1796fee80c..5beed11a08 100644 --- a/modules/push/src/main/Env.scala +++ b/modules/push/src/main/Env.scala @@ -49,12 +49,13 @@ final class Env( def receive = { case lila.game.actorApi.FinishGame(game, _, _) => pushApi finish game case lila.hub.actorApi.round.CorresMoveEvent(move, _, pushable, _, _) if pushable => pushApi move move + case lila.hub.actorApi.round.CorresTakebackEvent(gameId) => pushApi takeback gameId case lila.message.Event.NewMessage(t, p) => pushApi newMessage (t, p) case lila.challenge.Event.Create(c) => pushApi challengeCreate c case lila.challenge.Event.Accept(c, joinerId) => pushApi.challengeAccept(c, joinerId) case lila.game.actorApi.CorresAlarmEvent(pov) => pushApi corresAlarm pov } - })), 'finishGame, 'moveEventCorres, 'newMessage, 'challenge, 'corresAlarm) + })), 'finishGame, 'moveEventCorres, 'newMessage, 'challenge, 'corresAlarm, 'takebackEventCorres) } object Env { diff --git a/modules/push/src/main/PushApi.scala b/modules/push/src/main/PushApi.scala index 65a357a7c7..ef7e3162e8 100644 --- a/modules/push/src/main/PushApi.scala +++ b/modules/push/src/main/PushApi.scala @@ -10,7 +10,7 @@ import lila.challenge.Challenge import lila.common.LightUser import lila.game.{ Game, GameRepo, Pov, Namer } import lila.hub.actorApi.map.Ask -import lila.hub.actorApi.round.{ MoveEvent, IsOnGame } +import lila.hub.actorApi.round.{ MoveEvent, IsOnGame, CorresTakebackEvent } import lila.message.{ Thread, Post } private final class PushApi( @@ -64,15 +64,31 @@ private final class PushApi( stacking = Stacking.GameMove, payload = Json.obj( "userId" -> userId, - "userData" -> Json.obj( - "type" -> "gameMove", - "gameId" -> game.id, - "fullId" -> pov.fullId, - "color" -> pov.color.name, - "fen" -> Forsyth.exportBoard(game.toChess.board), - "lastMove" -> game.castleLastMoveTime.lastMoveString, - "secondsLeft" -> pov.remainingSeconds - ) + "userData" -> corresGameJson(pov, "gameMove") + ) + )) + } + } + } + } + } + } + + def takeback(gameId: Game.ID): Funit = scheduler.after(1 seconds) { + GameRepo game gameId flatMap { + _.filter(_.playable).?? { game => + game.players.collectFirst { + case p if p.isProposingTakeback => Pov(game, game opponent p) + } ?? { pov => // the pov of the receiver + pov.player.userId ?? { userId => + IfAway(pov) { + pushToAll(userId, _.takeback, PushApi.Data( + title = "Takeback offer", + body = s"${opponentName(pov)} proposes a takeback", + stacking = Stacking.GameMove, + payload = Json.obj( + "userId" -> userId, + "userData" -> corresGameJson(pov, "gameTakeback") ) )) } @@ -90,19 +106,21 @@ private final class PushApi( stacking = Stacking.GameMove, payload = Json.obj( "userId" -> userId, - "userData" -> Json.obj( - "type" -> "corresAlarm", - "gameId" -> pov.gameId, - "fullId" -> pov.fullId, - "color" -> pov.color.name, - "fen" -> Forsyth.exportBoard(pov.game.toChess.board), - "lastMove" -> pov.game.castleLastMoveTime.lastMoveString, - "secondsLeft" -> pov.remainingSeconds - ) + "userData" -> corresGameJson(pov, "corresAlarm") ) )) } + private def corresGameJson(pov: Pov, typ: String) = Json.obj( + "type" -> typ, + "gameId" -> pov.game.id, + "fullId" -> pov.fullId, + "color" -> pov.color.name, + "fen" -> Forsyth.exportBoard(pov.game.toChess.board), + "lastMove" -> pov.game.castleLastMoveTime.lastMoveString, + "secondsLeft" -> pov.remainingSeconds + ) + def newMessage(t: Thread, p: Post): Funit = lightUser(t.visibleSenderOf(p)) ?? { sender => pushToAll(t.receiverOf(p), _.message, PushApi.Data( diff --git a/modules/push/src/main/Stacking.scala b/modules/push/src/main/Stacking.scala index ad2413649d..52246b9676 100644 --- a/modules/push/src/main/Stacking.scala +++ b/modules/push/src/main/Stacking.scala @@ -6,6 +6,7 @@ private object Stacking { case object GameFinish extends Stacking("gameFinish", "$[notif_count] games are over") case object GameMove extends Stacking("gameMove", "It's your turn in $[notif_count] games") + case object GameTakeback extends Stacking("gameTakeback", "Takeback offers in $[notif_count] games") case object NewMessage extends Stacking("newMessage", "You have $[notif_count] new messages") case object ChallengeCreate extends Stacking("challengeCreate", "You have $[notif_count] new challenges") case object ChallengeAccept extends Stacking("challengeAccept", "$[notif_count] players accepted your challenges") diff --git a/modules/round/src/main/Env.scala b/modules/round/src/main/Env.scala index 1a7b696d0b..01535e98d1 100644 --- a/modules/round/src/main/Env.scala +++ b/modules/round/src/main/Env.scala @@ -218,7 +218,8 @@ final class Env( lazy val takebacker = new Takebacker( messenger = messenger, uciMemo = uciMemo, - prefApi = prefApi + prefApi = prefApi, + bus = system.lilaBus ) val tvBroadcast = system.actorOf(Props(classOf[TvBroadcast])) diff --git a/modules/round/src/main/Takebacker.scala b/modules/round/src/main/Takebacker.scala index 49e6533284..373d0021b0 100644 --- a/modules/round/src/main/Takebacker.scala +++ b/modules/round/src/main/Takebacker.scala @@ -6,7 +6,8 @@ import lila.pref.{ Pref, PrefApi } private[round] final class Takebacker( messenger: Messenger, uciMemo: UciMemo, - prefApi: PrefApi + prefApi: PrefApi, + bus: lila.common.Bus ) { def yes(situation: Round.TakebackSituation)(pov: Pov)(implicit proxy: GameProxy): Fu[(Events, Round.TakebackSituation)] = IfAllowed(pov.game) { @@ -21,7 +22,8 @@ private[round] final class Takebacker( val progress = Progress(game) map { g => g.updatePlayer(color, _ proposeTakeback g.turns) } - proxy.save(progress) inject List(Event.TakebackOffers(color.white, color.black)) + proxy.save(progress) >>- publishTakeback(pov) inject + List(Event.TakebackOffers(color.white, color.black)) } map (_ -> situation) case _ => fufail(ClientError("[takebacker] invalid yes " + pov)) } @@ -53,6 +55,14 @@ private[round] final class Takebacker( } } + private def publishTakeback(pov: Pov): Unit = + if (pov.game.isCorrespondence && pov.game.nonAi) pov.player.userId foreach { userId => + bus.publish( + lila.hub.actorApi.round.CorresTakebackEvent(pov.gameId), + 'takebackEventCorres + ) + } + private def IfAllowed[A](game: Game)(f: => Fu[A]): Fu[A] = if (!game.playable) fufail(ClientError("[takebacker] game is over " + game.id)) else isAllowedByPrefs(game) flatMap {