round remote socket WIP
parent
4d9b5bfa48
commit
fdc746cd11
|
@ -620,7 +620,7 @@ object Game {
|
|||
|
||||
val gameIdSize = 8
|
||||
val playerIdSize = 4
|
||||
val fullIdSize = gameIdSize + playerIdSize
|
||||
val fullIdSize = 12
|
||||
val tokenSize = 4
|
||||
|
||||
val unplayedHours = 24
|
||||
|
@ -635,7 +635,7 @@ object Game {
|
|||
def takeGameId(fullId: String) = fullId take gameIdSize
|
||||
def takePlayerId(fullId: String) = fullId drop gameIdSize
|
||||
|
||||
val idRegex = s"""[\w-]{$gameIdSize}""".r
|
||||
val idRegex = """[\w-]{8}""".r
|
||||
def validId(id: ID) = idRegex matches id
|
||||
|
||||
private[game] val emptyCheckCount = CheckCount(0, 0)
|
||||
|
|
|
@ -6,7 +6,7 @@ import scala.collection.JavaConverters._
|
|||
import scala.concurrent.duration.FiniteDuration
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
final class DuctMap[D <: Duct](
|
||||
final class DuctMap[+D <: Duct](
|
||||
mkDuct: String => D,
|
||||
accessTimeout: FiniteDuration
|
||||
) {
|
||||
|
|
|
@ -105,7 +105,7 @@ object RoomSocket {
|
|||
def tellRoom(roomId: RoomId, payload: JsObject) =
|
||||
s"tell/room $roomId ${Json stringify payload}"
|
||||
def tellRoomVersion(roomId: RoomId, payload: JsObject, version: SocketVersion, isTroll: Boolean) =
|
||||
s"tell/room/version $roomId $version ${P.Out.bool(isTroll)} ${Json stringify payload}"
|
||||
s"tell/room/version $roomId $version ${P.Out.boolean(isTroll)} ${Json stringify payload}"
|
||||
def tellRoomUser(roomId: RoomId, userId: User.ID, payload: JsObject) =
|
||||
s"tell/room/user $roomId $userId ${Json stringify payload}"
|
||||
def tellRoomUsers(roomId: RoomId, userIds: Iterable[User.ID], payload: JsObject) =
|
||||
|
|
|
@ -75,7 +75,7 @@ final class Env(
|
|||
forecastApi = forecastApi,
|
||||
socketMap = socketMap
|
||||
)
|
||||
val roundMap = new lila.hub.DuctMap[RoundDuct](
|
||||
private val roundMap = new lila.hub.DuctMap[RoundDuct](
|
||||
mkDuct = id => {
|
||||
val duct = new RoundDuct(
|
||||
dependencies = roundDependencies,
|
||||
|
@ -93,7 +93,7 @@ final class Env(
|
|||
game.whitePlayer.userId.fold(defaultGoneWeight)(goneWeight) zip
|
||||
game.blackPlayer.userId.fold(defaultGoneWeight)(goneWeight)
|
||||
|
||||
val roundSocket = new RoundRemoteSocket(
|
||||
lazy val roundSocket = new RoundRemoteSocket(
|
||||
remoteSocketApi = remoteSocketApi,
|
||||
roundDependencies = RoundRemoteDuct.Dependencies(
|
||||
messenger = messenger,
|
||||
|
@ -116,7 +116,7 @@ final class Env(
|
|||
|
||||
bus.subscribeFuns(
|
||||
'roundMapTell -> {
|
||||
case Tell(id, msg) => selectRoundMap(id).tell(id, msg)
|
||||
case Tell(id, msg) => tellRound(id, msg)
|
||||
},
|
||||
'roundMapTellAll -> {
|
||||
case msg =>
|
||||
|
@ -129,7 +129,7 @@ final class Env(
|
|||
'accountClose -> {
|
||||
case lila.hub.actorApi.security.CloseAccount(userId) => GameRepo.allPlaying(userId) map {
|
||||
_ foreach { pov =>
|
||||
selectRoundMap(pov.gameId).tell(pov.gameId, Resign(pov.playerId))
|
||||
tellRound(pov.gameId, Resign(pov.playerId))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -153,8 +153,8 @@ final class Env(
|
|||
text = "Remote socket game ID regex".some
|
||||
)
|
||||
def useRemoteSocket(gameId: Game.ID) = remoteSocketSetting.get().matches(gameId)
|
||||
def selectRoundMap(gameId: Game.ID) =
|
||||
if (useRemoteSocket(gameId)) roundSocket.rounds else roundMap
|
||||
def selectRoundMap(gameId: Game.ID) = if (useRemoteSocket(gameId)) roundSocket.rounds else roundMap
|
||||
def tellRound(gameId: Game.ID, msg: Any): Unit = selectRoundMap(gameId).tell(gameId, msg)
|
||||
|
||||
object proxy {
|
||||
|
||||
|
@ -205,7 +205,7 @@ final class Env(
|
|||
|
||||
private def scheduleExpiration(game: Game): Unit = game.timeBeforeExpiration foreach { centis =>
|
||||
system.scheduler.scheduleOnce((centis.millis + 1000).millis) {
|
||||
selectRoundMap(game.id).tell(game.id, actorApi.round.NoStart)
|
||||
tellRound(game.id, actorApi.round.NoStart)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ final class Env(
|
|||
playban = playban
|
||||
)
|
||||
|
||||
lazy val selfReport = new SelfReport(roundMap, slackApi, proxy.pov)
|
||||
lazy val selfReport = new SelfReport(tellRound, slackApi, proxy.pov)
|
||||
|
||||
lazy val recentTvGames = new {
|
||||
val fast = new lila.memo.ExpireSetMemo(7 minutes)
|
||||
|
@ -250,7 +250,7 @@ final class Env(
|
|||
|
||||
lazy val forecastApi: ForecastApi = new ForecastApi(
|
||||
coll = db(CollectionForecast),
|
||||
roundMap = roundMap
|
||||
tellRound = tellRound
|
||||
)
|
||||
|
||||
private lazy val notifier = new RoundNotifier(
|
||||
|
@ -333,7 +333,7 @@ final class Env(
|
|||
MoveMonitor.start(system, moveTimeChannel)
|
||||
|
||||
system.actorOf(
|
||||
Props(new Titivate(roundMap, hub.bookmark, hub.chat)),
|
||||
Props(new Titivate(tellRound, hub.bookmark, hub.chat)),
|
||||
name = "titivate"
|
||||
)
|
||||
|
||||
|
@ -355,12 +355,12 @@ final class Env(
|
|||
|
||||
def checkOutoftime(game: Game): Unit = {
|
||||
if (game.playable && game.started && !game.isUnlimited)
|
||||
roundMap.tell(game.id, actorApi.round.QuietFlag)
|
||||
tellRound(game.id, actorApi.round.QuietFlag)
|
||||
}
|
||||
|
||||
def resign(pov: Pov): Unit =
|
||||
if (pov.game.abortable) roundMap.tell(pov.gameId, Abort(pov.playerId))
|
||||
else if (pov.game.resignable) roundMap.tell(pov.gameId, Resign(pov.playerId))
|
||||
if (pov.game.abortable) tellRound(pov.gameId, Abort(pov.playerId))
|
||||
else if (pov.game.resignable) tellRound(pov.gameId, Resign(pov.playerId))
|
||||
}
|
||||
|
||||
object Env {
|
||||
|
|
|
@ -13,7 +13,7 @@ import Forecast.Step
|
|||
import lila.game.{ Pov, Game }
|
||||
import lila.hub.DuctMap
|
||||
|
||||
final class ForecastApi(coll: Coll, roundMap: DuctMap[RoundDuct]) {
|
||||
final class ForecastApi(coll: Coll, tellRound: TellRound) {
|
||||
|
||||
private implicit val PosBSONHandler = new BSONHandler[BSONString, Pos] {
|
||||
def read(bsonStr: BSONString): Pos = Pos.posAt(bsonStr.value) err s"No such pos: ${bsonStr.value}"
|
||||
|
@ -50,7 +50,7 @@ final class ForecastApi(coll: Coll, roundMap: DuctMap[RoundDuct]) {
|
|||
if (!pov.isMyTurn) funit
|
||||
else Uci.Move(uciMove).fold[Funit](fufail(s"Invalid move $uciMove on $pov")) { uci =>
|
||||
val promise = Promise[Unit]
|
||||
roundMap.tell(pov.gameId, actorApi.round.HumanPlay(
|
||||
tellRound(pov.gameId, actorApi.round.HumanPlay(
|
||||
playerId = pov.playerId,
|
||||
uci = uci,
|
||||
blur = true,
|
||||
|
|
|
@ -135,25 +135,30 @@ private[round] final class RoundRemoteDuct(
|
|||
blackPlayer.goneWeight = blackGoneWeight
|
||||
}
|
||||
|
||||
case lila.chat.actorApi.ChatLine(chatId, line) => fuccess {
|
||||
publish(List(line match {
|
||||
case l: lila.chat.UserLine => Event.UserMessage(l, chatId == chatIds.pub)
|
||||
case l: lila.chat.PlayerLine => Event.PlayerMessage(l)
|
||||
}))
|
||||
}
|
||||
|
||||
// round stuff
|
||||
|
||||
case p: HumanPlay =>
|
||||
handleHumanPlay(p) { pov =>
|
||||
if (pov.game.outoftime(withGrace = true)) finisher.outOfTime(pov.game)
|
||||
else {
|
||||
recordLag(pov)
|
||||
player.human(p, this)(pov)
|
||||
}
|
||||
} >>- {
|
||||
p.trace.finish()
|
||||
lila.mon.round.move.full.count()
|
||||
case p: HumanPlay => handleHumanPlay(p) { pov =>
|
||||
if (pov.game.outoftime(withGrace = true)) finisher.outOfTime(pov.game)
|
||||
else {
|
||||
recordLag(pov)
|
||||
player.human(p, this)(pov)
|
||||
}
|
||||
} >>- {
|
||||
p.trace.finish()
|
||||
lila.mon.round.move.full.count()
|
||||
}
|
||||
|
||||
case p: BotPlay =>
|
||||
handleBotPlay(p) { pov =>
|
||||
if (pov.game.outoftime(withGrace = true)) finisher.outOfTime(pov.game)
|
||||
else player.bot(p, this)(pov)
|
||||
}
|
||||
case p: BotPlay => handleBotPlay(p) { pov =>
|
||||
if (pov.game.outoftime(withGrace = true)) finisher.outOfTime(pov.game)
|
||||
else player.bot(p, this)(pov)
|
||||
}
|
||||
|
||||
case FishnetPlay(uci, ply) => handle { game =>
|
||||
player.fishnet(game, ply, uci, this)
|
||||
|
|
|
@ -2,10 +2,12 @@ package lila.round
|
|||
|
||||
import play.api.libs.json._
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.Promise
|
||||
|
||||
import actorApi._
|
||||
import actorApi.round._
|
||||
import chess.{ Color, White, Black, Speed }
|
||||
import chess.format.Uci
|
||||
import chess.{ Color, White, Black, Speed, Centis, MoveMetrics }
|
||||
import lila.chat.Chat
|
||||
import lila.common.Bus
|
||||
import lila.game.{ Game, Event }
|
||||
|
@ -64,6 +66,11 @@ final class RoundRemoteSocket(
|
|||
case "moretime" => tellRound(fullId.gameId, Moretime(fullId.playerId.value))
|
||||
case t => logger.warn(s"Unhandled round socket message: $t")
|
||||
}
|
||||
case Protocol.In.PlayerMove(fullId, uci, blur, lag) =>
|
||||
// TODO remove promise, resync from remote round duct
|
||||
val promise = Promise[Unit]
|
||||
promise.future onFailure { case _: Exception => send(Protocol.Out.resyncPlayer(fullId)) }
|
||||
tellRound(fullId.gameId, HumanPlay(fullId.playerId.value, uci, blur, lag, promise.some))
|
||||
case ping: Protocol.In.PlayerPing => tellRound(ping.gameId, ping)
|
||||
case RP.In.KeepAlives(roomIds) => roomIds foreach { roomId =>
|
||||
rounds touchOrMake roomId.value
|
||||
|
@ -94,6 +101,7 @@ object RoundRemoteSocket {
|
|||
|
||||
case class PlayerPing(gameId: GameId, color: Color) extends P.In
|
||||
case class PlayerDo(fullId: FullId, tpe: String, msg: JsObject) extends P.In
|
||||
case class PlayerMove(fullId: FullId, uci: Uci, blur: Boolean, lag: MoveMetrics) extends P.In
|
||||
|
||||
val reader: P.In.Reader = raw => raw.path match {
|
||||
case "round/w" => PlayerPing(GameId(raw.args), chess.White).some
|
||||
|
@ -104,8 +112,22 @@ object RoundRemoteSocket {
|
|||
tpe <- obj str "t"
|
||||
} yield PlayerDo(FullId(fullId), tpe, obj)
|
||||
}
|
||||
case "round/move" => raw.get(5) {
|
||||
case Array(fullId, uciS, blurS, lagS, mtS) => Uci(uciS) map { uci =>
|
||||
PlayerMove(FullId(fullId), uci, P.In.boolean(blurS), MoveMetrics(centis(lagS), centis(mtS)))
|
||||
}
|
||||
}
|
||||
case _ => RP.In.reader(raw)
|
||||
}
|
||||
|
||||
private def centis(s: String): Option[Centis] =
|
||||
if (s == "-") none
|
||||
else parseIntOption(s) map Centis.apply
|
||||
}
|
||||
|
||||
object Out {
|
||||
|
||||
def resyncPlayer(fullId: FullId) = s"round/resync/player $fullId"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,12 @@ package lila.round
|
|||
import scala.concurrent.duration._
|
||||
|
||||
import lila.common.IpAddress
|
||||
import lila.game.{ Game, Pov }
|
||||
import lila.hub.DuctMap
|
||||
import lila.game.Pov
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
final class SelfReport(
|
||||
roundMap: DuctMap[RoundDuct],
|
||||
tellRound: TellRound,
|
||||
slackApi: lila.slack.SlackApi,
|
||||
proxyPov: String => Fu[Option[Pov]]
|
||||
) {
|
||||
|
@ -55,7 +55,7 @@ final class SelfReport(
|
|||
_ ?? { pov =>
|
||||
if (!known) doLog
|
||||
if (Set("ceval", "rcb", "ccs")(name)) fuccess {
|
||||
roundMap.tell(
|
||||
tellRound(
|
||||
pov.gameId,
|
||||
lila.round.actorApi.round.Cheat(pov.color)
|
||||
)
|
||||
|
|
|
@ -16,7 +16,7 @@ import lila.round.actorApi.round.{ QuietFlag, Abandon }
|
|||
* and flagged games when no one is around
|
||||
*/
|
||||
private[round] final class Titivate(
|
||||
roundMap: DuctMap[RoundDuct],
|
||||
tellRound: TellRound,
|
||||
bookmark: ActorSelection,
|
||||
chat: ActorSelection
|
||||
) extends Actor {
|
||||
|
@ -50,11 +50,11 @@ private[round] final class Titivate(
|
|||
GameRepo unsetCheckAt game
|
||||
|
||||
else if (game.outoftime(withGrace = true)) fuccess {
|
||||
roundMap.tell(game.id, QuietFlag)
|
||||
tellRound(game.id, QuietFlag)
|
||||
}
|
||||
|
||||
else if (game.abandoned) fuccess {
|
||||
roundMap.tell(game.id, Abandon)
|
||||
tellRound(game.id, Abandon)
|
||||
}
|
||||
|
||||
else if (game.unplayed) {
|
||||
|
|
|
@ -10,6 +10,8 @@ package object round extends PackageObject with WithSocket {
|
|||
private[round] type Events = List[Event]
|
||||
|
||||
private[round] def logger = lila.log("round")
|
||||
|
||||
type TellRound = (lila.game.Game.ID, Any) => Unit
|
||||
}
|
||||
|
||||
package round {
|
||||
|
|
|
@ -227,8 +227,8 @@ object RemoteSocket {
|
|||
} yield TellSri(Sri(sri), userId, typ, obj)
|
||||
}
|
||||
|
||||
def commas(str: String): Array[String] =
|
||||
if (str == "-") Array.empty else str split ','
|
||||
def commas(str: String): Array[String] = if (str == "-") Array.empty else str split ','
|
||||
def boolean(str: String): Boolean = str == "+"
|
||||
}
|
||||
|
||||
object Out {
|
||||
|
@ -252,7 +252,7 @@ object RemoteSocket {
|
|||
s"disconnect/user $userId"
|
||||
|
||||
def commas(strs: Iterable[Any]): String = if (strs.isEmpty) "-" else strs mkString ","
|
||||
def bool(v: Boolean): String = if (v) "true" else "-"
|
||||
def boolean(v: Boolean): String = if (v) "+" else "-"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ final class Env(
|
|||
proxyGame: Game.ID => Fu[Option[Game]],
|
||||
flood: lila.security.Flood,
|
||||
hub: lila.hub.Env,
|
||||
roundMap: DuctMap[_],
|
||||
tellRound: lila.round.TellRound,
|
||||
lightUserApi: lila.user.LightUserApi,
|
||||
isOnline: User.ID => Boolean,
|
||||
onStart: String => Unit,
|
||||
|
@ -107,7 +107,7 @@ final class Env(
|
|||
trophyApi = trophyApi,
|
||||
verify = verify,
|
||||
indexLeaderboard = leaderboardIndexer.indexOne _,
|
||||
roundMap = roundMap,
|
||||
tellRound = tellRound,
|
||||
asyncCache = asyncCache,
|
||||
duelStore = duelStore,
|
||||
pause = pause,
|
||||
|
@ -193,7 +193,7 @@ object Env {
|
|||
proxyGame = lila.round.Env.current.proxy.game _,
|
||||
flood = lila.security.Env.current.flood,
|
||||
hub = lila.hub.Env.current,
|
||||
roundMap = lila.round.Env.current.roundMap,
|
||||
tellRound = lila.round.Env.current.tellRound,
|
||||
lightUserApi = lila.user.Env.current.lightUserApi,
|
||||
isOnline = lila.user.Env.current.isOnline,
|
||||
onStart = lila.round.Env.current.onStart,
|
||||
|
|
|
@ -32,7 +32,7 @@ final class TournamentApi(
|
|||
renderer: ActorSelection,
|
||||
timeline: ActorSelection,
|
||||
socket: TournamentSocket,
|
||||
roundMap: lila.hub.DuctMap[_],
|
||||
tellRound: lila.round.TellRound,
|
||||
trophyApi: lila.user.TrophyApi,
|
||||
verify: Condition.Verify,
|
||||
indexLeaderboard: Tournament => Funit,
|
||||
|
@ -329,7 +329,7 @@ final class TournamentApi(
|
|||
case Some(pairing) if !pairing.berserkOf(userId) =>
|
||||
(pairing colorOf userId) ?? { color =>
|
||||
PairingRepo.setBerserk(pairing, userId) >>-
|
||||
roundMap.tell(gameId, GoBerserk(color))
|
||||
tellRound(gameId, GoBerserk(color))
|
||||
}
|
||||
case _ => funit
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ final class TournamentApi(
|
|||
if (tour.isStarted)
|
||||
PairingRepo.findPlaying(tour.id, userId).map {
|
||||
_ foreach { currentPairing =>
|
||||
roundMap.tell(currentPairing.gameId, AbortForce)
|
||||
tellRound(currentPairing.gameId, AbortForce)
|
||||
}
|
||||
} >> PairingRepo.opponentsOf(tour.id, userId).flatMap { uids =>
|
||||
PairingRepo.removeByTourAndUserId(tour.id, userId) >>
|
||||
|
|
Loading…
Reference in New Issue