reporting app

pull/83/head
Thibault Duplessis 2013-05-08 15:30:55 -03:00
parent 18fa379dbe
commit 9655a1b786
19 changed files with 132 additions and 113 deletions

View File

@ -20,7 +20,7 @@ final class Env(config: Config, system: ActorSystem, isServer: Boolean) {
)), name = RouterName)
loginfo("[boot] Preloading modules")
(Env.site, Env.game, Env.setup, Env.game, Env.gameSearch, Env.team,
(Env.site, Env.game, Env.ai, Env.setup, Env.round, Env.gameSearch, Env.team,
Env.teamSearch, Env.forumSearch, Env.message, Env.socket)
if (Env.ai.isServer) println("Running as AI server")

View File

@ -1,44 +1,36 @@
package controllers
import play.api.mvc._
import play.api.libs.Comet
import play.api.libs.json._
import akka.pattern.ask
import lila.app._
import lila.monitor.actorApi._
import lila.socket.actorApi.GetNbMembers
// import lila.monitor._
import makeTimeout.short
object Monitor extends LilaController {
// private def reporting = env.monitor.reporting
// private def usernameMemo = env.user.usernameMemo
// private def userRepo = env.user.userRepo
// private def gameRepo = env.game.gameRepo
private def env = Env.monitor
def index = TODO
// Action {
// Ok(views.html.monitor.monitor())
// }
def index = Action {
Ok(views.html.monitor.monitor())
}
// def websocket = WebSocket.async[JsValue] { implicit req
// env.monitor.socket.join(uidOption = get("sri", req))
// }
def websocket = WebSocket.async[JsValue] { implicit req
get("sri", req) zmap env.socketHandler.join
}
// def status = Open { implicit ctx
// Async {
// import lila.common.Futuristic.ioToFuture
// (~get("key") match {
// case "elo"
// userRepo.idsAverageElo(usernameMemo.keys).toFuture zip
// gameRepo.recentAverageElo(5).toFuture map {
// case (users, (rated, casual)) List(users, rated, casual) mkString " "
// }
// case "moves" (reporting ? GetNbMoves).mapTo[Int]
// case "players" (reporting ? GetNbMembers).mapTo[Int] map { "%d %d".format(_, usernameMemo.preciseCount) }
// case _ (reporting ? GetStatus).mapTo[String]
// }) map { x Ok(x.toString) }
// }
// }
def status = Open { implicit ctx
(~get("key") match {
case "elo"
lila.user.UserRepo.idsAverageElo(Env.user.usernameMemo.keys) zip
lila.game.GameRepo.recentAverageElo(5) map {
case (users, (rated, casual)) List(users, rated, casual) mkString " "
}
case "moves" (env.reporting ? GetNbMoves).mapTo[Int]
case "players" (env.reporting ? GetNbMembers).mapTo[Int] map { "%d %d".format(_, Env.user.usernameMemo.count) }
case _ (env.reporting ? GetStatus).mapTo[String]
}) map { x Ok(x.toString) }
}
}

View File

@ -177,10 +177,8 @@ POST /import controllers.Importer.sendGame
# Monitor
GET /monitor controllers.Monitor.index
# GET /monitor/socket controllers.Monitor.websocket
# GET /monitor/players controllers.Monitor.nbPlayers
# GET /monitor/mps controllers.Monitor.nbMoves
# GET /monitor/status controllers.Monitor.status
GET /monitor/socket controllers.Monitor.websocket
GET /monitor/status controllers.Monitor.status
# Misc
POST /cli controllers.Cli.command

View File

@ -2,7 +2,7 @@ package lila.ai
import lila.common.PimpedConfig._
import akka.actor.{ ActorRef, ActorSystem }
import akka.actor._
import com.typesafe.config.Config
final class Env(
@ -17,6 +17,7 @@ final class Env(
val StockfishExecPath = config getString "stockfish.exec_path"
val StockfishPlayUrl = config getString "stockfish.play.url"
val StockfishAnalyseUrl = config getString "stockfish.analyse.url"
val ActorName = config getString "actor.name"
}
import settings._
@ -32,6 +33,13 @@ final class Env(
def isServer = IsServer
// api actor
system.actorOf(Props(new Actor {
def receive = {
case lila.hub.actorApi.ai.Ping sender ! clientPing
}
}), name = ActorName)
{
import scala.concurrent.duration._
@ -39,7 +47,7 @@ final class Env(
clientDiagnose
}
scheduler.once(5 millis) { clientDiagnose }
scheduler.once(10 millis) { clientDiagnose }
}
private lazy val stockfishAi = new stockfish.Ai(

View File

@ -3,6 +3,7 @@ package lila.game
import com.typesafe.config.Config
import lila.common.PimpedConfig._
import akka.actor._
import akka.pattern.pipe
final class Env(
config: Config,
@ -21,6 +22,7 @@ final class Env(
val CollectionPgn = config getString "collection.pgn"
val JsPathRaw = config getString "js_path.raw"
val JsPathCompiled = config getString "js_path.compiled"
val ActorName = config getString "actor.name"
}
import settings._
@ -50,6 +52,13 @@ final class Env(
// load captcher actor
system.actorOf(Props(new Captcher), name = CaptcherName)
// api actor
system.actorOf(Props(new Actor {
def receive = {
case lila.hub.actorApi.game.Count cached.nbGames pipeTo sender
}
}), name = ActorName)
{
import scala.concurrent.duration._

View File

@ -7,8 +7,11 @@ import lila.user.User
import lila.db.api._
import lila.db.Implicits._
import tube.gameTube
import lila.common.PimpedJson._
import play.api.libs.json._
import play.modules.reactivemongo.json.ImplicitBSONHandlers.JsObjectWriter
import play.modules.reactivemongo.json.BSONFormats.toJSON
import org.joda.time.DateTime
import org.scala_tools.time.Imports._
@ -19,8 +22,7 @@ object GameRepo {
type ID = String
import Game._
import Game.ShortFields._
import Game._, ShortFields._
def game(gameId: ID): Fu[Option[Game]] = $find byId gameId
@ -140,35 +142,39 @@ object GameRepo {
$count(Json.obj(createdAt -> ($gte(from) ++ $lt(to))))
}
// def recentAverageElo(minutes: Int): Fu[(Int, Int)] = io {
// val result = collection.mapReduce(
// mapFunction = """function() {
// emit(!!this.ra, this.p);
// }""",
// reduceFunction = """function(rated, values) {
// var sum = 0, nb = 0;
// values.forEach(function(game) {
// if(typeof game[0] != "undefined") {
// game.forEach(function(player) {
// if(player.elo) {
// sum += player.elo;
// ++nb;
// }
// });
// }
// });
// return nb == 0 ? nb : Math.round(sum / nb);
// }""",
// output = MapReduceInlineOutput,
// query = Some {
// (createdAt $gte (DateTime.now - minutes.minutes)) ++ ("p.elo" $exists true)
// }
// )
// (for {
// ratedRow result.hasNext option result.next
// rated ratedRow.getAs[Double]("value")
// casualRow result.hasNext option result.next
// casual casualRow.getAs[Double]("value")
// } yield rated.toInt -> casual.toInt) | (0, 0)
// }
def recentAverageElo(minutes: Int): Fu[(Int, Int)] = {
val command = MapReduce(
collectionName = gameTube.coll.name,
mapFunction = """function() {
emit(!!this.ra, this.p);
}""",
reduceFunction = """function(rated, values) {
var sum = 0, nb = 0;
values.forEach(function(game) {
if(typeof game[0] != "undefined") {
game.forEach(function(player) {
if(player.elo) {
sum += player.elo;
++nb;
}
});
}
});
return nb == 0 ? nb : Math.round(sum / nb);
}""",
query = Some(JsObjectWriter write Json.obj(
createdAt -> $gte(DateTime.now - minutes.minutes),
"p.elo" -> $exists(true)
))
)
gameTube.coll.db.command(command) map { res
toJSON(res).pp.arr("results").pp.flatMap(_.apply(0) int "value")
} map (~_) inject (0, 0)
// (for {
// ratedRow result.hasNext option result.next
// rated ratedRow.getAs[Double]("value")
// casualRow result.hasNext option result.next
// casual casualRow.getAs[Double]("value")
// } yield rated.toInt -> casual.toInt) | (0, 0)
}
}

View File

@ -10,6 +10,7 @@ final class Env(config: Config, system: ActorSystem) {
private val SocketHubTimeout = config duration "socket.hub.timeout"
object actor {
val game = actorFor("game.actor")
val gameIndexer = actorFor("game.indexer")
val renderer = actorFor("renderer")
val captcher = actorFor("captcher")
@ -29,6 +30,7 @@ final class Env(config: Config, system: ActorSystem) {
val lobby = socketFor("lobby")
val monitor = socketFor("monitor")
val site = socketFor("site")
val round = socketFor("round")
val hub = system.actorOf(Props(new Broadcast(List(
socket.lobby, socket.site
))(makeTimeout(SocketHubTimeout))), name = SocketHubName)

View File

@ -28,6 +28,10 @@ package lobby {
case class Censor(username: String)
}
package game {
case object Count
}
package message {
case class LichessThread(to: String, subject: String, message: String)
}
@ -44,6 +48,7 @@ package forum {
}
package ai {
case object Ping
case class Analyse(pgn: String, initialFen: Option[String])
}

View File

@ -22,10 +22,11 @@ final class Env(
lazy val socketHandler = new SocketHandler(socket)
lazy val reporting = system.actorOf(
val reporting = system.actorOf(
Props(new Reporting(
rpsProvider = rpsProvider,
mpsProvider = mpsProvider,
socket = socket,
db = db,
hub = hub
)), name = ActorName)
@ -33,8 +34,8 @@ final class Env(
{
import scala.concurrent.duration._
scheduler.message(5 seconds) {
reporting -> actorApi.Update
scheduler.message(1 seconds) {
reporting -> lila.hub.actorApi.monitor.Update
}
}

View File

@ -1,9 +1,8 @@
package lila.monitor
import actorApi._
import lila.socket.actorApi.GetNbMembers
import lila.socket.actorApi.{ GetNbMembers, GetNbHubs }
import lila.hub.actorApi.monitor._
// import round.GetNbHubs
import akka.actor._
import akka.pattern.{ ask, pipe }
@ -16,6 +15,7 @@ import java.lang.management.ManagementFactory
private[monitor] final class Reporting(
rpsProvider: RpsProvider,
mpsProvider: RpsProvider,
socket: ActorRef,
db: lila.db.Env,
hub: lila.hub.Env) extends Actor {
@ -61,37 +61,35 @@ private[monitor] final class Reporting(
case GetMonitorData sender ! monitorData
// TODO
// case Update {
// val before = nowMillis
// List(
// (env.site.hub ? GetNbMembers).mapTo[Int],
// (hub.actor.lobby ? GetNbMembers).mapTo[Int],
// (env.round.hubMaster ? GetNbHubs).mapTo[Int],
// (env.round.hubMaster ? GetNbMembers).mapTo[Int]
// ).sequence onComplete {
// case Failure(e) logwarn("[reporting] " + e.getMessage)
// case Success(List(
// siteMembers,
// lobbyMembers,
// gameHubs,
// gameMembers)) {
// latency = (nowMillis - before).toInt
// site = SiteSocket(siteMembers)
// lobby = LobbySocket(lobbyMembers)
// game = GameSocket(gameHubs, gameMembers)
// mongoStatus = MongoStatus(mongodb)(mongoStatus)
// nbGames = env.game.cached.nbGames
// loadAvg = osStats.getSystemLoadAverage.toFloat
// nbThreads = threadStats.getThreadCount
// memory = memoryStats.getHeapMemoryUsage.getUsed / 1024 / 1024
// rps = rpsProvider.rps
// mps = mpsProvider.rps
// cpu = ((cpuStats.getCpuUsage() * 1000).round / 10.0).toInt
// clientAi = env.ai.clientPing
// hub ! MonitorData(monitorData)
// }
// }
case Update {
val before = nowMillis
MongoStatus(db.db)(mongoStatus) zip
(hub.actor.ai ? lila.hub.actorApi.ai.Ping).mapTo[Option[Int]] zip
List((hub.socket.site ? GetNbMembers),
(hub.socket.lobby ? GetNbMembers),
(hub.socket.round ? GetNbHubs),
(hub.socket.round ? GetNbMembers),
(hub.actor.game ? lila.hub.actorApi.game.Count)
).map(_.mapTo[Int]).sequence onComplete {
case Failure(e) logwarn("[reporting] " + e.getMessage)
case Success(((mongoS, aiPing), List(siteMembers, lobbyMembers, gameHubs, gameMembers, games))) {
latency = (nowMillis - before).toInt
site = SiteSocket(siteMembers)
lobby = LobbySocket(lobbyMembers)
game = GameSocket(gameHubs, gameMembers)
mongoStatus = mongoS
nbGames = games
loadAvg = osStats.getSystemLoadAverage.toFloat
nbThreads = threadStats.getThreadCount
memory = memoryStats.getHeapMemoryUsage.getUsed / 1024 / 1024
rps = rpsProvider.rps
mps = mpsProvider.rps
cpu = ((cpuStats.getCpuUsage() * 1000).round / 10.0).toInt
clientAi = aiPing
socket ! MonitorData(monitorData)
}
}
}
}
private def display {

View File

@ -11,7 +11,7 @@ private[monitor] final class SocketHandler(socket: ActorRef) {
def join(uid: String): Fu[JsSocketHandler] = {
def controller: Handler.Controller = {
case _ =>
case _
}
Handler(socket, uid, Join(uid)) {

View File

@ -12,7 +12,5 @@ case object GetNbMoves
case object GetStatus
case object GetMonitorData
case object Update
case class Join(uid: String)
case class MonitorData(data: List[String])

View File

@ -35,7 +35,7 @@ final class Env(
lazy val history = () new History(ttl = MessageTtl)
lazy val socketHub = system.actorOf(Props(new SocketHub(
val socketHub = system.actorOf(Props(new SocketHub(
makeHistory = history,
uidTimeout = UidTimeout,
socketTimeout = SocketTimeout,

View File

@ -30,6 +30,8 @@ private[round] final class SocketHub(
case msg @ GameEvents(gameId, events) sockets get gameId foreach (_ forward msg)
case GetNbHubs sender ! sockets.size
case GetSocket(id) sender ! {
(sockets get id) | {
mkSocket(id) ~ { h sockets = sockets + (id -> h) }

View File

@ -9,6 +9,7 @@ case class Connected[M <: SocketMember](
case object Close
case object GetNbMembers
case class NbMembers(nb: Int)
case object GetNbHubs
case class Ping(uid: String)
case class PingVersion(uid: String, version: Int)
case object Broom

View File

@ -128,7 +128,7 @@ object UserRepo {
def idsAverageElo(ids: Iterable[String]): Fu[Int] = {
val command = MapReduce(
collectionName = tube.userTube.coll.name,
collectionName = userTube.coll.name,
mapFunction = """function() { emit("e", this.elo); }""",
reduceFunction = """function(key, values) {
var sum = 0;
@ -139,14 +139,14 @@ object UserRepo {
JsObjectWriter write Json.obj("_id" -> $in(ids map normalize))
}
)
tube.userTube.coll.db.command(command) map { res
userTube.coll.db.command(command) map { res
toJSON(res).arr("results").flatMap(_.apply(0) int "value")
} map (~_)
}
def idsSumToints(ids: Iterable[String]): Fu[Int] = {
val command = MapReduce(
collectionName = tube.userTube.coll.name,
collectionName = userTube.coll.name,
mapFunction = """function() { emit("e", this.toints); }""",
reduceFunction = """function(key, values) {
var sum = 0;
@ -157,7 +157,7 @@ object UserRepo {
JsObjectWriter write Json.obj("_id" -> $in(ids map normalize))
}
)
tube.userTube.coll.db.command(command) map { res
userTube.coll.db.command(command) map { res
toJSON(res).arr("results").flatMap(_.apply(0) int "value")
} map (~_)
}

View File

@ -37,7 +37,6 @@ case object Start
case object Reload
case object ReloadPage
case object HubTimeout
case object GetNbHubs
case class StartGame(game: DbGame)
case class Joining(userId: String)