rewrite handling of online bots/boards

now goes entirely through lila-ws
fl2
Thibault Duplessis 2020-04-02 12:18:53 -06:00
parent 8953d42082
commit e3de0fcdc5
8 changed files with 32 additions and 21 deletions

View File

@ -144,7 +144,7 @@ final class PlayApi(
}
def botOnline = Open { implicit ctx =>
env.user.repo.byIds(env.bot.onlineBots.get) map { users =>
env.user.repo.botsByIds(env.bot.onlineApiUsers.get) map { users =>
Ok(views.html.user.bots(users))
}
}

View File

@ -37,7 +37,7 @@ final class Env(
setupEnv: lila.setup.Env,
simulEnv: lila.simul.Env,
tourEnv: lila.tournament.Env,
onlineBots: lila.bot.OnlineBots,
onlineApiUsers: lila.bot.OnlineApiUsers,
pools: List[lila.pool.PoolConfig],
challengeEnv: lila.challenge.Env,
ws: WSClient,

View File

@ -15,7 +15,7 @@ import lila.user.{ User, UserRepo }
final class EventStream(
challengeJsonView: lila.challenge.JsonView,
challengeMaker: lila.challenge.ChallengeMaker,
onlineBots: lila.bot.OnlineBots,
onlineApiUsers: lila.bot.OnlineApiUsers,
userRepo: UserRepo
)(implicit ec: scala.concurrent.ExecutionContext, system: ActorSystem) {
@ -64,7 +64,7 @@ final class EventStream(
def receive = {
case SetOnline =>
if (me.isBot) onlineBots.setOnline(me.id)
onlineApiUsers.setOnline(me.id)
if (lastSetSeenAt isBefore DateTime.now.minusMinutes(2)) {
userRepo setSeenAt me.id

View File

@ -19,7 +19,7 @@ final class Env(
lazy val player = wire[BotPlayer]
lazy val onlineBots: OnlineBots = wire[OnlineBots]
lazy val onlineApiUsers: OnlineApiUsers = wire[OnlineApiUsers]
val form = BotForm
}

View File

@ -3,27 +3,32 @@ package lila.bot
import scala.concurrent.duration._
import lila.common.Bus
import lila.hub.actorApi.socket.BotIsOnline
import lila.hub.actorApi.socket.ApiUserIsOnline
import lila.memo.ExpireCallbackMemo
final class OnlineBots(
final class OnlineApiUsers(
scheduler: akka.actor.Scheduler
)(implicit ec: scala.concurrent.ExecutionContext, mode: play.api.Mode) {
private val cache = new ExpireCallbackMemo(
10.seconds,
userId => Bus.publish(BotIsOnline(userId, false), "botIsOnline")
userId => publish(userId, false)
)
def setOnline(userId: lila.user.User.ID): Unit = {
// We must delay the event publication, because caffeine
// delays the removal listener, therefore when a bot reconnects,
// the offline event is sent after the online event.
scheduler.scheduleOnce(1 second) {
Bus.publish(BotIsOnline(userId, true), "botIsOnline")
}
if (!cache.get(userId)) scheduler.scheduleOnce(1 second) { publish(userId, true) }
cache.put(userId)
}
def setOffline(userId: lila.user.User.ID): Unit = {
cache.remove(userId)
}
def get: Set[lila.user.User.ID] = cache.keySet
private def publish(userId: lila.user.User.ID, isOnline: Boolean) =
Bus.publish(ApiUserIsOnline(userId, isOnline), "onlineApiUsers")
}

View File

@ -36,7 +36,7 @@ package socket {
case class TellSriOut(sri: String, payload: JsValue)
case class TellUserIn(user: String, msg: JsObject)
}
case class BotIsOnline(userId: String, isOnline: Boolean)
case class ApiUserIsOnline(userId: String, isOnline: Boolean)
}
package clas {

View File

@ -15,7 +15,7 @@ import lila.hub.actorApi.Announce
import lila.hub.actorApi.round.Mlat
import lila.hub.actorApi.security.CloseAccount
import lila.hub.actorApi.socket.remote.{ TellSriIn, TellSriOut, TellUserIn }
import lila.hub.actorApi.socket.{ BotIsOnline, SendTo, SendTos }
import lila.hub.actorApi.socket.{ ApiUserIsOnline, SendTo, SendTos }
import lila.hub.actorApi.relation.{ Follow, UnFollow }
import Socket.Sri
@ -76,8 +76,8 @@ final class RemoteSocket(
"accountClose",
"shadowban",
"impersonate",
"botIsOnline",
"relation"
"relation",
"onlineApiUsers"
) {
case SendTos(userIds, payload) =>
val connectedUsers = userIds intersect onlineUserIds.get
@ -98,8 +98,8 @@ final class RemoteSocket(
send(Out.setTroll(userId, v))
case lila.hub.actorApi.mod.Impersonate(userId, modId) =>
send(Out.impersonate(userId, modId))
case BotIsOnline(userId, value) =>
onlineUserIds.getAndUpdate((x: UserIds) => { if (value) x + userId else x - userId })
case ApiUserIsOnline(userId, value) =>
send(Out.apiUserOnline(userId, value))
case Follow(u1, u2) => send(Out.follow(u1, u2))
case UnFollow(u1, u2) => send(Out.unfollow(u1, u2))
}
@ -262,10 +262,11 @@ object RemoteSocket {
s"mod/troll/set $userId ${boolean(v)}"
def impersonate(userId: String, by: Option[String]) =
s"mod/impersonate $userId ${optional(by)}"
def follow(u1: String, u2: String) = s"rel/follow $u1 $u2"
def unfollow(u1: String, u2: String) = s"rel/unfollow $u1 $u2"
def boot = "boot"
def stop(reqId: Int) = s"lila/stop $reqId"
def follow(u1: String, u2: String) = s"rel/follow $u1 $u2"
def unfollow(u1: String, u2: String) = s"rel/unfollow $u1 $u2"
def apiUserOnline(u: String, v: Boolean) = s"api/online $u ${boolean(v)}"
def boot = "boot"
def stop(reqId: Int) = s"lila/stop $reqId"
def commas(strs: Iterable[Any]): String = if (strs.isEmpty) "-" else strs mkString ","
def boolean(v: Boolean): String = if (v) "+" else "-"

View File

@ -101,6 +101,11 @@ final class UserRepo(val coll: Coll)(implicit ec: scala.concurrent.ExecutionCont
.sort($sort desc "perfs.standard.gl.r")
.list[User](nb, ReadPreference.secondaryPreferred)
def botsByIds(ids: Iterable[ID]): Fu[List[User]] =
coll.ext
.find($inIds(ids) ++ botSelect(true))
.list[User](Int.MaxValue, ReadPreference.secondaryPreferred)
def usernameById(id: ID) =
coll.primitiveOne[User.ID]($id(id), F.username)