From 8717264ae070c2eb4463b00b6a8bde7803516d9f Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Fri, 31 Oct 2014 17:17:52 +0100 Subject: [PATCH] print game to PDF, stream it as chunked HTTP and cache it in CDN --- .gitmodules | 3 +++ app/controllers/Analyse.scala | 8 ++++++++ conf/routes | 2 ++ modules/game/src/main/Env.scala | 3 +++ modules/game/src/main/PdfExport.scala | 14 ++++++++++++++ modules/i18n/src/main/Env.scala | 6 +++++- modules/i18n/src/main/I18nRequestHandler.scala | 14 ++++++++++---- submodules/pdfexporter | 1 + 8 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 modules/game/src/main/PdfExport.scala create mode 160000 submodules/pdfexporter diff --git a/.gitmodules b/.gitmodules index a36a009068..f0e3e94943 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "public/staunton"] path = public/staunton url = https://github.com/clarkerubber/Staunton-Pieces +[submodule "submodules/pdfexporter"] + path = submodules/pdfexporter + url = https://github.com/clarkerubber/lichessPDFExporter diff --git a/app/controllers/Analyse.scala b/app/controllers/Analyse.scala index 1697d93825..4c67083c7d 100644 --- a/app/controllers/Analyse.scala +++ b/app/controllers/Analyse.scala @@ -6,6 +6,7 @@ import akka.pattern.ask import play.api.http.ContentTypes import play.api.mvc._ import play.twirl.api.Html +import play.api.libs.iteratee.{ Iteratee, Enumerator } import lila.analyse.{ Analysis, TimeChart, AdvantageChart } import lila.api.Context @@ -92,6 +93,13 @@ object Analyse extends LilaController { } } + def pdf(id: String) = Open { implicit ctx => + OptionResult(GameRepo game id) { game => + Ok.chunked(Enumerator.outputStream(Env.game.pdfExport(game.id))).withHeaders( + CONTENT_TYPE -> ContentTypes.withCharset("application/pdf")) + } + } + private def gameOpening(game: GameModel) = if (game.fromPosition || game.variant.exotic) none else chess.OpeningExplorer openingOf game.pgnMoves diff --git a/conf/routes b/conf/routes index 1094c2dcfb..95ab7acb21 100644 --- a/conf/routes +++ b/conf/routes @@ -138,6 +138,8 @@ POST /$gameId<\w{8}>/better-analysis/$color controllers.Analyse.be POST /$gameId<\w{8}>/post-analysis controllers.Analyse.postAnalysis(gameId: String) GET /$gameId<\w{8}>/pgn controllers.Analyse.pgn(gameId: String) +GET /game/pdf/$gameId<\w{8}> controllers.Analyse.pdf(gameId: String) + # Pref POST /pref/:name controllers.Pref.set(name: String) GET /account/preferences controllers.Pref.form diff --git a/modules/game/src/main/Env.scala b/modules/game/src/main/Env.scala index 484978fa23..e581cf7538 100644 --- a/modules/game/src/main/Env.scala +++ b/modules/game/src/main/Env.scala @@ -28,6 +28,7 @@ final class Env( val ActorName = config getString "actor.name" val UciMemoTtl = config duration "uci_memo.ttl" val netBaseUrl = config getString "net.base_url" + val PdfExecPath = config getString "pdf.exec_path" } import settings._ @@ -35,6 +36,8 @@ final class Env( private[game] lazy val gameColl = db(CollectionGame) + lazy val pdfExport = PdfExport(PdfExecPath) _ + lazy val cached = new Cached(ttl = CachedNbTtl) lazy val paginator = new PaginatorBuilder( diff --git a/modules/game/src/main/PdfExport.scala b/modules/game/src/main/PdfExport.scala new file mode 100644 index 0000000000..f00052feb3 --- /dev/null +++ b/modules/game/src/main/PdfExport.scala @@ -0,0 +1,14 @@ +package lila.game + +import java.io.{ File, OutputStream } +import scala.sys.process._ + +object PdfExport { + + private val logger = ProcessLogger(_ => (), _ => ()) + + def apply(execPath: String)(id: String)(out: OutputStream) { + val exec = Process(Seq("php", "main.php", id), new File(execPath)) + exec #> out ! logger + } +} diff --git a/modules/i18n/src/main/Env.scala b/modules/i18n/src/main/Env.scala index b84ab1f14c..e0060c8982 100644 --- a/modules/i18n/src/main/Env.scala +++ b/modules/i18n/src/main/Env.scala @@ -22,6 +22,7 @@ final class Env( val CollectionTranslation = config getString "collection.translation" val ContextGitUrl = config getString "context.git.url" val ContextGitFile = config getString "context.git.file" + val CdnDomain = config getString "cdn_domain" } import settings._ @@ -40,7 +41,10 @@ final class Env( lazy val keys = new I18nKeys(translator) - lazy val requestHandler = new I18nRequestHandler(pool, RequestHandlerProtocol) + lazy val requestHandler = new I18nRequestHandler( + pool, + RequestHandlerProtocol, + CdnDomain) lazy val jsDump = new JsDump( path = appPath + "/" + WebPathRelative, diff --git a/modules/i18n/src/main/I18nRequestHandler.scala b/modules/i18n/src/main/I18nRequestHandler.scala index 17681f97b7..8b52a8fa83 100644 --- a/modules/i18n/src/main/I18nRequestHandler.scala +++ b/modules/i18n/src/main/I18nRequestHandler.scala @@ -6,12 +6,18 @@ import play.api.mvc.{ Action, RequestHeader, Handler } import lila.common.HTTPRequest -final class I18nRequestHandler(pool: I18nPool, protocol: String) { +final class I18nRequestHandler( + pool: I18nPool, + protocol: String, + cdnDomain: String) { def apply(req: RequestHeader): Option[Handler] = - (HTTPRequest.isRedirectable(req) && !pool.domainLang(req).isDefined) option Action { - Redirect(redirectUrl(req)) - } + (HTTPRequest.isRedirectable(req) && + !pool.domainLang(req).isDefined && + req.host != cdnDomain + ) option Action { + Redirect(redirectUrl(req)) + } private def redirectUrl(req: RequestHeader) = protocol + diff --git a/submodules/pdfexporter b/submodules/pdfexporter new file mode 160000 index 0000000000..8d6c955043 --- /dev/null +++ b/submodules/pdfexporter @@ -0,0 +1 @@ +Subproject commit 8d6c9550432ce462e4e977a770751354da097cf4