170 lines
5.4 KiB
Scala
170 lines
5.4 KiB
Scala
package lila.lobby
|
|
|
|
import scala.concurrent.duration._
|
|
import scala.concurrent.Future
|
|
|
|
import akka.actor._
|
|
import akka.pattern.ask
|
|
import play.api.libs.iteratee._
|
|
import play.api.libs.json._
|
|
import play.twirl.api.Html
|
|
|
|
import actorApi._
|
|
import lila.common.PimpedJson._
|
|
import lila.game.actorApi._
|
|
import lila.game.{ Game, AnonCookie }
|
|
import lila.hub.actorApi.game.ChangeFeatured
|
|
import lila.hub.actorApi.lobby._
|
|
import lila.hub.actorApi.timeline._
|
|
import lila.socket.actorApi.{ SocketLeave, Connected => _, _ }
|
|
import lila.socket.SocketActor
|
|
import makeTimeout.short
|
|
|
|
private[lobby] final class Socket(
|
|
uidTtl: FiniteDuration) extends SocketActor[Member](uidTtl) {
|
|
|
|
override val startsOnApplicationBoot = true
|
|
|
|
override def preStart() {
|
|
super.preStart()
|
|
context.system.lilaBus.subscribe(self, 'changeFeaturedGame, 'streams, 'nbMembers, 'nbRounds, 'poolGame)
|
|
}
|
|
|
|
override def postStop() {
|
|
super.postStop()
|
|
context.system.lilaBus.unsubscribe(self)
|
|
}
|
|
|
|
// override postRestart so we don't call preStart and schedule a new message
|
|
override def postRestart(reason: Throwable) = {}
|
|
|
|
var idleUids = scala.collection.mutable.Set[String]()
|
|
|
|
var hookSubscriberUids = scala.collection.mutable.Set[String]()
|
|
|
|
def receiveSpecific = {
|
|
|
|
case GetUids =>
|
|
sender ! SocketUids(members.keySet.toSet)
|
|
lila.mon.lobby.socket.idle(idleUids.size)
|
|
lila.mon.lobby.socket.hookSubscribers(hookSubscriberUids.size)
|
|
lila.mon.lobby.socket.mobile(members.count(_._2.mobile))
|
|
|
|
case Join(uid, user, blocks, mobile) =>
|
|
val (enumerator, channel) = Concurrent.broadcast[JsValue]
|
|
val member = Member(channel, user, blocks, uid, mobile)
|
|
addMember(uid, member)
|
|
sender ! Connected(enumerator, member)
|
|
|
|
case ReloadTournaments(html) => notifyAllActiveAsync(makeMessage("tournaments", html))
|
|
|
|
case ReloadSimuls(html) => notifyAllActiveAsync(makeMessage("simuls", html))
|
|
|
|
case NewForumPost => notifyAllActiveAsync(makeMessage("reload_forum"))
|
|
|
|
case ReloadTimeline(userId) =>
|
|
membersByUserId(userId) foreach (_ push makeMessage("reload_timeline"))
|
|
|
|
case AddHook(hook) => Future {
|
|
val msg = makeMessage("had", hook.render)
|
|
hookSubscriberUids.foreach { uid =>
|
|
withActiveMember(uid) { member =>
|
|
if (hook.uid == member.uid || Biter.canJoin(hook, member.user)) member push msg
|
|
}
|
|
}
|
|
if (hook.likePoolFiveO) withMember(hook.uid) { member =>
|
|
lila.mon.lobby.hook.createdLikePoolFiveO(member.mobile)()
|
|
}
|
|
}
|
|
|
|
case AddSeek(_) => notifySeeks
|
|
|
|
case RemoveHook(hookId) => Future {
|
|
val msg = makeMessage("hrm", hookId)
|
|
hookSubscriberUids.foreach { uid =>
|
|
withActiveMember(uid)(_ push msg)
|
|
}
|
|
}
|
|
|
|
case RemoveSeek(_) => notifySeeks
|
|
|
|
case JoinHook(uid, hook, game, creatorColor) =>
|
|
withMember(hook.uid) { member =>
|
|
lila.mon.lobby.hook.joinMobile(member.mobile)()
|
|
notifyPlayerStart(game, creatorColor)(member)
|
|
}
|
|
withMember(uid) { member =>
|
|
lila.mon.lobby.hook.joinMobile(member.mobile)()
|
|
if (hook.likePoolFiveO)
|
|
lila.mon.lobby.hook.acceptedLikePoolFiveO(member.mobile)()
|
|
notifyPlayerStart(game, !creatorColor)(member)
|
|
}
|
|
|
|
case JoinSeek(userId, seek, game, creatorColor) =>
|
|
membersByUserId(seek.user.id) foreach { member =>
|
|
lila.mon.lobby.seek.joinMobile(member.mobile)()
|
|
notifyPlayerStart(game, creatorColor)(member)
|
|
}
|
|
membersByUserId(userId) foreach { member =>
|
|
lila.mon.lobby.seek.joinMobile(member.mobile)()
|
|
notifyPlayerStart(game, !creatorColor)(member)
|
|
}
|
|
|
|
case lila.pool.PoolApi.Pairing(game, whiteUid, blackUid) =>
|
|
withMember(whiteUid.value)(notifyPlayerStart(game, chess.White))
|
|
withMember(blackUid.value)(notifyPlayerStart(game, chess.Black))
|
|
|
|
case HookIds(ids) => Future {
|
|
val msg = makeMessage("hli", ids mkString ",")
|
|
hookSubscriberUids.foreach { uid =>
|
|
withActiveMember(uid)(_ push msg)
|
|
}
|
|
}
|
|
|
|
case lila.hub.actorApi.StreamsOnAir(html) => notifyAllAsync(makeMessage("streams", html))
|
|
|
|
case NbMembers(nb) => pong = pong + ("d" -> JsNumber(nb))
|
|
case lila.hub.actorApi.round.NbRounds(nb) =>
|
|
pong = pong + ("r" -> JsNumber(nb))
|
|
|
|
case ChangeFeatured(_, msg) => notifyAllActiveAsync(msg)
|
|
|
|
case SetIdle(uid, true) => idleUids += uid
|
|
case SetIdle(uid, false) => idleUids -= uid
|
|
|
|
case HookSub(member, true) => hookSubscriberUids += member.uid
|
|
case HookSub(member, false) => hookSubscriberUids -= member.uid
|
|
case AllHooksFor(member, hooks) =>
|
|
notifyMember("hooks", JsArray(hooks.map(_.render)))(member)
|
|
hookSubscriberUids += member.uid
|
|
}
|
|
|
|
private def notifyPlayerStart(game: Game, color: chess.Color) =
|
|
notifyMember("redirect", Json.obj(
|
|
"id" -> (game fullIdOf color),
|
|
"url" -> playerUrl(game fullIdOf color),
|
|
"cookie" -> AnonCookie.json(game, color)
|
|
).noNull) _
|
|
|
|
def notifyAllActiveAsync(msg: JsObject) = Future {
|
|
members.foreach {
|
|
case (uid, member) => if (!idleUids(uid)) member push msg
|
|
}
|
|
}
|
|
|
|
def withActiveMember(uid: String)(f: Member => Unit) {
|
|
if (!idleUids(uid)) members get uid foreach f
|
|
}
|
|
|
|
override def quit(uid: String) {
|
|
super.quit(uid)
|
|
idleUids -= uid
|
|
hookSubscriberUids -= uid
|
|
}
|
|
|
|
def playerUrl(fullId: String) = s"/$fullId"
|
|
|
|
def notifySeeks =
|
|
notifyAllActiveAsync(makeMessage("reload_seeks"))
|
|
}
|