diff --git a/app/Env.scala b/app/Env.scala index 8427b2391696d..2817e94dacc75 100644 --- a/app/Env.scala +++ b/app/Env.scala @@ -143,7 +143,6 @@ given ConfigLoader[NetConfig] = ConfigLoader(config => siteName = get[String]("site.name"), socketDomains = get[List[String]]("socket.domains"), socketAlts = get[List[String]]("socket.alts"), - socketTest = get[Boolean]("socket.test"), crawlable = get[Boolean]("crawlable"), rateLimit = get[RateLimit]("ratelimit"), email = get[EmailAddress]("email"), diff --git a/app/UiEnv.scala b/app/UiEnv.scala index 8a50ce369c802..5f15379a93e52 100644 --- a/app/UiEnv.scala +++ b/app/UiEnv.scala @@ -25,6 +25,7 @@ object UiEnv def netConfig = env.net def contactEmailInClear = env.net.email.value def picfitUrl = env.memo.picfitUrl + def socketTest = env.web.socketTest given lila.core.config.NetDomain = env.net.domain given (using ctx: PageContext): Option[Nonce] = ctx.nonce diff --git a/app/controllers/Dev.scala b/app/controllers/Dev.scala index 0fb80b3ee03cc..638a784b366bb 100644 --- a/app/controllers/Dev.scala +++ b/app/controllers/Dev.scala @@ -27,6 +27,7 @@ final class Dev(env: Env) extends LilaController(env): env.web.settings.noDelaySecret, env.web.settings.prizeTournamentMakers, env.web.settings.sitewideCoepCredentiallessHeader, + env.web.socketTest.distributionSetting, env.tournament.reloadEndpointSetting, env.tutor.nbAnalysisSetting, env.tutor.parallelismSetting, @@ -84,7 +85,7 @@ final class Dev(env: Env) extends LilaController(env): .fold( err => BadRequest(Json.obj("error" -> err.toString)), results => - env.api.socketTestResult + env.web.socketTest .put(Json.obj(me.userId.toString -> results)) .inject(jsonOkResult) ) diff --git a/app/views/base/page.scala b/app/views/base/page.scala index 6addb667dcefc..ac73b327ceff8 100644 --- a/app/views/base/page.scala +++ b/app/views/base/page.scala @@ -4,7 +4,6 @@ import scalalib.StringUtils.escapeHtmlRaw import lila.app.UiEnv.{ *, given } import lila.common.String.html.safeJsonValue import lila.ui.RenderedPage -import lila.api.SocketTest object page: @@ -114,9 +113,9 @@ object page: .option(env.push.vapidPublicKey), dataUser := ctx.userId, dataSoundSet := pref.currentSoundSet.toString, - attr("data-socket-domains") := SocketTest.socketEndpoints(netConfig).mkString(","), - attr("data-socket-test-user") := SocketTest.isUserInTestBucket(netConfig), - attr("data-socket-test-running") := netConfig.socketTest, + attr("data-socket-domains") := socketTest.socketEndpoints(netConfig).mkString(","), + attr("data-socket-test-user") := socketTest.isUserInTestBucket(), + attr("data-socket-test-running") := socketTest.isTestRunning(), dataAssetUrl, dataAssetVersion := assetVersion, dataNonce := ctx.nonce.ifTrue(sameAssetDomain).map(_.value), diff --git a/conf/base.conf b/conf/base.conf index 8273ff8633605..68ab6c22145d8 100644 --- a/conf/base.conf +++ b/conf/base.conf @@ -15,7 +15,6 @@ net { domain = "localhost:9663" socket.domains = ["localhost:9664"] socket.alts = [] - socket.test = false asset.domain = ${net.domain} asset.base_url = "http://"${net.asset.domain} asset.base_url_internal = ${net.asset.base_url} diff --git a/modules/api/src/main/Env.scala b/modules/api/src/main/Env.scala index 1693dbc56be51..18c9185f441f1 100644 --- a/modules/api/src/main/Env.scala +++ b/modules/api/src/main/Env.scala @@ -2,7 +2,6 @@ package lila.api import akka.actor.* import com.softwaremill.macwire.* -import com.softwaremill.tagging.* import play.api.Mode import lila.chat.{ GetLinkCheck, IsChatFresh } @@ -59,8 +58,7 @@ final class Env( webConfig: lila.web.WebConfig, realPlayerApi: lila.web.RealPlayerApi, bookmarkExists: lila.core.bookmark.BookmarkExists, - manifest: lila.web.AssetManifest, - yoloDb: lila.db.AsyncDb @@ lila.db.YoloDb // for socket test results + manifest: lila.web.AssetManifest )(using val mode: Mode, scheduler: Scheduler)(using Executor, ActorSystem, @@ -97,9 +95,6 @@ final class Env( lazy val cli = wire[Cli] - lazy val socketTestResult = - SocketTestResult(yoloDb(lila.core.config.CollName("socket_test")).failingSilently()) - private lazy val linkCheck = wire[LinkCheck] lazy val chatFreshness = wire[ChatFreshness] diff --git a/modules/api/src/main/SocketTestResult.scala b/modules/api/src/main/SocketTestResult.scala deleted file mode 100644 index 566959abd5c14..0000000000000 --- a/modules/api/src/main/SocketTestResult.scala +++ /dev/null @@ -1,22 +0,0 @@ -package lila.api - -import play.api.libs.json.* - -import lila.db.JSON -import lila.core.config.NetConfig - -final class SocketTestResult(resultsDb: lila.db.AsyncCollFailingSilently)(using Executor): - def put(results: JsObject) = resultsDb: coll => - coll.insert.one(JSON.bdoc(results)).void - -object SocketTest: - - def isUserInTestBucket(net: NetConfig)(using ctx: Context) = - ctx.pref.usingAltSocket.isEmpty && ctx.userId.exists(_.value.hashCode % 128 == 0) - - def socketEndpoints(net: NetConfig)(using ctx: Context): List[String] = - ctx.pref.usingAltSocket.match - case Some(true) => net.socketAlts - case Some(false) => net.socketDomains - case _ if isUserInTestBucket(net) => net.socketDomains.head :: net.socketAlts.headOption.toList - case _ => net.socketDomains diff --git a/modules/core/src/main/config.scala b/modules/core/src/main/config.scala index 56f6b4593cf56..e864894d7a76d 100644 --- a/modules/core/src/main/config.scala +++ b/modules/core/src/main/config.scala @@ -68,7 +68,6 @@ object config: siteName: String, socketDomains: List[String], socketAlts: List[String], - socketTest: Boolean, crawlable: Boolean, rateLimit: RateLimit, email: EmailAddress, diff --git a/modules/core/src/main/pref.scala b/modules/core/src/main/pref.scala index c8ba49cdece9e..4d1ebe3fafb37 100644 --- a/modules/core/src/main/pref.scala +++ b/modules/core/src/main/pref.scala @@ -18,6 +18,7 @@ trait Pref: val resizeHandle: Int val theme: String val pieceSet: String + val usingAltSocket: Option[Boolean] def hasKeyboardMove: Boolean def hasVoice: Boolean diff --git a/modules/db/src/main/JSON.scala b/modules/db/src/main/JSON.scala index 11001cfd098c0..d31f92219d780 100644 --- a/modules/db/src/main/JSON.scala +++ b/modules/db/src/main/JSON.scala @@ -6,7 +6,7 @@ import reactivemongo.api.bson.* object JSON: def bdoc(json: JsObject): BSONDocument = - BSONDocument(json.fields.map { case (k, v) => k -> bval(v) }) + BSONDocument(json.fields.map { (k, v) => k -> bval(v) }) def bval(json: JsValue): BSONValue = json match case JsString(value) => BSONString(value) diff --git a/modules/web/src/main/Env.scala b/modules/web/src/main/Env.scala index 789852868bb09..2b48d4ab30608 100644 --- a/modules/web/src/main/Env.scala +++ b/modules/web/src/main/Env.scala @@ -1,6 +1,7 @@ package lila.web import com.softwaremill.macwire.* +import com.softwaremill.tagging.* import play.api.libs.ws.StandaloneWSClient @Module @@ -8,6 +9,7 @@ final class Env( appConfig: play.api.Configuration, environment: play.api.Environment, cacheApi: lila.memo.CacheApi, + yoloDb: lila.db.AsyncDb @@ lila.db.YoloDb, settingStore: lila.memo.SettingStore.Builder, ws: StandaloneWSClient, net: lila.core.config.NetConfig @@ -33,6 +35,11 @@ final class Env( if mode.isProd then scheduler.scheduleOnce(5 seconds)(influxEvent.start()) private lazy val pagerDuty = wire[PagerDuty] + val socketTest = SocketTest( + yoloDb(lila.core.config.CollName("socket_test")).failingSilently(), + settingStore + ) + lila.common.Bus.subscribeFun("announce"): case lila.core.socket.Announce(msg, date, _) if msg.contains("will restart") => pagerDuty.lilaRestart(date) diff --git a/modules/web/src/main/SocketTest.scala b/modules/web/src/main/SocketTest.scala new file mode 100644 index 0000000000000..656e0d1494bcb --- /dev/null +++ b/modules/web/src/main/SocketTest.scala @@ -0,0 +1,35 @@ +package lila.web + +import play.api.libs.json.* + +import lila.db.JSON +import lila.core.config.NetConfig +import lila.ui.Context + +final class SocketTest( + resultsDb: lila.db.AsyncCollFailingSilently, + settingStore: lila.memo.SettingStore.Builder +)(using Executor): + + val distributionSetting = settingStore[Int]( + "socketTestDistribution", + default = 0, + text = "Participates to socket test if userId.hashCode % distribution == 0".some + ) + + def put(results: JsObject) = resultsDb: coll => + coll.insert.one(JSON.bdoc(results)).void + + def isTestRunning() = distributionSetting.get() > 0 + + def isUserInTestBucket()(using ctx: Context) = + isTestRunning() && + ctx.pref.usingAltSocket.isEmpty && + ctx.userId.exists(_.value.hashCode % distributionSetting.get() == 0) + + def socketEndpoints(net: NetConfig)(using ctx: Context): List[String] = + ctx.pref.usingAltSocket.match + case Some(true) => net.socketAlts + case Some(false) => net.socketDomains + case _ if isUserInTestBucket() => net.socketDomains.head :: net.socketAlts.headOption.toList + case _ => net.socketDomains