relay live clock WIP

pull/3627/head
Thibault Duplessis 2017-10-05 16:48:14 -05:00
parent 81a4ab54d2
commit e9fc1de4dc
8 changed files with 50 additions and 17 deletions

View File

@ -49,8 +49,7 @@ object Relay {
def set(v: Boolean) = copy(
until = v option DateTime.now.plusHours(3),
nextAt = DateTime.now.plusSeconds(1).some,
log = SyncLog(Vector.empty)
nextAt = DateTime.now.plusSeconds(1).some
)
override def toString = upstream.toString

View File

@ -1,5 +1,7 @@
package lila.relay
import org.joda.time.DateTime
import chess.format.pgn.Tag
import lila.common.{ LilaException, Chronometer }
import lila.socket.Socket.Uid
@ -68,7 +70,8 @@ private final class RelaySync(
position = position,
rawNode = n,
uid = socketUid,
opts = moveOpts.copy(clock = n.clock)
opts = moveOpts.copy(clock = n.clock),
relayMoveAt = DateTime.now.some
) flatten s"Can't add relay node $position $node"
} inject node.mainline.size
}

View File

@ -1,8 +1,8 @@
package lila.study
import chess.{ Color, Centis }
import chess.format.pgn.{ Glyph, Tag, Tags }
import chess.variant.Variant
import chess.{ Color, Centis }
import org.joda.time.DateTime
import chess.opening.{ FullOpening, FullOpeningDB }
@ -22,6 +22,7 @@ case class Chapter(
practice: Option[Boolean] = None,
gamebook: Option[Boolean] = None,
description: Option[String] = None,
relayLastMoveAt: Option[DateTime] = None,
createdAt: DateTime
) extends Chapter.Like {
@ -30,9 +31,13 @@ case class Chapter(
copy(root = newRoot)
}
def addNode(node: Node, path: Path): Option[Chapter] =
def addNode(node: Node, path: Path, relayMoveAt: Option[DateTime] = None): Option[Chapter] =
updateRoot { root =>
root.withChildren(_.addNodeAt(node, path))
} map {
_.copy(
relayLastMoveAt = relayMoveAt orElse relayLastMoveAt
)
}
def setShapes(shapes: Shapes, path: Path): Option[Chapter] =
@ -77,6 +82,10 @@ case class Chapter(
def isConceal = conceal.isDefined
def withoutChildren = copy(root = root.withoutChildren)
def relaySecondsSinceLastMove: Option[Int] = relayLastMoveAt.map { at =>
(nowSeconds - at.getSeconds).toInt
}
}
object Chapter {

View File

@ -1,5 +1,6 @@
package lila.study
import org.joda.time.DateTime
import reactivemongo.api.ReadPreference
import lila.db.dsl._
@ -59,6 +60,9 @@ final class ChapterRepo(coll: Coll) {
def removeConceal(chapterId: Chapter.Id) =
coll.unsetField($id(chapterId), "conceal").void
def setRelayLastMoveAt(chapterId: Chapter.Id, at: DateTime) =
coll.updateField($id(chapterId), "relayLastMoveAt", at).void
def setTagsFor(chapter: Chapter) =
coll.updateField($id(chapter.id), "tags", chapter.tags).void

View File

@ -46,7 +46,8 @@ final class JsonView(
"computer" -> allowed(study.settings.computer),
"explorer" -> allowed(study.settings.explorer)
)
).add("description", currentChapter.description) |> addChapterMode(currentChapter)
).add("description", currentChapter.description)
.add("relaySecondsSinceLastMove", currentChapter.relaySecondsSinceLastMove) |> addChapterMode(currentChapter)
}
)
}

View File

