perform all lobby hook actions through actors

pull/83/head
Thibault Duplessis 2013-05-18 22:18:41 -03:00
parent 4d89b1bdc4
commit 4dbed3f627
13 changed files with 93 additions and 87 deletions

View File

@ -26,6 +26,7 @@ private[app] final class Router(
case route: String noLangBaseUrl + route
} pipeTo sender
case Homepage sender ! R.Lobby.home().url
case TeamShow(id) sender ! R.Team.show(id).url
case Player(fullId) sender ! R.Round.player(fullId).url
case Watcher(gameId, color) sender ! R.Round.watcher(gameId, color).url

View File

@ -51,31 +51,12 @@ object Lobby extends LilaController with Results {
def hook(ownerId: String) = Open { implicit ctx
HookRepo.ownedHook(ownerId) flatMap {
_.fold(Redirect(routes.Lobby.home).fuccess) { hook
Env.lobby.lobby ! lila.lobby.actorApi.ShakeHook(hook)
renderHome(hook.some, Ok)
}
}
}
def join(hookId: String) = Open { implicit ctx
val myHookId = get("cancel")
Env.setup.hookJoiner(hookId, myHookId)(ctx.me) map { result
Redirect {
result.fold(
_ myHookId.fold(routes.Lobby.home)(routes.Lobby.hook(_)),
pov routes.Round.player(pov.fullId))
}
}
}
def cancel(ownerId: String) = Open { implicit ctx
HookRepo ownedHook ownerId foreach {
_ foreach { hook
Env.lobby.lobby ! lila.lobby.actorApi.RemoveHook(hook)
}
}
Redirect(routes.Lobby.home).fuccess
}
def log = Open { implicit ctx
Env.lobby.messenger.recent(ctx.troll, 200) map { html.lobby.log(_) }
}

View File

@ -41,10 +41,7 @@ underchat = underchat.some) {
<span class="number">(0)</span>
</a>
<div class="filter"></div>
<div class="hooks"
data-my-hook="@myHook.map(_.ownerId)"
data-cancel-url="@routes.Lobby.cancel("000000000000")"
data-join-url="@routes.Lobby.join("00000000")">
<div class="hooks" data-my-hook="@myHook.map(_.ownerId)">
<table class="some"></table>
<table class="empty">
<tr class="create_game">

View File

@ -1,8 +1,6 @@
# Lobby
GET / controllers.Lobby.home
GET /new/$ownerId<[\w\-]{12}> controllers.Lobby.hook(ownerId: String)
GET /new/$ownerId<[\w\-]{12}>/cancel controllers.Lobby.cancel(ownerId: String)
GET /new/$hookId<[\w\-]{8}>/join controllers.Lobby.join(hookId: String)
GET /lobby/socket controllers.Lobby.socket
GET /lobby/log controllers.Lobby.log

View File

@ -52,6 +52,7 @@ package message {
package router {
case class Abs(route: Any)
case class Nolang(route: Any)
case object Homepage
case class TeamShow(id: String)
case class Player(fullId: String)
case class Watcher(gameId: String, color: String)

View File

@ -1,45 +1,39 @@
package lila.setup
package lila.lobby
import lila.lobby.{ HookRepo, Hook }
import lila.lobby.actorApi.{ RemoveHook, BiteHook }
import actorApi.{ RemoveHook, BiteHook, JoinHook }
import lila.user.{ User, UserRepo }
import chess.{ Game ChessGame, Board, Variant, Mode, Clock, Color ChessColor }
import lila.game.{ GameRepo, Game, Player, Pov, Progress }
import lila.round.Messenger
import lila.user.tube.userTube
import lila.lobby.tube.hookTube
import lila.game.tube.gameTube
import lila.db.api._
private[setup] final class HookJoiner(
lobby: lila.hub.ActorLazyRef,
timeline: lila.hub.ActorLazyRef,
messenger: Messenger) {
import akka.actor.ActorRef
def apply(hookId: String, myHookId: Option[String])(me: Option[User]): Fu[Valid[Pov]] = for {
private[lobby] final class Biter(
timeline: lila.hub.ActorLazyRef,
roundMessenger: lila.round.Messenger) {
def apply(hookId: String, userId: Option[String]): Fu[String JoinHook] = for {
hookOption $find.byId[Hook](hookId)
myHookOption myHookId ?? HookRepo.ownedHook
result hookOption.fold(fuccess(!![Pov]("No such hook"))) { hook
if (canJoin(hook, me)) join(hook, myHookOption)(me) map success
else fuccess(!![Pov]("Can not join hook"))
userOption userId ?? UserRepo.byId
result hookOption.fold[Fu[String JoinHook]](fufail("No such hook")) { hook
if (canJoin(hook, userOption)) join(hook, userOption)
else fufail("Can not join hook")
}
} yield result
private def join(hook: Hook, myHook: Option[Hook])(me: Option[User]): Fu[Pov] = for {
_ fuccess(myHook foreach { h lobby ! RemoveHook(h) })
ownerOption hook.userId ?? $find.byId[User]
private def join(hook: Hook, userOption: Option[User]): Fu[String JoinHook] = for {
ownerOption hook.userId ?? UserRepo.byId
game = blame(
_.invitedColor, me,
_.invitedColor, userOption,
blame(_.creatorColor, ownerOption, makeGame(hook))
).start
_ (GameRepo insertDenormalized game) >>-
(timeline ! game) >>
// messenges are not sent to the game socket
// as nobody is there to see them yet
(messenger init game) >>-
(lobby ! BiteHook(hook, game))
} yield Pov(game, game.invitedColor)
(roundMessenger init game)
} yield uid JoinHook(uid, hook, game)
def blame(color: Game ChessColor, userOption: Option[User], game: Game) =
userOption.fold(game)(user game.updatePlayer(color(game), _ withUser user))
@ -62,8 +56,8 @@ private[setup] final class HookJoiner(
source = lila.game.Source.Lobby,
pgnImport = None)
private def canJoin(hook: Hook, me: Option[User]) = !hook.`match` && {
hook.realMode.casual || (me exists { u
private def canJoin(hook: Hook, userOption: Option[User]) = !hook.`match` && {
hook.realMode.casual || (userOption exists { u
hook.realEloRange.fold(true)(_ contains u.elo)
})
}

View File

@ -10,7 +10,9 @@ import akka.actor._
final class Env(
config: Config,
db: lila.db.Env,
hub: lila.hub.Env,
flood: lila.security.Flood,
roundMessenger: lila.round.Messenger,
system: ActorSystem,
scheduler: lila.common.Scheduler) {
@ -30,18 +32,25 @@ final class Env(
private val socket = system.actorOf(Props(new Socket(
messenger = messenger,
history = history,
router = hub.actor.router,
uidTtl = SocketUidTtl
)), name = SocketName)
val lobby = system.actorOf(Props(new Lobby(
biter = biter,
socket = socket,
hookMemo = hookMemo
)), name = ActorName)
lazy val socketHandler = new SocketHandler(
lobby = lobby,
socket = socket,
messenger = messenger)
lazy val messenger = new Messenger(flood = flood, netDomain = NetDomain)
lazy val history = new History(ttl = MessageTtl)
{
import scala.concurrent.duration._
@ -53,14 +62,14 @@ final class Env(
lobby -> lila.socket.actorApi.Broom
}
scheduler.future(20 seconds, "lobby: cleanup") {
scheduler.future(30 seconds, "lobby: cleanup") {
HookRepo.cleanupOld
}
}
lazy val history = new History(ttl = MessageTtl)
lazy val messenger = new Messenger(flood = flood, netDomain = NetDomain)
private lazy val biter = new Biter(
timeline = hub.actor.timeline,
roundMessenger = roundMessenger)
private lazy val hookMemo = new ExpireSetMemo(ttl = OrphanHookTtl)
@ -73,7 +82,9 @@ object Env {
lazy val current = "[boot] lobby" describes new Env(
config = lila.common.PlayApp loadConfig "lobby",
db = lila.db.Env.current,
hub = lila.hub.Env.current,
flood = lila.security.Env.current.flood,
roundMessenger = lila.round.Env.current.messenger,
system = lila.common.PlayApp.system,
scheduler = lila.common.PlayApp.scheduler)
}

View File

@ -11,6 +11,7 @@ import akka.actor._
import akka.pattern.{ ask, pipe }
private[lobby] final class Lobby(
biter: Biter,
hookMemo: ExpireSetMemo,
socket: ActorRef) extends Actor {
@ -23,16 +24,16 @@ private[lobby] final class Lobby(
$insert(hook) >>- (socket ! msg) >>- shake(hook)
}
case msg @ RemoveHook(hook) blocking {
remove(hook)
case msg @ CancelHook(ownerId) socket ! blocking {
removeByOwnerId(ownerId) inject msg
}
case msg @ BiteHook(hook, game) blocking {
HookRepo.setGame(hook, game) >>-
(socket ! RemoveHook(hook)) >>-
(socket ! msg)
case BiteHook(hookId, uid, userId, hookOwnerId) socket ! blocking {
(hookOwnerId ?? removeByOwnerId) >> biter(hookId, userId) map { _(uid) }
}
case ShakeHook(hook) shake(hook)
case Broom blocking {
HookRepo unmatchedNotInOwnerIds hookMemo.keys flatMap { hooks
(hooks map remove).sequence.void
@ -43,12 +44,13 @@ private[lobby] final class Lobby(
// mark the hook as active, once
private def shake(hook: Hook) { hookMemo put hook.ownerId }
private def removeByOwnerId(ownerId: String) =
HookRepo ownedHook ownerId flatMap { _ ?? remove }
private def remove(hook: Hook) =
$remove(hook) >>-
(socket ! RemoveHook(hook)) >>-
(hookMemo remove hook.ownerId)
private def blocking(f: Funit) {
f await 1.second
}
private def blocking[A](f: Fu[A]): A = f await 1.second
}

View File

@ -5,8 +5,11 @@ import lila.socket.{ SocketActor, History, Historical }
import lila.socket.actorApi.{ Connected _, _ }
import lila.game.actorApi._
import lila.hub.actorApi.lobby._
import lila.hub.actorApi.router.{ Homepage, Player }
import makeTimeout.short
import akka.actor._
import akka.pattern.ask
import play.api.libs.json._
import play.api.libs.iteratee._
import play.api.templates.Html
@ -15,8 +18,8 @@ import scala.concurrent.duration._
private[lobby] final class Socket(
messenger: Messenger,
val history: History,
uidTtl: Duration)
extends SocketActor[Member](uidTtl) with Historical[Member] {
router: lila.hub.ActorLazyRef,
uidTtl: Duration) extends SocketActor[Member](uidTtl) with Historical[Member] {
def receiveSpecific = {
@ -70,14 +73,20 @@ private[lobby] final class Socket(
case RemoveHook(hook) notifyVersion("hook_remove", hook.id)
case BiteHook(hook, game) notifyMember(
"redirect", game fullIdOf game.creatorColor) _ |> { fn
members.values filter (_ ownsHook hook) foreach fn
}
case CancelHook(ownerId) homeUrl foreach { url
hookOwner(ownerId) foreach notifyMember("redirect", url)
}
case JoinHook(uid, hook, game) playerUrl(game fullIdOf game.creatorColor) foreach { url
hookOwner(hook.ownerId) foreach notifyMember("redirect", url)
}
case ChangeFeatured(html) notifyFeatured(html)
}
private lazy val homeUrl = router ? Homepage mapTo manifest[String]
private def playerUrl(fullId: String) = router ? Player(fullId) mapTo manifest[String]
private def notifyFeatured(html: Html) {
broadcast(makeMessage("featured", html.toString))
}
@ -92,4 +101,7 @@ private[lobby] final class Socket(
private def hookOwnerIds: Iterable[String] =
members.values.map(_.hookOwnerId).flatten
private def hookOwner(ownerId: String): Iterable[Member] =
members.values filter (_.hookOwnerId == ownerId.some)
}

View File

@ -14,6 +14,7 @@ import play.api.libs.json._
import play.api.libs.iteratee._
private[lobby] final class SocketHandler(
lobby: ActorRef,
socket: ActorRef,
messenger: Messenger) {
@ -22,6 +23,12 @@ private[lobby] final class SocketHandler(
uid: String,
member: Member): Handler.Controller = {
case ("p", o) o int "v" foreach { v socket ! PingVersion(uid, v) }
case ("join", o) o str "d" foreach { id
lobby ! BiteHook(id, uid, member.userId, member.hookOwnerId)
}
case ("cancel", o) o str "d" foreach { ownerId
lobby ! CancelHook(ownerId)
}
case ("talk", o) for {
userId member.userId
text o str "d"

View File

@ -27,7 +27,14 @@ case class Connected(enumerator: JsEnumerator, member: Member)
case class WithHooks(op: Iterable[String] Unit)
case class AddHook(hook: Hook)
case class RemoveHook(hook: Hook)
case class BiteHook(hook: Hook, game: Game)
case class ShakeHook(hook: Hook)
case class CancelHook(ownerId: String)
case class BiteHook(
hookId: String,
uid: String,
userId: Option[String],
hookOwnerId: Option[String])
case class JoinHook(uid: String, hook: Hook, game: Game)
case class AddEntry(entry: Entry)
case class Join(
uid: String,

View File

@ -35,11 +35,6 @@ final class Env(
router = hub.actor.router,
timeline = hub.actor.timeline)
lazy val hookJoiner = new HookJoiner(
lobby = hub.actor.lobby,
timeline = hub.actor.timeline,
messenger = messenger)
lazy val friendConfigMemo = new FriendConfigMemo(ttl = FriendMemoTtl)
private[setup] lazy val userConfigColl = db(CollectionUserConfig)

View File

@ -278,6 +278,15 @@ var lichess_translations = [];
}, 2000);
}
$('#lichess').on('click', 'a.socket-link', function() {
console.debug(
$(this).data('msg'),
$(this).data('data'));
lichess.socket.send(
$(this).data('msg'),
$(this).data('data'));
});
// Start game
var $game = $('div.lichess_game').orNot();
if ($game) $game.game(_ld_);
@ -585,10 +594,6 @@ var lichess_translations = [];
$('body').data('tournament-id', self.options.tournament_id);
}
self.$tableInner.on('click', 'a.socket-link', function() {
lichess.socket.send($(this).data('msg'));
});
if (self.options.game.started) {
self.indicateTurn();
self.initSquaresAndPieces();
@ -1675,10 +1680,6 @@ var lichess_translations = [];
var $hooks = $wrap.find('div.hooks');
var $hooksTable = $hooks.find("table.some").on('click', 'a.join', $.lichessOpeningPreventClicks);
var $hooksTableEmpty = $hooks.find("table.empty");
var actionUrls = {
'cancel': $hooks.data('cancel-url'),
'join': $hooks.data('join-url')
};
var $userTag = $('#user_tag');
var isRegistered = $userTag.length > 0
var myElo = isRegistered ? parseInt($userTag.data('elo')) : null;
@ -1874,10 +1875,9 @@ var lichess_translations = [];
html += '<td>' + $.trans(hook.clock) + '</td>';
html += '<td class="action">';
if (hook.action == "cancel") {
html += '<a href="' + actionUrls.cancel.replace(/\/0{12}/, '/' + hook.ownerId) + '" class="cancel"></a>';
html += '<a class="cancel socket-link" data-msg="cancel" data-data=' + hook.ownerId + '"></a>';
} else {
var cancelParam = hookOwnerId ? "?cancel=" + hookOwnerId : ""
html += '<a href="' + actionUrls.join.replace(/\/0{8}/, '/' + hook.id) + cancelParam + '" class="join"></a>';
html += '<a class="join socket-link" data-msg="join" data-data="' + hook.id + '"></a>';
}
html += '</td>';
html += '</tr>';