further optimize chat

pull/6459/head
Thibault Duplessis 2020-04-23 11:43:54 -06:00
parent 6bda5fa715
commit e4578072a1
13 changed files with 78 additions and 46 deletions

View File

@ -46,7 +46,7 @@ final class BotPlayer(
val source = d.room == "spectator" option {
lila.hub.actorApi.shutup.PublicSource.Watcher(gameId)
}
chatApi.userChat.write(chatId, me.id, d.text, publicSource = source)
chatApi.userChat.write(chatId, me.id, d.text, publicSource = source, _.Round)
}
def rematchAccept(id: Game.ID, me: User): Fu[Boolean] = rematch(id, me, true)

View File

@ -80,7 +80,7 @@ final class ChatApi(
userId: User.ID,
text: String,
publicSource: Option[PublicSource],
busChan: Option[String] = None
busChan: BusChan.Select
): Funit =
makeLine(chatId, userId, text) flatMap {
_ ?? { line =>
@ -100,14 +100,14 @@ final class ChatApi(
def clear(chatId: Chat.Id) = coll.delete.one($id(chatId)).void
def system(chatId: Chat.Id, text: String, busChan: Option[String] = None): Funit = {
def system(chatId: Chat.Id, text: String, busChan: BusChan.Select): Funit = {
val line = UserLine(systemUserId, None, text, troll = false, deleted = false)
pushLine(chatId, line) >>-
publish(chatId, actorApi.ChatLine(chatId, line), busChan)
}
// like system, but not persisted.
def volatile(chatId: Chat.Id, text: String, busChan: Option[String]): Unit = {
def volatile(chatId: Chat.Id, text: String, busChan: BusChan.Select): Unit = {
val line = UserLine(systemUserId, None, text, troll = false, deleted = false)
publish(chatId, actorApi.ChatLine(chatId, line), busChan)
}
@ -118,11 +118,12 @@ final class ChatApi(
userId: User.ID,
reason: ChatTimeout.Reason,
scope: ChatTimeout.Scope,
text: String
text: String,
busChan: BusChan.Select
): Funit =
coll.byId[UserChat](chatId.value) zip userRepo.byId(modId) zip userRepo.byId(userId) flatMap {
case Some(chat) ~ Some(mod) ~ Some(user) if isMod(mod) || scope == ChatTimeout.Scope.Local =>
doTimeout(chat, mod, user, reason, scope, text)
doTimeout(chat, mod, user, reason, scope, text, busChan)
case _ => fuccess(none)
}
@ -139,7 +140,8 @@ final class ChatApi(
user: User,
reason: ChatTimeout.Reason,
scope: ChatTimeout.Scope,
text: String
text: String,
busChan: BusChan.Select
): Funit = {
val line = c.hasRecentLine(user) option UserLine(
username = systemUserId,
@ -153,9 +155,9 @@ final class ChatApi(
coll.update.one($id(chat.id), chat).void >>
chatTimeout.add(c, mod, user, reason, scope) >>- {
cached invalidate chat.id
publish(chat.id, actorApi.OnTimeout(chat.id, user.id))
publish(chat.id, actorApi.OnTimeout(chat.id, user.id), busChan)
line foreach { l =>
publish(chat.id, actorApi.ChatLine(chat.id, l))
publish(chat.id, actorApi.ChatLine(chat.id, l), busChan)
}
if (isMod(mod))
modActor ! lila.hub.actorApi.mod.ChatTimeout(
@ -168,19 +170,18 @@ final class ChatApi(
}
}
def delete(c: UserChat, user: User): Funit = {
def delete(c: UserChat, user: User, busChan: BusChan.Select): Funit = {
val chat = c.markDeleted(user)
coll.update.one($id(chat.id), chat).void >>- {
cached invalidate chat.id
publish(chat.id, actorApi.OnTimeout(chat.id, user.id))
publish(chat.id, actorApi.OnTimeout(chat.id, user.id), busChan)
}
}
private def isMod(user: User) = lila.security.Granter(_.ChatTimeout)(user)
def reinstate(list: List[ChatTimeout.Reinstate]) = list.foreach { r =>
val chatId = Chat.Id(r.chat)
publish(chatId, actorApi.OnReinstate(chatId, r.user))
Bus.publish(actorApi.OnReinstate(Chat.Id(r.chat), r.user), BusChan.Global.chan)
}
private[ChatApi] def makeLine(chatId: Chat.Id, userId: String, t1: String): Fu[Option[UserLine]] =
@ -219,10 +220,10 @@ final class ChatApi(
def optionsByOrderedIds(chatIds: List[Chat.Id]): Fu[List[Option[MixedChat]]] =
coll.optionsByOrderedIds[MixedChat, Chat.Id](chatIds, none, ReadPreference.secondaryPreferred)(_.id)
def write(chatId: Chat.Id, color: Color, text: String, busChan: String): Funit =
def write(chatId: Chat.Id, color: Color, text: String, busChan: BusChan.Select): Funit =
makeLine(chatId, color, text) ?? { line =>
pushLine(chatId, line) >>- {
publish(chatId, actorApi.ChatLine(chatId, line), busChan.some)
publish(chatId, actorApi.ChatLine(chatId, line), busChan)
lila.mon.chat.message("anonPlayer", false).increment()
}
}
@ -234,8 +235,8 @@ final class ChatApi(
}
}
private def publish(chatId: Chat.Id, msg: Any, busChan: Option[String] = None): Unit = {
Bus.publish(msg, busChan | "chat")
private def publish(chatId: Chat.Id, msg: Any, busChan: BusChan.Select): Unit = {
Bus.publish(msg, busChan(BusChan).chan)
Bus.publish(msg, Chat chanOf chatId)
}

View File

@ -6,3 +6,16 @@ case class UserModInfo(
user: User,
history: List[ChatTimeout.UserEntry]
)
sealed trait BusChan {
lazy val chan = s"chat:${toString.toLowerCase}"
}
object BusChan {
case object Round extends BusChan
case object Tournament extends BusChan
case object Simul extends BusChan
case object Study extends BusChan
case object Global extends BusChan
type Select = BusChan.type => BusChan
}

View File

@ -18,7 +18,7 @@ final class PublicChat(
case (tours, simuls) =>
(tours.map(_._2) ::: simuls.map(_._2))
.filter(_ hasLinesOf suspect.user)
.map(chatApi.userChat.delete(_, suspect.user))
.map(chatApi.userChat.delete(_, suspect.user, _.Global))
.sequenceFu
.void
}

View File

@ -25,7 +25,7 @@ final private class PlaybanFeedback(
pov.player.userId foreach { userId =>
lightUser(userId) foreach { light =>
val message = template.replace("{user}", light.fold(userId)(_.name))
chatApi.userChat.volatile(Chat.Id(pov.gameId), message, "chat:round".some)
chatApi.userChat.volatile(Chat.Id(pov.gameId), message, _.Round)
}
}
}

View File

@ -1,6 +1,6 @@
package lila.room
import lila.chat.{ Chat, ChatApi, ChatTimeout, UserLine }
import lila.chat.{ BusChan, Chat, ChatApi, ChatTimeout, UserLine }
import lila.hub.actorApi.shutup.PublicSource
import lila.hub.{ Trouper, TrouperMap }
import lila.log.Logger
@ -61,16 +61,31 @@ object RoomSocket {
chat: ChatApi,
logger: Logger,
publicSource: RoomId => PublicSource.type => Option[PublicSource],
localTimeout: Option[(RoomId, User.ID, User.ID) => Fu[Boolean]] = None
localTimeout: Option[(RoomId, User.ID, User.ID) => Fu[Boolean]] = None,
chatBusChan: BusChan.Select
)(implicit ec: ExecutionContext): Handler =
({
case Protocol.In.ChatSay(roomId, userId, msg) =>
chat.userChat.write(Chat.Id(roomId.value), userId, msg, publicSource(roomId)(PublicSource))
chat.userChat.write(
Chat.Id(roomId.value),
userId,
msg,
publicSource(roomId)(PublicSource),
chatBusChan
)
case Protocol.In.ChatTimeout(roomId, modId, suspect, reason, text) =>
lila.chat.ChatTimeout.Reason(reason) foreach { r =>
localTimeout.?? { _(roomId, modId, suspect) } foreach { local =>
val scope = if (local) ChatTimeout.Scope.Local else ChatTimeout.Scope.Global
chat.userChat.timeout(Chat.Id(roomId.value), modId, suspect, r, text = text, scope = scope)
chat.userChat.timeout(
Chat.Id(roomId.value),
modId,
suspect,
r,
text = text,
scope = scope,
busChan = chatBusChan
)
}
}
}: Handler) orElse minRoomHandler(rooms, logger)
@ -91,9 +106,9 @@ object RoomSocket {
private val chatMsgs = Set("message", "chat_timeout", "chat_reinstate")
def subscribeChat(rooms: TrouperMap[RoomState]) = {
def subscribeChat(rooms: TrouperMap[RoomState], busChan: BusChan.Select) = {
import lila.chat.actorApi._
lila.common.Bus.subscribeFun("chat") {
lila.common.Bus.subscribeFun(busChan(BusChan).chan, BusChan.Global.chan) {
case ChatLine(id, line: UserLine) =>
rooms.tellIfPresent(id.value, NotifyVersion("message", lila.chat.JsonView(line), line.troll))
case OnTimeout(id, userId) =>

View File

@ -7,8 +7,6 @@ import lila.user.User
final class Messenger(api: ChatApi) {
private[round] val busChan = "chat:round"
def system(game: Game, message: String): Unit =
system(true)(game, message)
@ -19,16 +17,16 @@ final class Messenger(api: ChatApi) {
val apiCall =
if (persistent) api.userChat.system _
else api.userChat.volatile _
apiCall(watcherId(Chat.Id(game.id)), message, busChan.some)
if (game.nonAi) apiCall(Chat.Id(game.id), message, busChan.some)
apiCall(watcherId(Chat.Id(game.id)), message, _.Round)
if (game.nonAi) apiCall(Chat.Id(game.id), message, _.Round)
}
def systemForOwners(chatId: Chat.Id, message: String): Unit = {
api.userChat.system(chatId, message, busChan.some)
api.userChat.system(chatId, message, _.Round)
}
def watcher(gameId: Game.Id, userId: User.ID, text: String) =
api.userChat.write(watcherId(gameId), userId, text, PublicSource.Watcher(gameId.value).some, busChan.some)
api.userChat.write(watcherId(gameId), userId, text, PublicSource.Watcher(gameId.value).some, _.Round)
private val whisperCommands = List("/whisper ", "/w ")
@ -36,18 +34,18 @@ final class Messenger(api: ChatApi) {
whisperCommands.collectFirst {
case command if text startsWith command =>
val source = PublicSource.Watcher(gameId.value)
api.userChat.write(watcherId(gameId), userId, text drop command.size, source.some, busChan.some)
api.userChat.write(watcherId(gameId), userId, text drop command.size, source.some, _.Round)
} getOrElse {
if (!text.startsWith("/")) // mistyped command?
api.userChat.write(Chat.Id(gameId.value), userId, text, publicSource = none, busChan.some).some
api.userChat.write(Chat.Id(gameId.value), userId, text, publicSource = none, _.Round).some
}
def owner(gameId: Game.Id, anonColor: chess.Color, text: String): Unit =
api.playerChat.write(Chat.Id(gameId.value), anonColor, text, busChan)
api.playerChat.write(Chat.Id(gameId.value), anonColor, text, _.Round)
def timeout(chatId: Chat.Id, modId: User.ID, suspect: User.ID, reason: String, text: String): Unit =
ChatTimeout.Reason(reason) foreach { r =>
api.userChat.timeout(chatId, modId, suspect, r, ChatTimeout.Scope.Global, text)
api.userChat.timeout(chatId, modId, suspect, r, ChatTimeout.Scope.Global, text, _.Round)
}
private def watcherId(chatId: Chat.Id) = Chat.Id(s"$chatId/w")

View File

@ -9,7 +9,7 @@ import actorApi._
import actorApi.round._
import chess.format.Uci
import chess.{ Black, Centis, Color, MoveMetrics, Speed, White }
import lila.chat.Chat
import lila.chat.{ BusChan, Chat }
import lila.common.{ Bus, IpAddress, Lilakka }
import lila.game.Game.{ FullId, PlayerId }
import lila.game.{ Event, Game, Pov }
@ -173,7 +173,7 @@ final class RoundSocket(
{
import lila.chat.actorApi._
Bus.subscribeFun(messenger.busChan) {
Bus.subscribeFun(BusChan.Round.chan, BusChan.Global.chan) {
case ChatLine(Chat.Id(id), l) =>
val line = RoundLine(l, id endsWith "/w")
rounds.tellIfPresent(if (line.watcher) id take Game.gameIdSize else id, line)

View File

@ -46,9 +46,10 @@ final private class SimulSocket(
lazy val rooms = makeRoomMap(send)
subscribeChat(rooms)
subscribeChat(rooms, _.Simul)
private lazy val handler: Handler = roomHandler(rooms, chat, logger, roomId => _.Simul(roomId.value).some)
private lazy val handler: Handler =
roomHandler(rooms, chat, logger, roomId => _.Simul(roomId.value).some, chatBusChan = _.Simul)
private lazy val send: String => Unit = remoteSocketApi.makeSender("simul-out").apply _

View File

@ -153,7 +153,8 @@ final private class ChapterMaker(
chatId = Chat.Id(chatId),
userId = userId,
text = s"I'm studying this game on ${net.domain}/study/${study.id}",
publicSource = none
publicSource = none,
_.Study
)
}

View File

@ -129,7 +129,8 @@ final class StudyApi(
newChapters.map(chapterRepo.insert).sequenceFu >>- {
chatApi.userChat.system(
Chat.Id(study.id.value),
s"Cloned from lichess.org/study/${prev.id}"
s"Cloned from lichess.org/study/${prev.id}",
_.Study
)
} inject study.some
}
@ -161,7 +162,8 @@ final class StudyApi(
Chat.Id(studyId.value),
userId = userId,
text = text,
publicSource = lila.hub.actorApi.shutup.PublicSource.Study(studyId.value).some
publicSource = lila.hub.actorApi.shutup.PublicSource.Study(studyId.value).some,
busChan = _.Study
)
}
}

View File

@ -28,7 +28,7 @@ final private class StudySocket(
lazy val rooms = makeRoomMap(send)
subscribeChat(rooms)
subscribeChat(rooms, _.Study)
def isPresent(studyId: Study.Id, userId: User.ID): Fu[Boolean] =
remoteSocketApi.request[Boolean](
@ -221,7 +221,8 @@ final private class StudySocket(
_ => _ => none, // the "talk" event is handled by the study API
localTimeout = Some { (roomId, modId, suspectId) =>
api.isContributor(roomId, modId) >>& !api.isMember(roomId, suspectId)
}
},
chatBusChan = _.Study
)
private def moveOrDrop(studyId: Study.Id, m: AnaAny, opts: MoveOpts)(who: Who) = m.branch match {

View File

@ -67,10 +67,10 @@ final private class TournamentSocket(
lazy val rooms = makeRoomMap(send)
subscribeChat(rooms)
subscribeChat(rooms, _.Tournament)
private lazy val handler: Handler =
roomHandler(rooms, chat, logger, roomId => _.Tournament(roomId.value).some)
roomHandler(rooms, chat, logger, roomId => _.Tournament(roomId.value).some, chatBusChan = _.Tournament)
private lazy val tourHandler: Handler = {
case Protocol.In.WaitingUsers(roomId, users) =>