Skip to content

Commit

Permalink
much progress on relay
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Jun 24, 2015
1 parent 0320a58 commit f45fa62
Show file tree
Hide file tree
Showing 40 changed files with 893 additions and 24 deletions.
45 changes: 45 additions & 0 deletions app/controllers/Relay.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package controllers

import play.api.data.Form
import play.api.libs.json._
import play.api.mvc._

import lila.api.Context
import lila.app._
import lila.relay.{ Relay => RelayModel }
import views._

object Relay extends LilaController {

private def env = Env.relay

private def relayNotFound(implicit ctx: Context) = NotFound(html.relay.notFound())

val index = Open { implicit ctx =>
env.repo recent 30 map { relays =>
Ok(html.relay.home(relays))
}
}

def show(id: String, slug: String) = Open { implicit ctx =>
env.repo byId id flatMap {
_.fold(relayNotFound.fuccess) { relay =>
if (relay.slug != slug) Redirect(routes.Relay.show(id, relay.slug)).fuccess
else env.version(relay.id) zip env.jsonView(relay) zip chatOf(relay) map {
case ((version, data), chat) => html.relay.show(relay, version, data, chat)
}
} map NoCache
}
}

def websocket(id: String, apiVersion: Int) = SocketOption[JsValue] { implicit ctx =>
(getInt("version") |@| get("sri")).tupled ?? {
case (version, uid) => env.socketHandler.join(id, version, uid, ctx.me)
}
}

private def chatOf(relay: RelayModel)(implicit ctx: Context) =
ctx.isAuth ?? {
Env.chat.api.userChat find relay.id map (_.forUser(ctx.me).some)
}
}
3 changes: 2 additions & 1 deletion app/templating/Environment.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ object Environment
with AnalysisHelper
with IRCHelper
with TournamentHelper
with SimulHelper {
with SimulHelper
with RelayHelper {

implicit val LilaHtmlMonoid = scalaz.Monoid.instance[Html](
(a, b) => Html(a.body + b.body),
Expand Down
21 changes: 21 additions & 0 deletions app/templating/RelayHelper.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package lila.app
package templating

import controllers.routes
import lila.api.Context
import lila.relay.Relay
import lila.user.{ User, UserContext }
import lila.relay.Env.{ current => relayEnv }

import play.api.libs.json.Json
import play.twirl.api.Html

trait RelayHelper { self: I18nHelper =>

def relayLink(relay: Relay): Html = Html {
val url = routes.Relay.show(relay.id, relay.slug)
s"""<a class="text" data-icon="n" href="$url">${relay.name}</a>"""
}

def relayIdToName(id: String) = relayEnv.cached name id getOrElse "Chess event"
}
29 changes: 29 additions & 0 deletions app/views/relay/home.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@(relays: List[lila.relay.Relay])(implicit ctx: Context)

@relay.layout(
title = "Watch Chess events",
side = none) {
<div id="relay_list">
<div class="content_box simul_box no_padding">
<h1>Watch Chess events</h1>
<table class="slist">
<thead>
<tr>
<th>Date</th>
<th>Event</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@relays.map { rel =>
<tr class="scheduled">
<td>@showDate(rel.date)</td>
<td><a href="@routes.Relay.show(rel.id, rel.slug)">@rel.name</a></td>
<td>@rel.status</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
4 changes: 4 additions & 0 deletions app/views/relay/jsI18n.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@()(implicit ctx: Context)
@Html(J.stringify(i18nJsObject(
trans.finished
)))
16 changes: 16 additions & 0 deletions app/views/relay/layout.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@(title: String, moreJs: Html = Html(""), side: Option[Html] = None, chat: Option[Html] = None, underchat: Option[Html] = None, chessground: Boolean = true)(body: Html)(implicit ctx: Context)

@moreCss = {
@cssTag("relay.css")
}

@base.layout(
title = title,
moreJs = moreJs,
moreCss = moreCss,
side = side,
chat = chat,
underchat = underchat,
chessground = chessground) {
@body
}
14 changes: 14 additions & 0 deletions app/views/relay/notFound.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
@()(implicit ctx: Context)

@relay.layout(title = "Event not found") {
<div id="relay">
<div class="content_box small_box faq_page">
<h1>Event not found</h1><br /><br />
This event does not exist.<br />
It may have been canceled.
<br />
<br />
<a href="@routes.Relay.index">Return to events homepage</a>
</div>
</div>
}
29 changes: 29 additions & 0 deletions app/views/relay/show.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@(rel: lila.relay.Relay, socketVersion: Int, data: play.api.libs.json.JsObject, chat: Option[lila.chat.UserChat])(implicit ctx: Context)

@underchat = {
<div class="watchers" data-icon="v">
<span class="list inline_userlist"></span>
</div>
}

@moreJs = {
@jsAt(s"compiled/lichess.relay${isProd??(".min")}.js")
@embedJs {
lichess = lichess || {};
lichess.relay = LichessRelay(document.getElementById('relay'), {
data: @Html(J.stringify(data)),
i18n: @jsI18n(),
socketVersion: @socketVersion
});
}
}

@relay.layout(
title = rel.name,
side = relay.side(rel).some,
chat = chat.map(c => base.chat(c, trans.chatRoom.str())),
underchat = underchat.some,
moreJs = moreJs,
chessground = false) {
<div id="relay"></div>
}
5 changes: 5 additions & 0 deletions app/views/relay/side.scala.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@(rel: lila.relay.Relay)(implicit ctx: Context)

<div class="side_box padded">
@rel.name
</div>
5 changes: 5 additions & 0 deletions conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,11 @@ POST /qa/:id/comment controllers.QaComment.question(id: Int)
POST /qa/:id/:a/comment controllers.QaComment.answer(id: Int, a: Int)
POST /qa/:id/:c/rm-comment controllers.QaComment.remove(id: Int, c: String)

# RELAY
GET /watch controllers.Relay.index
GET /watch/:id/:slug controllers.Relay.show(id: String, slug: String)
GET /watch/$id<\w{8}>/socket/v:apiVersion controllers.Relay.websocket(id: String, apiVersion: Int)

# API
GET /api/user controllers.Api.users
GET /api/user/:id controllers.Api.user(id: String)
Expand Down
13 changes: 13 additions & 0 deletions modules/relay/src/main/Cached.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package lila.relay

import scala.concurrent.duration._

private[relay] final class Cached(repo: RelayRepo) {

private val nameCache = lila.memo.MixedCache[String, Option[String]](
((id: String) => repo byId id map2 { (relay: Relay) => relay.name }),
timeToLive = 6 hours,
default = _ => none)

def name(id: String) = nameCache get id
}
67 changes: 55 additions & 12 deletions modules/relay/src/main/Env.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package lila.relay

import akka.actor._
import akka.pattern.ask
import com.typesafe.config.Config

import lila.common.PimpedConfig._
import makeTimeout.short

final class Env(
config: Config,
db: lila.db.Env,
system: ActorSystem,
roundMap: akka.actor.ActorRef,
flood: lila.security.Flood,
hub: lila.hub.Env,
lightUser: String => Option[lila.common.LightUser],
scheduler: lila.common.Scheduler) {

/* ACTOR ARCHITECTURE
Expand All @@ -27,11 +31,18 @@ final class Env(
* +- 1 telnet Actor
*/

private val Enabled = config getBoolean "enabled"
private val UserId = config getString "user_id"
private val ImportMoveDelay = config duration "import.move_delay"
private val CollectionRelay = config getString "collection.relay"
private val TourneyActorMapName = config getString "actor.map.tourney.name"
private val settings = new {
val Enabled = config getBoolean "enabled"
val UserId = config getString "user_id"
val ImportMoveDelay = config duration "import.move_delay"
val CollectionRelay = config getString "collection.relay"
val TourneyActorMapName = config getString "actor.map.tourney.name"
val HistoryMessageTtl = config duration "history.message.ttl"
val UidTimeout = config duration "uid.timeout"
val SocketTimeout = config duration "socket.timeout"
val SocketName = config getString "socket.name"
}
import settings._

private val ficsConfig = FICS.Config(
host = config getString "fics.host",
Expand All @@ -46,28 +57,58 @@ final class Env(

private val mainFics = system.actorOf(ficsProps, name = "fics")

private lazy val relayRepo = new RelayRepo(db(CollectionRelay))
val repo = new RelayRepo(db(CollectionRelay))

lazy val api = new RelayApi(mainFics, repo, tourneyMap)

lazy val api = new RelayApi(mainFics, relayRepo, tourneyMap)
lazy val jsonView = new JsonView

private val importer = new Importer(
roundMap,
hub.actor.roundMap,
ImportMoveDelay,
system.scheduler)

private val tourneyMap = system.actorOf(Props(new lila.hub.ActorMap {
def mkActor(id: String) = new TourneyActor(
id = id,
ficsProps = ficsProps,
repo = relayRepo,
repo = repo,
importer = importer)
def receive = actorMapReceive
}), name = TourneyActorMapName)

private val socketHub = system.actorOf(
Props(new lila.socket.SocketHubActor.Default[Socket] {
def mkActor(relayId: String) = new Socket(
relayId = relayId,
history = new lila.socket.History(ttl = HistoryMessageTtl),
getRelay = () => repo byId relayId,
jsonView = jsonView,
lightUser = lightUser,
uidTimeout = UidTimeout,
socketTimeout = SocketTimeout)
}), name = SocketName)

lazy val socketHandler = new SocketHandler(
hub = hub,
socketHub = socketHub,
chat = hub.actor.chat,
flood = flood,
exists = repo.exists)

lazy val cached = new Cached(repo)

def version(relayId: String): Fu[Int] =
socketHub ? lila.hub.actorApi.map.Ask(
relayId,
lila.socket.actorApi.GetVersion) mapTo manifest[Int]

{
import scala.concurrent.duration._

api.refreshFromFics
scheduler.once(10 seconds) {
api.refreshFromFics
}
scheduler.effect(5 minutes, "refresh FICS relays") {
api.refreshFromFics
}
Expand All @@ -80,6 +121,8 @@ object Env {
config = lila.common.PlayApp loadConfig "relay",
db = lila.db.Env.current,
system = lila.common.PlayApp.system,
roundMap = lila.round.Env.current.roundMap,
flood = lila.security.Env.current.flood,
hub = lila.hub.Env.current,
lightUser = lila.user.Env.current.lightUser,
scheduler = lila.common.PlayApp.scheduler)
}
4 changes: 2 additions & 2 deletions modules/relay/src/main/Importer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package lila.relay
import scala.concurrent.duration._
import scala.concurrent.Future

import akka.actor.ActorRef
import akka.actor.ActorSelection
import akka.pattern.after
import chess.format.UciMove
import chess.variant.Standard
Expand All @@ -13,7 +13,7 @@ import lila.hub.actorApi.map.Tell
import lila.round.actorApi.round._

final class Importer(
roundMap: ActorRef,
roundMap: ActorSelection,
delay: FiniteDuration,
scheduler: akka.actor.Scheduler) {

Expand Down
25 changes: 25 additions & 0 deletions modules/relay/src/main/JsonView.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package lila.relay

import play.api.libs.json._

import lila.game.{ Game, GameRepo }

final class JsonView {

def apply(relay: Relay): Fu[JsObject] =
GameRepo.games(relay.gameIds) map { games =>
Json.obj(
"id" -> relay.id,
"name" -> relay.name,
"status" -> relay.status.id,
"games" -> games.map(gameJson)
)
}

private def gameJson(g: Game) = Json.obj(
"id" -> g.id,
"status" -> g.status.id,
"fen" -> (chess.format.Forsyth exportBoard g.toChess.board),
"lastMove" -> ~g.castleLastMoveTime.lastMoveString,
"orient" -> g.firstPlayer.color.name)
}
8 changes: 8 additions & 0 deletions modules/relay/src/main/Relay.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@ case class Relay(

def gameIdByFicsId(ficsId: Int) = gameByFicsId(ficsId).map(_.id)

def gameIds = games.map(_.id)

def activeGames = games.filterNot(_.end)

def slug = Relay.SlugR.replaceAllIn(
lila.common.String slugify name,
"-")
}

object Relay {

private val SlugR = """-{2,}""".r

def make(ficsId: Int, name: String, status: Status) = Relay(
id = Random nextStringUppercase 8,
ficsId = ficsId,
Expand Down
Loading

0 comments on commit f45fa62

Please sign in to comment.