refactor historical socket messages to allow for member filtering

This commit is contained in:
Thibault Duplessis 2014-08-02 06:42:31 +02:00
parent a0741fdc90
commit 4f827a8f3b
13 changed files with 61 additions and 53 deletions

View file

@ -18,7 +18,7 @@ final class Env(
lazy val preloader = new mashup.Preload(
lobby = Env.lobby.lobby,
history = Env.lobby.history,
lobbyVersion = () => Env.lobby.history.version,
featured = Env.tv.featured,
relations = Env.relation.api,
leaderboard = Env.user.cached.topRatingDay.apply,

View file

@ -24,7 +24,7 @@ import makeTimeout.large
final class Preload(
lobby: ActorRef,
history: History,
lobbyVersion: () => Int,
featured: Featured,
relations: RelationApi,
leaderboard: Int => Fu[List[User]],
@ -56,7 +56,7 @@ final class Preload(
streamsOnAir() map {
case ((((((((((((hooks, posts), tours), feat), blocks), entries), lead), tWinners), puzzle), playing), filter), pools), streams) =>
(Json.obj(
"version" -> history.version,
"version" -> lobbyVersion(),
"pool" -> JsArray(hooks map (_.render)),
"filter" -> filter.render,
"blocks" -> blocks,

View file

@ -41,7 +41,7 @@ final class Env(
lobby = lobby,
socket = socket)
lazy val history = new History(ttl = MessageTtl)
lazy val history = new History[actorApi.Messadata.type](ttl = MessageTtl)
{
import scala.concurrent.duration._

View file

@ -11,8 +11,8 @@ import lila.game.GameRepo
import lila.hub.actorApi.GetUids
import lila.memo.ExpireSetMemo
import lila.socket.actorApi.Broom
import org.joda.time.DateTime
import makeTimeout.short
import org.joda.time.DateTime
private[lobby] final class Lobby(
biter: Biter,

View file

@ -20,9 +20,9 @@ import lila.socket.{ SocketActor, History, Historical }
import makeTimeout.short
private[lobby] final class Socket(
val history: History,
val history: History[Messadata.type],
router: akka.actor.ActorSelection,
uidTtl: Duration) extends SocketActor[Member](uidTtl) with Historical[Member] {
uidTtl: Duration) extends SocketActor[Member](uidTtl) with Historical[Member, Messadata.type] {
context.system.lilaBus.subscribe(self, 'changeFeaturedGame, 'streams)
@ -46,9 +46,9 @@ private[lobby] final class Socket(
case ReloadTimeline(user) => sendTo(user, makeMessage("reload_timeline", JsNull))
case AddHook(hook) => notifyVersion("hook_add", hook.render)
case AddHook(hook) => notifyVersion("hook_add", hook.render, Messadata)
case RemoveHook(hookId) => notifyVersion("hook_remove", hookId)
case RemoveHook(hookId) => notifyVersion("hook_remove", hookId, Messadata)
case JoinHook(uid, hook, game, creatorColor) =>
withMember(hook.uid)(notifyMember("redirect", Json.obj(
@ -62,11 +62,13 @@ private[lobby] final class Socket(
"cookie" -> AnonCookie.json(game, !creatorColor)
).noNull))
case HookIds(ids) => notifyVersion("hook_list", ids)
case HookIds(ids) => notifyVersion("hook_list", ids, Messadata)
case lila.hub.actorApi.StreamsOnAir(html) => notifyAll(makeMessage("streams", html))
}
protected def shouldSkipMessageFor(message: Message, member: Member) = false
private def playerUrl(fullId: String) = s"/$fullId"
private def notifyTournaments(html: String) {

View file

@ -17,6 +17,8 @@ object Member {
troll = user.??(_.troll))
}
case object Messadata
case class Connected(enumerator: JsEnumerator, member: Member)
case class WithHooks(op: Iterable[String] => Unit)
case class AddHook(hook: Hook)

View file

@ -48,7 +48,7 @@ final class Env(
setup = setupRepo byId id getOrElse {
throw new IllegalArgumentException(s"Can't create pool for id $id")
},
history = new History(ttl = HistoryMessageTtl),
history = new History[actorApi.Messadata](ttl = HistoryMessageTtl),
uidTimeout = UidTimeout,
lightUser = lightUser,
isOnline = isOnline,

View file

@ -18,12 +18,12 @@ import lila.user.{ User, UserRepo }
private[pool] final class PoolActor(
setup: PoolSetup,
val history: History,
val history: History[Messadata],
lightUser: String => Option[LightUser],
isOnline: String => Boolean,
renderer: ActorSelection,
joiner: Joiner,
uidTimeout: Duration) extends SocketActor[Member](uidTimeout) with Historical[Member] {
uidTimeout: Duration) extends SocketActor[Member](uidTimeout) with Historical[Member, Messadata] {
private var pool = Pool(setup, Nil, Nil, DateTime.now plusSeconds 5)
@ -154,7 +154,7 @@ private[pool] final class PoolActor(
case lila.chat.actorApi.ChatLine(_, line) => line match {
case line: lila.chat.UserLine =>
notifyVersionTrollable("message", lila.chat.Line toJson line, troll = line.troll)
notifyVersion("message", lila.chat.Line toJson line, Messadata(line.troll))
case _ =>
}
@ -176,22 +176,20 @@ private[pool] final class PoolActor(
pool = pool withoutUserId userId
}
protected def shouldSkipMessageFor(message: Message, member: Member) =
message.metadata.trollish && !member.troll
val crowdNotifier =
context.system.actorOf(Props(new Debouncer(1.seconds, (ms: Iterable[Member]) => {
val (anons, users) = ms.map(_.userId flatMap lightUser).foldLeft(0 -> List[LightUser]()) {
case ((anons, users), Some(user)) => anons -> (user :: users)
case ((anons, users), None) => (anons + 1) -> users
}
notifyVersion("crowd", showSpectators(users, anons))
notifyVersion("crowd", showSpectators(users, anons), Messadata())
})))
val reloadNotifier =
context.system.actorOf(Props(new Debouncer(1.seconds, (_: Debouncer.Nothing) => {
notifyAll(makeMessage("reload"))
})))
def notifyVersionTrollable[A: Writes](t: String, data: A, troll: Boolean) {
val vmsg = history.+=(makeMessage(t, data), troll)
members.values.foreach(sendMessage(vmsg))
}
}

View file

@ -17,6 +17,8 @@ private[pool] object Member {
troll = user.??(_.troll))
}
private[pool] case class Messadata(trollish: Boolean = false)
private[pool] case class Join(
uid: String,
user: Option[User],

View file

@ -2,23 +2,27 @@ package lila.socket
import play.api.libs.json._
trait Historical[M <: SocketMember] { self: SocketActor[M] =>
trait Historical[M <: SocketMember, Metadata] { self: SocketActor[M] =>
val history: History
val history: History[Metadata]
def notifyVersion[A: Writes](t: String, data: A, troll: Boolean = false) {
val vmsg = history.+=(makeMessage(t, data), troll)
protected type Message = History.Message[Metadata]
protected def shouldSkipMessageFor(message: Message, member: M): Boolean
def notifyVersion[A: Writes](t: String, data: A, metadata: Metadata) {
val vmsg = history.+=(makeMessage(t, data), metadata)
val send = sendMessage(vmsg) _
members.values.foreach(send)
}
def sendMessage(message: History.Message)(member: M) {
def sendMessage(message:Message)(member: M) {
member.channel push {
if (message.troll && !member.troll) message.skipMsg
if (shouldSkipMessageFor(message, member)) message.skipMsg
else message.fullMsg
}
}
def sendMessage(member: M)(message: History.Message) {
def sendMessage(member: M)(message: Message) {
sendMessage(message)(member)
}
}

View file

@ -7,9 +7,9 @@ import play.api.libs.json._
import actorApi._
import lila.memo
final class History(ttl: Duration) {
final class History[Metadata](ttl: Duration) {
import History._
type Message = History.Message[Metadata]
private var privateVersion = 0
private val messages = memo.Builder.expiry[Int, Message](ttl)
@ -25,9 +25,9 @@ final class History(ttl: Duration) {
private def message(v: Int) = Option(messages getIfPresent v)
def +=(payload: JsObject, troll: Boolean): Message = {
def +=(payload: JsObject, metadata: Metadata): Message = {
privateVersion = privateVersion + 1
val vmsg = Message(payload, privateVersion, troll)
val vmsg = History.Message(payload, privateVersion, metadata)
messages.put(privateVersion, vmsg)
vmsg
}
@ -35,7 +35,7 @@ final class History(ttl: Duration) {
object History {
case class Message(payload: JsObject, version: Int, troll: Boolean = false) {
case class Message[Metadata](payload: JsObject, version: Int, metadata: Metadata) {
lazy val fullMsg = payload + ("v" -> JsNumber(version))

View file

@ -16,10 +16,10 @@ import lila.socket.{ SocketActor, History, Historical }
private[tournament] final class Socket(
tournamentId: String,
val history: History,
val history: History[Messadata],
lightUser: String => Option[LightUser],
uidTimeout: Duration,
socketTimeout: Duration) extends SocketActor[Member](uidTimeout) with Historical[Member] {
socketTimeout: Duration) extends SocketActor[Member](uidTimeout) with Historical[Member, Messadata] {
val joiningMemo = new ExpireSetMemo(uidTimeout)
@ -37,9 +37,9 @@ private[tournament] final class Socket(
case Reload => reloadNotifier ! Debouncer.Nothing
case Start => notifyVersion("start", JsNull)
case Start => notifyVersion("start", JsNull, Messadata())
case ReloadPage => notifyVersion("reloadPage", JsNull)
case ReloadPage => notifyVersion("reloadPage", JsNull, Messadata())
case PingVersion(uid, v) => {
ping(uid)
@ -56,7 +56,7 @@ private[tournament] final class Socket(
case lila.chat.actorApi.ChatLine(_, line) => line match {
case line: lila.chat.UserLine =>
notifyVersionTrollable("message", lila.chat.Line toJson line, troll = line.troll)
notifyVersion("message", lila.chat.Line toJson line, Messadata(line.troll))
case _ =>
}
@ -78,22 +78,20 @@ private[tournament] final class Socket(
override def userIds = (super.userIds ++ joiningMemo.keys).toList.distinct
protected def shouldSkipMessageFor(message: Message, member: Member) =
message.metadata.trollish && !member.troll
val crowdNotifier =
context.system.actorOf(Props(new Debouncer(1.seconds, (ms: Iterable[Member]) => {
val (anons, users) = members.values.map(_.userId flatMap lightUser).foldLeft(0 -> List[LightUser]()) {
case ((anons, users), Some(user)) => anons -> (user :: users)
case ((anons, users), None) => (anons + 1) -> users
}
notifyVersion("crowd", showSpectators(users, anons))
notifyVersion("crowd", showSpectators(users, anons), Messadata())
})))
val reloadNotifier =
context.system.actorOf(Props(new Debouncer(1.seconds, (_: Debouncer.Nothing) => {
notifyAll(makeMessage("reload"))
})))
def notifyVersionTrollable[A: Writes](t: String, data: A, troll: Boolean) {
val vmsg = history.+=(makeMessage(t, data), troll)
members.values.foreach(sendMessage(vmsg))
}
}

View file

@ -5,29 +5,31 @@ import lila.game.Game
import lila.socket.SocketMember
import lila.user.User
case class Member(
private[tournament] case class Member(
channel: JsChannel,
userId: Option[String],
troll: Boolean) extends SocketMember
object Member {
private[tournament] object Member {
def apply(channel: JsChannel, user: Option[User]): Member = Member(
channel = channel,
userId = user map (_.id),
troll = user.??(_.troll))
}
case class Join(
private[tournament] case class Messadata(trollish: Boolean = false)
private[tournament] case class Join(
uid: String,
user: Option[User],
version: Int)
case class Talk(tourId: String, u: String, t: String, troll: Boolean)
case object Start
case object Reload
case object ReloadPage
case class StartGame(game: Game)
case class Joining(userId: String)
case class Connected(enumerator: JsEnumerator, member: Member)
private[tournament] case class Talk(tourId: String, u: String, t: String, troll: Boolean)
private[tournament] case object Start
private[tournament] case object Reload
private[tournament] case object ReloadPage
private[tournament] case class StartGame(game: Game)
private[tournament] case class Joining(userId: String)
private[tournament] case class Connected(enumerator: JsEnumerator, member: Member)
// organizer
private[tournament] case object AllCreatedTournaments