perform all lobby hook actions through actors
parent
4d89b1bdc4
commit
4dbed3f627
|
@ -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
|
||||
|
|
|
@ -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(_) }
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>';
|
||||
|
|
Loading…
Reference in New Issue