send empty frames for ping; keep bot player alive in the game socket
This commit is contained in:
parent
c1b409a489
commit
e273ad4232
|
@ -14,7 +14,7 @@ object Bot extends LilaController {
|
|||
WithMyBotGame(id, me) { pov =>
|
||||
RequireHttp11(req) {
|
||||
lila.game.GameRepo.withInitialFen(pov.game) map { wf =>
|
||||
Ok.chunked(Env.bot.gameStateStream(wf))
|
||||
Ok.chunked(Env.bot.gameStateStream(me, wf, pov.color))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ final class EventStream(
|
|||
|
||||
var stream: Option[ActorRef] = None
|
||||
|
||||
val enumerator = Concurrent.unicast[JsObject](
|
||||
val enumerator = Concurrent.unicast[Option[JsObject]](
|
||||
onStart = channel => {
|
||||
val actor = system.actorOf(Props(new Actor {
|
||||
|
||||
|
@ -34,9 +34,11 @@ final class EventStream(
|
|||
|
||||
case SetOnline =>
|
||||
setOnline(me.id)
|
||||
context.system.scheduler.scheduleOnce(6 second, self, SetOnline)
|
||||
// gotta send a message to check if the client has disconnected
|
||||
channel push Json.obj("up" -> true)
|
||||
context.system.scheduler.scheduleOnce(6 second) {
|
||||
// gotta send a message to check if the client has disconnected
|
||||
channel push None
|
||||
self ! SetOnline
|
||||
}
|
||||
|
||||
case UserStartGame(userId, game) if userId == me.id => pushGameStart(game)
|
||||
|
||||
|
@ -46,12 +48,12 @@ final class EventStream(
|
|||
def pushGameStart(game: Game) = channel push Json.obj(
|
||||
"type" -> "gameStart",
|
||||
"game" -> Json.obj("id" -> game.id)
|
||||
)
|
||||
).some
|
||||
|
||||
def pushChallenge(c: lila.challenge.Challenge) = channel push Json.obj(
|
||||
"type" -> "challenge",
|
||||
"challenge" -> challengeJsonView(none)(c)
|
||||
)
|
||||
).some
|
||||
}))
|
||||
system.lilaBus.subscribe(actor, Symbol(s"userStartGame:${me.id}"), 'challenge)
|
||||
stream = actor.some
|
||||
|
@ -59,6 +61,6 @@ final class EventStream(
|
|||
onComplete = onComplete(stream, system)
|
||||
)
|
||||
|
||||
enumerator &> stringify
|
||||
enumerator &> stringifyOrEmpty
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,17 @@ import akka.actor._
|
|||
final class Env(
|
||||
system: ActorSystem,
|
||||
hub: lila.hub.Env,
|
||||
onlineUserIds: lila.memo.ExpireSetMemo,
|
||||
lightUserApi: lila.user.LightUserApi
|
||||
) {
|
||||
|
||||
lazy val jsonView = new BotJsonView(lightUserApi)
|
||||
|
||||
lazy val gameStateStream = new GameStateStream(system, jsonView)
|
||||
lazy val gameStateStream = new GameStateStream(
|
||||
system,
|
||||
jsonView,
|
||||
hub.socket.round
|
||||
)
|
||||
|
||||
lazy val player = new BotPlayer(
|
||||
roundMap = hub.actor.roundMap
|
||||
|
@ -22,6 +27,7 @@ object Env {
|
|||
lazy val current: Env = "bot" boot new Env(
|
||||
system = lila.common.PlayApp.system,
|
||||
hub = lila.hub.Env.current,
|
||||
onlineUserIds = lila.user.Env.current.onlineUserIdMemo,
|
||||
lightUserApi = lila.user.Env.current.lightUserApi
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lila.bot
|
||||
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor._
|
||||
import play.api.libs.iteratee._
|
||||
import play.api.libs.json._
|
||||
|
@ -9,39 +10,51 @@ import chess.format.FEN
|
|||
import lila.game.actorApi.{ FinishGame, AbortedBy }
|
||||
import lila.game.{ Game, GameRepo }
|
||||
import lila.hub.actorApi.round.MoveEvent
|
||||
import lila.hub.actorApi.map.Tell
|
||||
import lila.socket.actorApi.BotPing
|
||||
import lila.user.User
|
||||
|
||||
final class GameStateStream(
|
||||
system: ActorSystem,
|
||||
jsonView: BotJsonView
|
||||
jsonView: BotJsonView,
|
||||
roundSocketHub: ActorSelection
|
||||
) {
|
||||
|
||||
import lila.common.HttpStream._
|
||||
|
||||
def apply(init: Game.WithInitialFen): Enumerator[String] = {
|
||||
def apply(me: User, init: Game.WithInitialFen, as: chess.Color): Enumerator[String] = {
|
||||
|
||||
val id = init.game.id
|
||||
|
||||
var stream: Option[ActorRef] = None
|
||||
|
||||
val enumerator = Concurrent.unicast[JsObject](
|
||||
val enumerator = Concurrent.unicast[Option[JsObject]](
|
||||
onStart = channel => {
|
||||
val actor = system.actorOf(Props(new Actor {
|
||||
|
||||
jsonView gameFull init foreach { json =>
|
||||
// prepend the full game JSON at the start of the stream
|
||||
channel push json
|
||||
channel push json.some
|
||||
// close stream if game is over
|
||||
if (init.game.finished) channel.eofAndEnd()
|
||||
}
|
||||
self ! SetOnline
|
||||
|
||||
def receive = {
|
||||
case g: Game if g.id == id => pushState(g)
|
||||
case FinishGame(g, _, _) if g.id == id => terminate
|
||||
case AbortedBy(pov) if pov.gameId == id => terminate
|
||||
|
||||
case SetOnline =>
|
||||
roundSocketHub ! Tell(init.game.id, BotPing(as))
|
||||
context.system.scheduler.scheduleOnce(6 second) {
|
||||
// gotta send a message to check if the client has disconnected
|
||||
channel push None
|
||||
self ! SetOnline
|
||||
}
|
||||
}
|
||||
|
||||
def pushState(g: Game) = jsonView gameState Game.WithInitialFen(g, init.fen) map channel.push
|
||||
def pushState(g: Game) = jsonView gameState Game.WithInitialFen(g, init.fen) map some map channel.push
|
||||
def terminate = channel.eofAndEnd()
|
||||
}))
|
||||
system.lilaBus.subscribe(actor, Symbol(s"moveGame:$id"), 'finishGame, 'abortGame)
|
||||
|
@ -50,6 +63,6 @@ final class GameStateStream(
|
|||
onComplete = onComplete(stream, system)
|
||||
)
|
||||
|
||||
enumerator &> stringify
|
||||
enumerator &> stringifyOrEmpty
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@ object HttpStream {
|
|||
Json.stringify(js) + "\n"
|
||||
}
|
||||
|
||||
val stringifyOrEmpty =
|
||||
Enumeratee.map[Option[JsObject]].apply[String] {
|
||||
case None => "\n"
|
||||
case Some(js) => Json.stringify(js) + "\n"
|
||||
}
|
||||
|
||||
def onComplete(stream: Option[ActorRef], system: ActorSystem) =
|
||||
stream foreach { actor =>
|
||||
system.lilaBus.unsubscribe(actor)
|
||||
|
|
|
@ -141,6 +141,8 @@ private[round] final class Socket(
|
|||
(history getEventsSince v).fold(resyncNow(member))(batch(member, _))
|
||||
}
|
||||
|
||||
case BotPing(color) => playerDo(color.pp("bot ping"), _.ping)
|
||||
|
||||
case Bye(color) => playerDo(color, _.setBye)
|
||||
|
||||
case Broom =>
|
||||
|
|
|
@ -11,6 +11,7 @@ case class Connected[M <: SocketMember](
|
|||
)
|
||||
case class Sync(uid: String, friends: List[String])
|
||||
case class Ping(uid: String, version: Option[Int], lagCentis: Option[Centis])
|
||||
case class BotPing(color: chess.Color)
|
||||
|
||||
object Ping {
|
||||
def apply(uid: Socket.Uid, o: JsObject): Ping =
|
||||
|
|
Loading…
Reference in a new issue