diff --git a/app/controllers/Dev.scala b/app/controllers/Dev.scala index b3486db0c1..a5f96352d7 100644 --- a/app/controllers/Dev.scala +++ b/app/controllers/Dev.scala @@ -19,7 +19,8 @@ object Dev extends LilaController { Env.report.scoreThresholdSetting, Env.api.cspEnabledSetting, Env.streamer.alwaysFeaturedSetting, - Env.rating.ratingFactorsSetting + Env.rating.ratingFactorsSetting, + Env.socket.socketDebugSetting ) def settings = Secure(_.Settings) { implicit ctx => me => diff --git a/build.sbt b/build.sbt index 4f1f334719..9b3efd3c74 100644 --- a/build.sbt +++ b/build.sbt @@ -391,7 +391,7 @@ lazy val tree = module("tree", Seq(common)).settings( ) lazy val socket = module("socket", Seq(common, hub, memo, tree)).settings( - libraryDependencies ++= provided(play.api) + libraryDependencies ++= provided(play.api, reactivemongo.driver) ) lazy val hub = module("hub", Seq(common)).settings( diff --git a/modules/round/src/main/Env.scala b/modules/round/src/main/Env.scala index 18bc51ea57..910a65c592 100644 --- a/modules/round/src/main/Env.scala +++ b/modules/round/src/main/Env.scala @@ -36,7 +36,8 @@ final class Env( evalCacheHandler: lila.evalCache.EvalCacheSocketHandler, isBotSync: lila.common.LightUser.IsBotSync, slackApi: lila.slack.SlackApi, - ratingFactors: () => lila.rating.RatingFactors + ratingFactors: () => lila.rating.RatingFactors, + val socketDebug: () => Boolean ) { private val settings = new { @@ -278,6 +279,7 @@ object Env { evalCacheHandler = lila.evalCache.Env.current.socketHandler, isBotSync = lila.user.Env.current.lightUserApi.isBotSync, slackApi = lila.slack.Env.current.api, - ratingFactors = lila.rating.Env.current.ratingFactorsSetting.get + ratingFactors = lila.rating.Env.current.ratingFactorsSetting.get, + socketDebug = lila.socket.Env.current.socketDebugSetting.get ) } diff --git a/modules/round/src/main/History.scala b/modules/round/src/main/History.scala index b3c4d283ec..4d9f43d01f 100644 --- a/modules/round/src/main/History.scala +++ b/modules/round/src/main/History.scala @@ -27,6 +27,12 @@ private final class History( events.headOption.fold(SocketVersion(0))(_.version) } + def versionDebugString: String = { + s"${events.lastOption.fold(-1)(_.version.value)}:${ + events.headOption.fold(-1)(_.version.value) + }" + } + def getEventsSince(v: SocketVersion, mon: Option[lila.mon.round.history.PlatformHistory]): EventResult = { val version = getVersion if (v > version) VersionTooHigh diff --git a/modules/round/src/main/RoundSocket.scala b/modules/round/src/main/RoundSocket.scala index 8d90a95a9b..a995cd3269 100644 --- a/modules/round/src/main/RoundSocket.scala +++ b/modules/round/src/main/RoundSocket.scala @@ -210,13 +210,13 @@ private[round] final class RoundSocket( case None => lila.mon.round.history(mobile).versionCheck.getEventsTooFar() logger.info(s"Lost mobile:$mobile $version < ${history.getVersion} $gameId $member") - member push SocketTrouper.resyncMessage + member push SocketTrouper.resyncMsgWithDebug(s"sv(${history.versionDebugString}),cv($version)") case Some(Nil) => // all good, nothing to do case Some(evs) => lila.mon.round.history(mobile).getEventsDelta(evs.size) lila.mon.round.history(mobile).versionCheck.lateClient() logger.info(s"Late mobile:$mobile $version < ${evs.lastOption.??(_.version)} $gameId $member") - batchMsgs(member, evs) foreach member.push + batchMsgsDebug(member, evs, s"sv(${history.versionDebugString}),cv($version)") foreach member.push } case eventList: EventList => notify(eventList.events) @@ -297,6 +297,11 @@ private[round] final class RoundSocket( case many => makeMessage("b", many map (_ jsFor member)).some } + def batchMsgsDebug(member: Member, vevents: List[VersionedEvent], debug: => String) = { + if (Env.current.socketDebug()) makeMessageDebug("b", vevents map (_ jsFor member), debug).some + else batchMsgs(member, vevents) + } + def notifyOwner[A: Writes](color: Color, t: String, data: A) = withOwnerOf(color) { _ push makeMessage(t, data) diff --git a/modules/socket/src/main/Env.scala b/modules/socket/src/main/Env.scala index 9f5f8d9de7..2880534881 100644 --- a/modules/socket/src/main/Env.scala +++ b/modules/socket/src/main/Env.scala @@ -6,7 +6,8 @@ import com.typesafe.config.Config import actorApi._ final class Env( - system: ActorSystem + system: ActorSystem, + settingStore: lila.memo.SettingStore.Builder ) { import scala.concurrent.duration._ @@ -18,11 +19,18 @@ final class Env( private val userRegister = new UserRegister(system) system.scheduler.schedule(5 seconds, 1 seconds) { population ! PopulationTell } + + val socketDebugSetting = settingStore[Boolean]( + "socketDebug", + default = false, + text = "Send extra debugging to websockets.".some + ) } object Env { lazy val current = "socket" boot new Env( - system = lila.common.PlayApp.system + system = lila.common.PlayApp.system, + settingStore = lila.memo.Env.current.settingStore ) } diff --git a/modules/socket/src/main/Socket.scala b/modules/socket/src/main/Socket.scala index 2fc99b7b4b..509dd0b6e1 100644 --- a/modules/socket/src/main/Socket.scala +++ b/modules/socket/src/main/Socket.scala @@ -29,6 +29,11 @@ object Socket extends Socket { } private[socket] trait Socket { + def makeMessageDebug[A](t: String, data: A, debug: String)(implicit writes: Writes[A]): JsObject = + JsObject(new Map.Map3("t", JsString(t), "d", writes.writes(data), "debug", JsString(debug))) + + def makeMessageDebug[A](t: String, debug: String): JsObject = + JsObject(new Map.Map2("t", JsString(t), "debug", JsString(debug))) def makeMessage[A](t: String, data: A)(implicit writes: Writes[A]): JsObject = JsObject(new Map.Map2("t", JsString(t), "d", writes.writes(data))) diff --git a/modules/socket/src/main/SocketTrouper.scala b/modules/socket/src/main/SocketTrouper.scala index 996b8e27d3..b2b6b7cbea 100644 --- a/modules/socket/src/main/SocketTrouper.scala +++ b/modules/socket/src/main/SocketTrouper.scala @@ -178,6 +178,10 @@ object SocketTrouper extends Socket { case class GetNbMembers(promise: Promise[Int]) val resyncMessage = makeMessage("resync") + + def resyncMsgWithDebug(debug: => String) = + if (Env.current.socketDebugSetting.get) makeMessageDebug("resync", debug) + else resyncMessage } // Not managed by a TrouperMap