lila3 compiles

rm0193-mapreduce
Thibault Duplessis 2019-12-05 09:46:00 -06:00
parent 2b82c5f5b4
commit c12b81b3df
27 changed files with 168 additions and 62 deletions

View File

@ -1,12 +1,13 @@
package lila.app
import akka.actor._
import akka.stream.Materializer
import com.softwaremill.macwire._
import play.api.mvc.SessionCookieBaker
import play.api.{ Application, Configuration, Mode }
import scala.concurrent.duration._
import play.api.libs.ws.ahc.AhcWSComponents
import play.api.inject.ApplicationLifecycle
import play.api.libs.ws.WSClient
import play.api.mvc.{ SessionCookieBaker, ControllerComponents }
import play.api.{ Application, Configuration, Environment, Mode }
import scala.concurrent.duration._
import lila.common.Bus
import lila.common.config._
@ -14,9 +15,9 @@ import lila.user.User
final class Env(
val config: Configuration,
val mode: Mode,
val common: lila.common.Env,
val db: lila.db.Env,
val playApp: Application,
val api: lila.api.Env,
val user: lila.user.Env,
val security: lila.security.Env,
@ -36,7 +37,7 @@ final class Env(
val teamSearch: lila.teamSearch.Env,
val analyse: lila.analyse.Env,
val mod: lila.mod.Env,
val notify: lila.notify.Env,
val notifyM: lila.notify.Env,
val round: lila.round.Env,
val lobby: lila.lobby.Env,
val setup: lila.setup.Env,
@ -77,10 +78,12 @@ final class Env(
val oAuth: lila.oauth.Env,
val bot: lila.bot.Env,
val evalCache: lila.evalCache.Env,
val rating: lila.rating.Env
val rating: lila.rating.Env,
val controllerComponents: ControllerComponents,
cookieBacker: SessionCookieBaker
)(implicit val system: ActorSystem) {
val isProd = playApp.mode == Mode.Prod
val isProd = mode == Mode.Prod
val isStage = config.get[Boolean]("app.stage")
val explorerEndpoint = config.get[String]("explorer.endpoint")
val tablebaseEndpoint = config.get[String]("explorer.tablebase.endpoint")
@ -88,19 +91,11 @@ final class Env(
def net = common.netConfig
lazy val preloader = wire[mashup.Preload]
lazy val socialInfo = wire[mashup.UserInfo.SocialApi]
lazy val userNbGames = wire[mashup.UserInfo.NbGamesApi]
lazy val userInfo = wire[mashup.UserInfo.UserInfoApi]
lazy val teamInfo = wire[mashup.TeamInfoApi]
lazy val gamePaginator = wire[mashup.GameFilterMenu.PaginatorBuilder]
private lazy val cookieBacker: SessionCookieBaker = playApp.injector.instanceOf[SessionCookieBaker]
lazy val lilaCookie = wire[lila.common.LilaCookie]
private val tryDailyPuzzle: lila.puzzle.Daily.Try = () =>
@ -155,18 +150,21 @@ final class Env(
scheduler.scheduleOnce(5 seconds) { slack.api.publishRestart }
}
final class EnvBoot(app: Application) extends AhcWSComponents {
final class EnvBoot(
config: Configuration,
environment: Environment,
lifecycle: ApplicationLifecycle,
controllerComponents: ControllerComponents,
cookieBacker: SessionCookieBaker
)(implicit system: ActorSystem, ws: WSClient) {
lila.log.boot.info {
s"Java: ${System.getProperty("java.version")}, memory: ${Runtime.getRuntime().maxMemory() / 1024 / 1024}MB"
}
implicit def system = app.actorSystem
implicit def scheduler = system.scheduler
def config = app.configuration
def appPath = AppPath(app.path)
def mode = app.mode
implicit def ws: WSClient = wsClient
def appPath = AppPath(environment.rootPath)
def mode = environment.mode
implicit def idGenerator = game.idGenerator
// wire all the lila modules
@ -191,7 +189,7 @@ final class EnvBoot(app: Application) extends AhcWSComponents {
lazy val teamSearch: lila.teamSearch.Env = wire[lila.teamSearch.Env]
lazy val analyse: lila.analyse.Env = wire[lila.analyse.Env]
lazy val mod: lila.mod.Env = wire[lila.mod.Env]
lazy val notify: lila.notify.Env = wire[lila.notify.Env]
lazy val notifyM: lila.notify.Env = wire[lila.notify.Env]
lazy val round: lila.round.Env = wire[lila.round.Env]
lazy val lobby: lila.lobby.Env = wire[lila.lobby.Env]
lazy val setup: lila.setup.Env = wire[lila.setup.Env]

View File

@ -1,4 +1,4 @@
package lila.app
// package lila.app
// #TODO relocate that shit
// object Global extends GlobalSettings {

View File

@ -0,0 +1,96 @@
import com.softwaremill.macwire._
import play.api._
import play.api.ApplicationLoader.Context
import play.api.i18n._
import play.api.mvc._
import play.api.routing.Router
import router.Routes
class LilaAppLoader extends ApplicationLoader {
def load(ctx: Context): Application = new LilaComponents(ctx).application
}
class LilaComponents(ctx: Context) extends BuiltInComponentsFromContext(ctx)
with _root_.controllers.AssetsComponents
with play.api.libs.ws.ahc.AhcWSComponents {
LoggerConfigurator(ctx.environment.classLoader).foreach {
_.configure(ctx.environment, ctx.initialConfiguration, Map.empty)
}
import _root_.controllers._
def httpFilters = Seq.empty[EssentialFilter]
implicit def system = actorSystem
implicit def ws = wsClient
def cookieBacker: SessionCookieBaker = injector.instanceOf[SessionCookieBaker]
lazy val boot: lila.app.EnvBoot = wire[lila.app.EnvBoot]
lazy val env: lila.app.Env = boot.env
lazy val account: Account = wire[Account]
lazy val analyse: Analyse = wire[Analyse]
lazy val api: Api = wire[Api]
lazy val auth: Auth = wire[Auth]
lazy val blog: Blog = wire[Blog]
lazy val bookmark: Bookmark = wire[Bookmark]
lazy val bot: Bot = wire[Bot]
lazy val challenge: Challenge = wire[Challenge]
lazy val coach: Coach = wire[Coach]
lazy val coordinate: Coordinate = wire[Coordinate]
lazy val dasher: Dasher = wire[Dasher]
lazy val dev: Dev = wire[Dev]
lazy val editor: Editor = wire[Editor]
lazy val event: Event = wire[Event]
lazy val export: Export = wire[Export]
lazy val fishnet: Fishnet = wire[Fishnet]
lazy val forumCateg: ForumCateg = wire[ForumCateg]
lazy val forumPost: ForumPost = wire[ForumPost]
lazy val forumTopic: ForumTopic = wire[ForumTopic]
lazy val game: Game = wire[Game]
lazy val i18n: I18n = wire[I18n]
lazy val importer: Importer = wire[Importer]
lazy val insight: Insight = wire[Insight]
lazy val irwin: Irwin = wire[Irwin]
lazy val learn: Learn = wire[Learn]
lazy val lobby: Lobby = wire[Lobby]
lazy val main: Main = wire[Main]
lazy val message: Message = wire[Message]
lazy val mod: Mod = wire[Mod]
lazy val notifyC: Notify = wire[Notify]
lazy val oAuthApp: OAuthApp = wire[OAuthApp]
lazy val oAuthToken: OAuthToken = wire[OAuthToken]
lazy val options: Options = wire[Options]
lazy val page: Page = wire[Page]
lazy val plan: Plan = wire[Plan]
lazy val practice: Practice = wire[Practice]
lazy val pref: Pref = wire[Pref]
lazy val prismic: Prismic = wire[Prismic]
lazy val push: Push = wire[Push]
lazy val puzzle: Puzzle = wire[Puzzle]
lazy val relation: Relation = wire[Relation]
lazy val relay: Relay = wire[Relay]
lazy val report: Report = wire[Report]
lazy val round: Round = wire[Round]
lazy val search: Search = wire[Search]
lazy val setup: Setup = wire[Setup]
lazy val simul: Simul = wire[Simul]
lazy val stat: Stat = wire[Stat]
lazy val streamer: Streamer = wire[Streamer]
lazy val study: Study = wire[Study]
lazy val team: Team = wire[Team]
lazy val timeline: Timeline = wire[Timeline]
lazy val tournament: Tournament = wire[Tournament]
lazy val tournamentCrud: TournamentCrud = wire[TournamentCrud]
lazy val tv: Tv = wire[Tv]
lazy val user: User = wire[User]
lazy val userAnalysis: UserAnalysis = wire[UserAnalysis]
lazy val userTournament: UserTournament = wire[UserTournament]
lazy val video: Video = wire[Video]
lazy val router: Router = {
val prefix: String = "/"
wire[Routes]
}
}

View File

@ -49,7 +49,7 @@ final class Event(env: Env) extends LilaController(env) {
)
}
def clone(id: String) = Secure(_.ManageEvent) { implicit ctx => me =>
def cloneE(id: String) = Secure(_.ManageEvent) { implicit ctx => me =>
OptionFuResult(api one id) { old =>
val event = api clone old
Ok(html.event.create(api editForm event)).fuccess

View File

@ -104,7 +104,7 @@ final class Game(
def exportByIds = Action.async(parse.tolerantText) { req =>
apiC.GlobalLinearLimitPerIP(HTTPRequest lastRemoteAddress req) {
val config = GameApiV2.ByIdsConfig(
ids = req.body.split(',').take(300),
ids = req.body.split(',').view.take(300).toSeq,
format = GameApiV2.Format byRequest req,
flags = requestPgnFlags(req, extended = false),
perSecond = MaxPerSecond(20)

View File

@ -21,7 +21,9 @@ private[controllers] abstract class LilaController(val env: Env)
with RequestGetter
with ResponseWriter {
implicit val defaultExecutionContext = scala.concurrent.ExecutionContext.Implicits.global
val controllerComponents = env.controllerComponents
implicit val executionContext = defaultExecutionContext
protected implicit val LilaResultZero = Zero.instance[Result](Results.NotFound)
@ -392,7 +394,7 @@ private[controllers] abstract class LilaController(val env: Env)
env.relation.online.friendsOf(me.id) zip
env.team.api.nbRequests(me.id) zip
env.challenge.api.countInFor.get(me.id) zip
env.notify.api.unreadCount(Notifies(me.id)).dmap(_.value) zip
env.notifyM.api.unreadCount(Notifies(me.id)).dmap(_.value) zip
env.mod.inquiryApi.forMod(me)
} else fuccess {
((((OnlineFriends.empty, 0), 0), 0), none)
@ -471,7 +473,7 @@ private[controllers] abstract class LilaController(val env: Env)
protected def errorsAsJson(form: Form[_])(implicit lang: Lang): JsObject = {
val json = JsObject(
form.errors.groupBy(_.key).mapValues { errors =>
form.errors.groupBy(_.key).view.mapValues { errors =>
JsArray {
errors.map { e =>
JsString(lila.i18n.Translator.txt.literal(e.message, lila.i18n.I18nDb.Site, e.args, lang))

View File

@ -110,7 +110,7 @@ final class Main(
val robots = Action { req =>
Ok {
if (env.net.crawlable && req.domain == env.net.domain) """User-agent: *
if (env.net.crawlable && req.domain == env.net.domain.value) """User-agent: *
Allow: /
Disallow: /game/export
Disallow: /games/export

View File

@ -64,7 +64,9 @@ final class Message(env: Env) extends LilaController(env) {
err => relationApi.fetchBlocks(thread otherUserId me, me.id) map { blocked =>
BadRequest(html.message.thread(thread, err.some, blocked))
},
text => api.makePost(thread, text, me) inject Redirect(routes.Message.thread(thread.id) + "#bottom")
text => api.makePost(thread, text, me) inject Redirect {
s"${routes.Message.thread(thread.id)}#bottom"
}
),
api = _ => forms.post.bindFromRequest.fold(
err => fuccess(BadRequest(Json.obj("err" -> "Malformed request"))),

View File

@ -7,12 +7,12 @@ import play.api.libs.json._
final class Notify(env: Env) extends LilaController(env) {
import env.notify.jsonHandlers._
import env.notifyM.jsonHandlers._
def recent(page: Int) = Auth { implicit ctx => me =>
XhrOrRedirectHome {
val notifies = Notifies(me.id)
env.notify.api.getNotificationsAndCount(notifies, page) map { res =>
env.notifyM.api.getNotificationsAndCount(notifies, page) map { res =>
Ok(Json toJson res) as JSON
}
}

View File

@ -109,7 +109,7 @@ final class Practice(
FormFuResult(form) { err =>
api.structure.get map { html.practice.config(_, err) }
} { text =>
~api.config.set(text).right.toOption >>-
~api.config.set(text).toOption >>-
api.structure.clear >>
env.mod.logApi.practiceConfig(me.id) inject Redirect(routes.Practice.config)
}

View File

@ -38,7 +38,7 @@ final class Setup(
)
}
} else fuccess {
Redirect(routes.Lobby.home + "#ai")
Redirect(s"${routes.Lobby.home}#ai")
}
}
@ -59,7 +59,7 @@ final class Setup(
}
}
else fuccess {
Redirect(routes.Lobby.home + "#friend")
Redirect(s"${routes.Lobby.home}#friend")
}
}
@ -122,7 +122,7 @@ final class Setup(
forms.hookFilled(timeModeString = get("time")) map { html.setup.forms.hook(_) }
}
else fuccess {
Redirect(routes.Lobby.home + "#hook")
Redirect(s"${routes.Lobby.home}#hook")
}
}
}

View File

@ -43,7 +43,7 @@ final class TournamentCrud(env: Env) extends LilaController(env) {
)
}
def clone(id: String) = Secure(_.ManageTournament) { implicit ctx => me =>
def cloneT(id: String) = Secure(_.ManageTournament) { implicit ctx => me =>
OptionFuResult(crud one id) { old =>
val tour = crud clone old
Ok(html.tournament.crud.create(crud editForm tour)).fuccess

View File

@ -17,7 +17,7 @@ trait AssetHelper { self: I18nHelper with SecurityHelper =>
val socketDomain = env.net.socketDomain
val vapidPublicKey = env.push.vapidPublicKey
val sameAssetDomain = siteDomain == assetDomain
val sameAssetDomain = siteDomain.value == assetDomain.value
val assetBaseUrl = s"//$assetDomain"
@ -101,8 +101,12 @@ trait AssetHelper { self: I18nHelper with SecurityHelper =>
}
def basicCsp(implicit req: RequestHeader): ContentSecurityPolicy = {
val assets = if (req.secure) "https://" + assetDomain else assetDomain
val socket = (if (req.secure) "wss://" else "ws://") + socketDomain + (if (socketDomain.contains(":")) "" else ":*")
val assets = if (req.secure) s"https://$assetDomain" else assetDomain.value
val socket = {
val protocol = if (req.secure) "wss://" else "ws://"
val port = if (socketDomain.contains(":")) "" else ":*"
s"$protocol$socketDomain$port"
}
ContentSecurityPolicy(
defaultSrc = List("'self'", assets),
connectSrc = List(
@ -113,7 +117,7 @@ trait AssetHelper { self: I18nHelper with SecurityHelper =>
env.tablebaseEndpoint
),
styleSrc = List("'self'", "'unsafe-inline'", assets),
fontSrc = List("'self'", assetDomain, "https://fonts.gstatic.com"),
fontSrc = List("'self'", assetDomain.value, "https://fonts.gstatic.com"),
frameSrc = List("'self'", assets, "https://www.youtube.com", "https://player.twitch.tv"),
workerSrc = List("'self'", assets),
imgSrc = List("data:", "*"),

View File

@ -55,7 +55,7 @@ object userAnalysis {
a(
dataIcon := iconByVariant(v),
cls := (pov.game.variant == v).option("current"),
href := routes.UserAnalysis.parse(v.key)
href := routes.UserAnalysis.parseArg(v.key)
)(v.name)
}
)

View File

@ -30,7 +30,7 @@ object event {
event.title,
span("Created by ", usernameOrId(event.createdBy.value), " ", momentFromNow(event.createdAt))
),
st.form(cls := "box__top__actions", action := routes.Event.clone(event.id), method := "get")(
st.form(cls := "box__top__actions", action := routes.Event.cloneE(event.id), method := "get")(
form3.submit("Clone", "".some, klass = "button-green")
)
),

View File

@ -66,7 +66,7 @@ object features {
" (62 million games!)"
),
tr(unlimited)(
a(href := s"${routes.UserAnalysis.parse("QN4n1/6r1/3k4/8/b2K4/8/8/8_b_-_-")}#explorer")("7-piece endgame tablebase")
a(href := s"${routes.UserAnalysis.parseArg("QN4n1/6r1/3k4/8/b2K4/8/8/8_b_-_-")}#explorer")("7-piece endgame tablebase")
),
tr(check)(
"Download/Upload any game as PGN"

View File

@ -52,7 +52,7 @@ object crud {
" ",
span("Created by ", usernameOrId(tour.createdBy), " on ", showDate(tour.createdAt))
),
st.form(cls := "box__top__actions", action := routes.TournamentCrud.clone(tour.id), method := "get")(
st.form(cls := "box__top__actions", action := routes.TournamentCrud.cloneT(tour.id), method := "get")(
form3.submit("Clone", "g".some, klass = "button-green")
)
),

View File

@ -78,7 +78,7 @@ object side {
strong(tour.position.eco), " ", tour.position.name
),
separator,
a(href := routes.UserAnalysis.parse(tour.position.fen.replace(" ", "_")))(trans.analysis())
a(href := routes.UserAnalysis.parseArg(tour.position.fen.replace(" ", "_")))(trans.analysis())
)
),
streamers.toList map views.html.streamer.bits.contextual,

View File

@ -47,7 +47,7 @@ object perfStat {
dataIcon := perfType.iconChar,
href := s"${routes.User.games(u.username, "search")}?perf=${perfType.id}"
)("View the games"),
bits.perfTrophies(u, rankMap.filterKeys(perfType==).toMap)
bits.perfTrophies(u, rankMap.view.filterKeys(perfType==).toMap)
)
),
ratingChart.isDefined option div(cls := "rating-history")(spinner),

View File

@ -47,7 +47,7 @@ object header {
splitNumber(trans.nbFollowers.pluralSame(info.nbFollowers))
),
info.nbBlockers.map { nb =>
a(cls := "nm-item")(splitNumber(nb + " Blockers"))
a(cls := "nm-item")(splitNumber(s"$nb Blockers"))
},
u.noBot option a(
href := routes.UserTournament.path(u.username, "recent"),
@ -57,7 +57,7 @@ object header {
splitNumber(trans.nbTournamentPoints.pluralSame(u.toints))
),
a(href := routes.Study.byOwnerDefault(u.username), cls := "nm-item")(
splitNumber(info.nbStudies + " studies")
splitNumber(s"${info.nbStudies} studies")
),
a(
cls := "nm-item",
@ -66,7 +66,7 @@ object header {
splitNumber(trans.nbForumPosts.pluralSame(info.nbPosts))
),
(ctx.isAuth && ctx.noKid && !ctx.is(u)) option
a(cls := "nm-item note-zone-toggle")(splitNumber(social.notes.size + " Notes"))
a(cls := "nm-item note-zone-toggle")(splitNumber(s"${social.notes.size} Notes"))
),
div(cls := "user-actions btn-rack")(
(ctx is u) option frag(

View File

@ -14,6 +14,7 @@ net {
ratelimit = true
}
play {
application.loader=LilaAppLoader
modules.disabled+="play.api.mvc.CookiesModule"
modules.enabled+="play.api.mvc.LegacyCookiesModule"
server {
@ -281,7 +282,6 @@ report {
collection.report = report2
actor.name = report
score.threshold = 50
net.domain = ${net.domain}
}
i18n {
web_path.relative = ${app.web_path}/trans

View File

@ -100,7 +100,7 @@ POST /training/:id/attempt controllers.Puzzle.round(id: Int)
# User Analysis
GET /analysis/help controllers.UserAnalysis.help
GET /analysis/*something controllers.UserAnalysis.parse(something: String)
GET /analysis/*something controllers.UserAnalysis.parseArg(something: String)
GET /analysis controllers.UserAnalysis.index
POST /analysis/pgn controllers.UserAnalysis.pgn
@ -229,7 +229,7 @@ GET /tournament/shields/:categ controllers.Tournament.categShield
# Tournament CRUD
GET /tournament/manager controllers.TournamentCrud.index(page: Int ?= 1)
GET /tournament/manager/clone/$id<\w{8}> controllers.TournamentCrud.clone(id: String)
GET /tournament/manager/clone/$id<\w{8}> controllers.TournamentCrud.cloneT(id: String)
GET /tournament/manager/$id<\w{8}> controllers.TournamentCrud.edit(id: String)
POST /tournament/manager/$id<\w{8}> controllers.TournamentCrud.update(id: String)
GET /tournament/manager/new controllers.TournamentCrud.form
@ -548,7 +548,7 @@ GET /event/$id<\w{8}> controllers.Event.show(id: String)
GET /event/manager controllers.Event.manager
GET /event/manager/$id<\w{8}> controllers.Event.edit(id: String)
POST /event/manager/$id<\w{8}> controllers.Event.update(id: String)
GET /event/manager/clone/$id<\w{8}> controllers.Event.clone(id: String)
GET /event/manager/clone/$id<\w{8}> controllers.Event.cloneE(id: String)
GET /event/manager/new controllers.Event.form
POST /event/manager controllers.Event.create

View File

@ -4,7 +4,7 @@ import chess.format.pgn.{ Pgn, Tag, Turn, Move, Glyphs }
import chess.opening._
import chess.{ Status, Color, Clock }
final class Annotator(netDomain: lila.common.Domain) {
final class Annotator(netDomain: lila.common.config.NetDomain) {
def apply(
p: Pgn,

View File

@ -14,6 +14,7 @@ final class Env(
) {
val netConfig = appConfig.get[NetConfig]("net")
def netDomain = netConfig.domain
private lazy val detectLanguageConfig =
appConfig.get[DetectLanguage.Config]("detect_language.api")

View File

@ -24,12 +24,15 @@ object config {
case class MaxPerSecond(value: Int) extends AnyVal with IntValue
case class NetDomain(value: String) extends AnyVal with StringValue
case class AssetDomain(value: String) extends AnyVal with StringValue
case class NetConfig(
domain: Domain,
domain: NetDomain,
protocol: String,
@ConfigName("base_url") baseUrl: BaseUrl,
port: Int,
@ConfigName("asset.domain") assetDomain: String,
@ConfigName("asset.domain") assetDomain: AssetDomain,
@ConfigName("socket.domain") socketDomain: String,
crawlable: Boolean,
@ConfigName("ratelimit") rateLimit: Boolean,
@ -43,7 +46,8 @@ object config {
implicit val secretLoader = strLoader(Secret.apply)
implicit val baseUrlLoader = strLoader(BaseUrl.apply)
implicit val emailAddressLoader = strLoader(EmailAddress.apply)
implicit val domainLoader = strLoader(Domain.unsafe)
implicit val netDomainLoader = strLoader(NetDomain.apply)
implicit val assetDomainLoader = strLoader(AssetDomain.apply)
implicit val netLoader = AutoConfig.loader[NetConfig]
implicit val strListLoader: ConfigLoader[List[String]] = ConfigLoader { c => k =>

View File

@ -5,12 +5,11 @@ import play.api.data.Forms._
import play.api.data.validation._
import lila.user.{ User, UserRepo }
import lila.common.Domain
private[report] final class DataForm(
userRepo: UserRepo,
val captcher: lila.hub.actors.Captcher,
domain: Domain
domain: lila.common.config.NetDomain
) extends lila.hub.CaptchedForm {
val cheatLinkConstraint: Constraint[ReportSetup] = Constraint("constraints.cheatgamelink")({ setup =>
if (setup.reason != "cheat" || (domain.value + """/(\w{8}|\w{12})""").r.findFirstIn(setup.text).isDefined)

View File

@ -13,7 +13,6 @@ import lila.common.Domain
private class CoachConfig(
@ConfigName("collection.report") val reportColl: CollName,
@ConfigName("score.threshold") val scoreThreshold: Int,
@ConfigName("net.domain") val netDomain: Domain,
@ConfigName("actor.name") val actorName: String
)
@ -22,6 +21,7 @@ private case class Thresholds(score: () => Int, slack: () => Int)
@Module
final class Env(
appConfig: Configuration,
domain: lila.common.config.NetDomain,
db: lila.db.Env,
isOnline: lila.socket.IsOnline,
noteApi: lila.user.NoteApi,