@ -3,15 +3,17 @@ package lila.study
import akka.actor._
import play.api.libs.json._
import scala.concurrent.duration._
import org.joda.time.DateTime
import chess.format.pgn.Glyphs
import chess.Centis
import chess.format.pgn.Glyphs
import lila.hub.TimeBomb
import lila.socket.actorApi.{ Connected => _, _ }
import lila.socket.Socket.Uid
import lila.socket.{ SocketActor, History, Historical, AnaDests }
import lila.tree.Node.{ Shapes, Comment }
import lila.user.User
import lila.common.PimpedJson._
private final class Socket(
studyId: Study.Id,
@ -293,7 +295,13 @@ object Socket {
case class ReloadUid(uid: Uid)
case class ReloadUidBecauseOf(uid: Uid, chapterId: Chapter.Id)
case class AddNode(position: Position.Ref, node: Node, variant: chess.variant.Variant, uid: Uid, sticky: Boolean)
case class AddNode(
position: Position.Ref,
node: Node,
variant: chess.variant.Variant,
uid: Uid,
sticky: Boolean
)
case class DeleteNode(position: Position.Ref, uid: Uid)
case class Promote(position: Position.Ref, toMainline: Boolean, uid: Uid)
case class SetPath(position: Position.Ref, uid: Uid)

View File

@ -1,6 +1,7 @@
package lila.study
import akka.actor.{ ActorRef, ActorSelection }
import org.joda.time.DateTime
import scala.concurrent.duration._
import chess.Centis
@ -177,13 +178,13 @@ final class StudyApi(
def addNode(userId: User.ID, studyId: Study.Id, position: Position.Ref, node: Node, uid: Uid, opts: MoveOpts) = sequenceStudyWithChapter(studyId, position.chapterId) {
case Study.WithChapter(study, chapter) => Contribute(userId, study) {
doAddNode(userId, study, Position(chapter, position.path), node, uid, opts).void
doAddNode(userId, study, Position(chapter, position.path), node, uid, opts, none).void
}
}
def doAddNode(userId: User.ID, study: Study, position: Position, rawNode: Node, uid: Uid, opts: MoveOpts): Fu[Option[Position]] = {
def doAddNode(userId: User.ID, study: Study, position: Position, rawNode: Node, uid: Uid, opts: MoveOpts, relayMoveAt: Option[DateTime]): Fu[Option[Position]] = {
val node = rawNode.withoutChildren
position.chapter.addNode(node, position.path) match {
position.chapter.addNode(node, position.path, relayMoveAt) match {
case None =>
fufail(s"Invalid addNode ${study.id} ${position.ref} $node") >>-
reloadUidBecauseOf(study, uid, position.chapter.id) inject none
@ -191,6 +192,7 @@ final class StudyApi(
chapter.root.nodeAt(position.path) ?? { parent =>
val newPosition = position.ref + node
chapterRepo.setChildren(chapter, position.path, parent.children) >>
(relayMoveAt ?? { chapterRepo.setRelayLastMoveAt(chapter.id, _) }) >>
(opts.sticky ?? studyRepo.setPosition(study.id, newPosition)) >>
updateConceal(study, chapter, newPosition) >>- {
sendTo(study, Socket.AddNode(position.ref, node, chapter.setup.variant, uid, sticky = opts.sticky))

View File

@ -2,6 +2,10 @@ import AnalyseCtrl from './ctrl';
import { h } from 'snabbdom'
import { VNode } from 'snabbdom/vnode'
interface ClockOpts {
tenths: boolean;
}
export default function(ctrl: AnalyseCtrl): VNode | undefined {
const node = ctrl.node, clock = node.clock;
if (!clock && clock !== 0) return;
@ -17,25 +21,28 @@ export default function(ctrl: AnalyseCtrl): VNode | undefined {
blackCentis = parentClock;
}
const whitePov = ctrl.bottomColor() === 'white';
const whiteEl = renderClock(whiteCentis, isWhiteTurn);
const blackEl = renderClock(blackCentis, !isWhiteTurn);
const opts = {
tenths: !ctrl.study || !ctrl.study.relay
};
const whiteEl = renderClock(whiteCentis, isWhiteTurn, opts);
const blackEl = renderClock(blackCentis, !isWhiteTurn, opts);
return h('div.aclocks', whitePov ? [blackEl, whiteEl] : [whiteEl, blackEl]);
}
function renderClock(centis: number, active: boolean): VNode {
function renderClock(centis: number, active: boolean, opts: ClockOpts): VNode {
return h('div.aclock', {
class: { active },
}, clockContent(centis));
}, clockContent(centis, opts));
}
function clockContent(centis: number): Array<string | VNode> {
function clockContent(centis: number, opts: ClockOpts): Array<string | VNode> {
if (!centis && centis !== 0) return ['-'];
const date = new Date(centis * 10),
millis = date.getUTCMilliseconds(),
sep = ':',
baseStr = pad2(date.getUTCMinutes()) + sep + pad2(date.getUTCSeconds());
if (centis >= 360000) return [Math.floor(centis / 360000) + sep + baseStr];
if (!opts.tenths || centis >= 360000) return [Math.floor(centis / 360000) + sep + baseStr];
const tenthsStr = Math.floor(millis / 100).toString();
return [
baseStr,