Remove previous cheat evaluator. Farewell, good cop, you did a great job

pull/363/head
Thibault Duplessis 2015-03-19 18:14:05 +01:00
parent 49d3f497ca
commit fb85cd0207
17 changed files with 10 additions and 303 deletions

3
.gitmodules vendored
View File

@ -16,9 +16,6 @@
[submodule "submodules/boardcreator"]
path = submodules/boardcreator
url = https://github.com/clarkerubber/board-creator
[submodule "submodules/evaluator"]
path = submodules/evaluator
url = https://github.com/ornicar/engine-evaluator
[submodule "ui/chessli"]
path = ui/chessli
url = https://github.com/ornicar/chess.js

View File

@ -65,7 +65,6 @@ final class Env(
Env.notification,
Env.bookmark,
Env.pref,
Env.evaluation,
Env.chat,
Env.puzzle,
Env.tv,
@ -119,7 +118,6 @@ object Env {
def relation = lila.relation.Env.current
def report = lila.report.Env.current
def pref = lila.pref.Env.current
def evaluation = lila.evaluation.Env.current
def chat = lila.chat.Env.current
def puzzle = lila.puzzle.Env.current
def coordinate = lila.coordinate.Env.current

View File

@ -147,18 +147,12 @@ object User extends LilaController {
def mod(username: String) = Secure(_.UserSpy) { implicit ctx =>
me => OptionFuOk(UserRepo named username) { user =>
(Env.evaluation.evaluator find user) zip (Env.security userSpy user.id) zip (Env.mod.assessApi.getPlayerAggregateAssessment(user.id)) map {
case ((eval, spy), playerAggregateAssessment) => html.user.mod(user, spy, eval, playerAggregateAssessment)
(Env.security userSpy user.id) zip (Env.mod.assessApi.getPlayerAggregateAssessment(user.id)) map {
case (spy, playerAggregateAssessment) => html.user.mod(user, spy, playerAggregateAssessment)
}
}
}
def evaluate(username: String) = Secure(_.UserEvaluate) { implicit ctx =>
me => OptionFuResult(UserRepo named username) { user =>
Env.evaluation.evaluator.generate(user.id, true) inject Redirect(routes.User.show(username).url + "?mod")
}
}
def writeNote(username: String) = AuthBody { implicit ctx =>
me => OptionFuResult(UserRepo named username) { user =>
implicit val req = ctx.body

View File

@ -1,14 +1,11 @@
@(u: User, spy: lila.security.UserSpy, eval: Option[lila.evaluation.Evaluation], optionAggregateAssessment: Option[lila.evaluation.PlayerAggregateAssessment])(implicit ctx: Context)
@(u: User, spy: lila.security.UserSpy, optionAggregateAssessment: Option[lila.evaluation.PlayerAggregateAssessment])(implicit ctx: Context)
@import lila.evaluation.Display
<div class="actions clearfix">
@if(isGranted(_.UserEvaluate)) {
<form method="post" action="@routes.User.evaluate(u.username)">
<input class="button" type="submit" value="@{eval.isDefined.??("(Re)")}Evaluate (old)" />
</form>
<form method="post" action="@routes.Mod.refreshUserAssess(u.username)">
<input class="button" type="submit" value="Evaluate (new)" />
<input class="button" type="submit" value="Evaluate" />
</form>
}
@if(isGranted(_.MarkEngine)) {
@ -52,39 +49,6 @@
</div>
<div class="user_spy">
@eval.map { e =>
<div class="evaluation">
<p>
<strong>@e.verdict(u.perfs)</strong> @e.isDeep.fold("Thoroughly", "Quickly") evaluated @momentFromNow(e.date) as @e.percent%
<br />
<br />
</p>
@if(e.games.nonEmpty) {
<table class="slist">
<thead>
<tr>
<th>Most suspicious games found</th>
<th>Move time</th>
<th>Blur</th>
<th>Analysis</th>
<th>Bot</th>
</tr>
</thead>
<tbody>
@e.games.map { g =>
<tr>
<td><a href="@g.path">@g.path</a></td>
<td>@g.moveTime.map(_ + "%")</td>
<td>@g.blur.map(_ + "%")</td>
<td>@g.error.map(_ + "%")</td>
<td>@g.hold.map(_ + "%")</td>
</tr>
}
</tbody>
</table>
}
</div>
}
@optionAggregateAssessment.fold{
<div class="evaluation">
<p>

View File

@ -30,7 +30,6 @@ GET /rel/blocks controllers.Relation.blocks
# User
GET /@/:username/opponents controllers.User.opponents(username: String)
GET /@/:username/mod controllers.User.mod(username: String)
POST /@/:username/evaluate controllers.User.evaluate(username: String)
POST /@/:username/note controllers.User.writeNote(username: String)
GET /@/:username/mini controllers.User.showMini(username: String)
GET /@/:username/tv controllers.User.tv(username: String)

View File

@ -20,7 +20,6 @@ case class ConcurrentAnalysisException(userId: String, progressId: String, gameI
final class Analyser(
ai: ActorSelection,
indexer: ActorSelection,
evaluator: ActorSelection,
modActor: ActorSelection) {
def get(id: String): Fu[Option[Analysis]] = AnalysisRepo byId id flatMap evictStalled
@ -77,9 +76,6 @@ final class Analyser(
if (analysis.valid) {
indexer ! InsertGame(game)
AnalysisRepo.done(id, analysis) >>- {
game.userIds foreach { userId =>
evaluator ! lila.hub.actorApi.evaluation.Refresh(userId)
}
modActor ! actorApi.AnalysisReady(game, analysis)
} >>- GameRepo.setAnalysed(game.id) inject analysis
}

View File

@ -14,7 +14,6 @@ final class Env(
ai: ActorSelection,
system: ActorSystem,
indexer: ActorSelection,
evaluator: ActorSelection,
modActor: ActorSelection) {
private val CollectionAnalysis = config getString "collection.analysis"
@ -28,7 +27,6 @@ final class Env(
lazy val analyser = new Analyser(
ai = ai,
indexer = indexer,
evaluator = evaluator,
modActor = modActor)
lazy val paginator = new PaginatorBuilder(
@ -66,6 +64,5 @@ object Env {
ai = lila.hub.Env.current.actor.ai,
system = lila.common.PlayApp.system,
indexer = lila.hub.Env.current.actor.gameIndexer,
evaluator = lila.hub.Env.current.actor.evaluator,
modActor = lila.hub.Env.current.actor.mod)
}

View File

@ -1,37 +0,0 @@
package lila.evaluation
import akka.actor._
import com.typesafe.config.Config
final class Env(
config: Config,
db: lila.db.Env,
hub: lila.hub.Env,
system: ActorSystem) {
private val CollectionEvaluation = config getString "collection.evaluation"
private val EvaluatorExecPath = config getString "evaluator.exec_path"
private val ActorName = config getString "actor.name"
private val ApiToken = config getString "api.token"
private val ApiUrl = config getString "api.url"
lazy val evaluator = new Evaluator(
coll = db(CollectionEvaluation),
execPath = EvaluatorExecPath,
reporter = hub.actor.report,
analyser = hub.actor.analyser,
marker = hub.actor.mod,
token = ApiToken,
apiUrl = ApiUrl)
system.actorOf(Props(new Listener(evaluator)), name = ActorName)
}
object Env {
lazy val current = "[boot] evaluation" describes new Env(
config = lila.common.PlayApp loadConfig "evaluation",
db = lila.db.Env.current,
hub = lila.hub.Env.current,
system = lila.common.PlayApp.system)
}

View File

@ -1,142 +0,0 @@
package lila.evaluation
import scala.util.{ Try, Success, Failure }
import akka.actor.ActorSelection
import akka.pattern.ask
import org.joda.time.DateTime
import play.api.libs.json._
import play.api.libs.json.Json
import play.modules.reactivemongo.json.ImplicitBSONHandlers._
import reactivemongo.bson._
import lila.db.api._
import lila.db.BSON.BSONJodaDateTimeHandler
import lila.db.JsTube.Helpers.{ rename, writeDate, readDate }
import lila.db.Types._
import lila.rating.{ Perf, PerfType }
import lila.user.{ User, UserRepo, Perfs }
final class Evaluator(
coll: Coll,
execPath: String,
reporter: ActorSelection,
analyser: ActorSelection,
marker: ActorSelection,
token: String,
apiUrl: String) {
import Evaluation._, heuristics._
def find(user: User): Fu[Option[Evaluation]] =
coll.find(BSONDocument("_id" -> user.id)).one[JsObject] map { _ map readEvaluation }
def evaluatedAt(user: User): Fu[Option[DateTime]] =
coll.find(
BSONDocument("_id" -> user.id),
BSONDocument("date" -> true)
).one[BSONDocument] map { _ flatMap (_.getAs[DateTime]("date")) }
def generate(userId: String, deep: Boolean): Fu[Option[Evaluation]] =
UserRepo byId userId flatMap {
_ ?? { user =>
(run(userId, deep) match {
case Failure(e: Exception) if e.getMessage.contains("exit value: 1") => fuccess(none)
case Failure(e: Exception) if e.getMessage.contains("exit value: 2") => fuccess(none)
case Failure(e: Exception) => fufail(e)
case Success(output) => for {
evalJs (Json parse output).transform(evaluationTransformer) match {
case JsSuccess(v, _) => fuccess(v)
case JsError(e) => fufail(lila.common.LilaException(s"Can't parse evaluator output: $e on $output"))
}
eval = readEvaluation(evalJs)
_ coll.update(Json.obj("_id" -> userId), evalJs, upsert = true)
} yield eval.some
}) andThen {
case Success(Some(eval)) if Evaluation.watchPerfs(user.perfs) exists eval.mark =>
UserRepo byId userId foreach {
_ filterNot (_.engine) foreach { user =>
marker ! lila.hub.actorApi.mod.MarkCheater(user.id)
reporter ! lila.hub.actorApi.report.Check(user.id)
}
}
case Failure(e) => logger.warn(s"generate: $e")
}
}
}
private[evaluation] def autoGenerate(
user: User,
perfType: PerfType,
important: Boolean,
forceRefresh: Boolean,
suspiciousHold: Boolean) {
val perf = user.perfs(perfType)
if (!user.engine && (
important || suspiciousHold ||
(deviationIsLow(perf) && (progressIsHigh(perf) || ratingIsHigh(perf)))
)) {
evaluatedAt(user) foreach { date =>
def freshness = if (progressIsVeryHigh(perf)) DateTime.now minusMinutes 20
else if (progressIsHigh(perf)) DateTime.now minusHours 1
else DateTime.now minusDays 2
if (suspiciousHold || forceRefresh || date.fold(true)(_ isBefore freshness)) {
generate(user.id, true) foreach {
_ foreach { eval =>
eval.gameIdsToAnalyse foreach { gameId =>
analyser ! lila.hub.actorApi.ai.AutoAnalyse(gameId)
if (eval report perf)
reporter ! lila.hub.actorApi.report.Cheater(user.id, eval reportText 3)
}
}
}
}
}
}
}
private[evaluation] def autoGenerate(
user: User,
important: Boolean,
forceRefresh: Boolean,
suspiciousHold: Boolean) {
user.perfs.bestPerf foreach {
case (pt, _) => autoGenerate(user, pt, important, forceRefresh, suspiciousHold)
}
}
private[evaluation] def autoGenerate(userId: String, important: Boolean, forceRefresh: Boolean) {
UserRepo byId userId foreach {
_ foreach { autoGenerate(_, important, forceRefresh, false) }
}
}
private def readEvaluation(js: JsValue): Evaluation =
(readDate('date) andThen Evaluation.reader) reads js match {
case JsSuccess(v, _) => v
case JsError(e) => throw lila.common.LilaException(s"Can't parse evaluator json: $e on $js")
}
private def run(userId: String, deep: Boolean): Try[String] = {
import scala.sys.process._
import java.io.File
val exec = Process(Seq("php", "engine-evaluator.php", userId, deep.fold("true", "false"), token, s"$apiUrl/"), new File(execPath))
Try {
exec.!!
} match {
case Failure(e) => Failure(new Exception(s"$exec $e"))
case x => x
}
}
private def evaluationTransformer =
rename('userId, '_id) andThen
rename('cheatIndex, 'shallow) andThen
rename('deepIndex, 'deep) andThen
rename('computerAnalysis, 'analysis) andThen
rename('knownEngineIP, 'sharedIP) andThen
__.json.update(
__.read[JsObject].map { o => o ++ Json.obj("date" -> $date(DateTime.now)) }
) andThen
(__ \ 'Error).json.prune
private val logger = play.api.Logger("evaluator")
}

View File

@ -1,38 +0,0 @@
package lila.evaluation
import akka.actor._
import lila.game.PerfPicker
import chess.{ Speed, White, Black }
import lila.hub.actorApi.evaluation._
import lila.user.User
import lila.rating.PerfType
private[evaluation] final class Listener(evaluator: Evaluator) extends Actor {
context.system.lilaBus.subscribe(self, 'finishGame)
def receive = {
case lila.game.actorApi.FinishGame(game, white, black) =>
PerfType(PerfPicker key game) ifTrue game.rated map { perfType =>
List(
game.whitePlayer -> white,
game.blackPlayer -> black
) foreach {
case (p, Some(u)) => evaluator.autoGenerate(
user = u,
perfType = perfType,
important = p.wins && game.isTournament && game.speed != Speed.Bullet,
forceRefresh = false,
suspiciousHold = p.hasSuspiciousHoldAlert)
case _ =>
}
}
case user: User => evaluator.generate(user.id, true)
case AutoCheck(userId) => evaluator.autoGenerate(userId, true, false)
case Refresh(userId) => evaluator.autoGenerate(userId, false, true)
}
}

View File

@ -27,7 +27,6 @@ final class Env(config: Config, system: ActorSystem) {
val challenger = select("actor.challenger")
val report = select("actor.report")
val mod = select("actor.mod")
val evaluator = select("actor.evaluator")
val chat = select("actor.chat")
val analyser = select("actor.analyser")
val moveBroadcast = select("actor.move_broadcast")

View File

@ -16,7 +16,7 @@ final class Env(
lazy val forms = new DataForm(hub.actor.captcher)
lazy val api = new ReportApi(hub.actor.evaluator)
lazy val api = new ReportApi
// api actor
system.actorOf(Props(new Actor {

View File

@ -10,7 +10,7 @@ import lila.db.Implicits._
import lila.user.{ User, UserRepo }
import tube.reportTube
private[report] final class ReportApi(evaluator: ActorSelection) {
private[report] final class ReportApi {
def create(setup: ReportSetup, by: User): Funit =
Reason(setup.reason).fold[Funit](fufail("Invalid report reason " + setup.reason)) { reason =>
@ -25,15 +25,9 @@ private[report] final class ReportApi(evaluator: ActorSelection) {
selectRecent(user, reason),
Json.obj("$set" -> (reportTube.toMongo(report).get - "processedBy" - "_id"))
) flatMap { res =>
(!res.updatedExisting) ?? {
if (report.isCheat) evaluator ! user
$insert(report)
}
(!res.updatedExisting) ?? $insert(report)
}
else {
if (report.isCheat) evaluator ! user
$insert(report)
}
else $insert(report)
}
}

View File

@ -91,8 +91,7 @@ final class Env(
renderer = hub.actor.renderer
)), name = ReminderName),
isOnline = isOnline,
socketHub = socketHub,
evaluator = hub.actor.evaluator
socketHub = socketHub
)), name = OrganizerName)
private val tournamentScheduler = system.actorOf(Props(new Scheduler(api)))
@ -123,10 +122,6 @@ final class Env(
organizer -> actorApi.StartedTournaments
}
scheduler.message(6 minutes) {
organizer -> actorApi.CheckLeaders
}
scheduler.message(5 minutes) {
tournamentScheduler -> actorApi.ScheduleNow
}

View File

@ -13,8 +13,7 @@ private[tournament] final class Organizer(
api: TournamentApi,
reminder: ActorRef,
isOnline: String => Boolean,
socketHub: ActorRef,
evaluator: ActorSelection) extends Actor {
socketHub: ActorRef) extends Actor {
context.system.lilaBus.subscribe(self, 'finishGame, 'adjustCheater)
@ -42,12 +41,6 @@ private[tournament] final class Organizer(
reminder ! RemindTournaments(tours)
}
case CheckLeaders => TournamentRepo.started foreach {
_.flatMap(_.leaders).map(_.id).distinct foreach { id =>
evaluator ! lila.hub.actorApi.evaluation.AutoCheck(id)
}
}
case FinishGame(game, _, _) => api finishGame game
case lila.hub.actorApi.mod.MarkCheater(userId) => api ejectCheater userId

View File

@ -32,7 +32,6 @@ private[tournament] case class Connected(enumerator: JsEnumerator, member: Membe
// organizer
private[tournament] case object AllCreatedTournaments
private[tournament] case object StartedTournaments
private[tournament] case object CheckLeaders
case class RemindTournaments(tours: List[Started])
case class RemindTournament(tour: Started)
case class TournamentTable(tours: List[Enterable])

@ -1 +0,0 @@
Subproject commit 16586282ce3d6cf67459582a612aa17571ffc9d0