send more live relay metadata to the client; make clocks tick
parent
75f86931c0
commit
793637eb6b
|
@ -71,7 +71,10 @@ private final class RelaySync(
|
|||
rawNode = n,
|
||||
uid = socketUid,
|
||||
opts = moveOpts.copy(clock = n.clock),
|
||||
relayMoveAt = DateTime.now.some
|
||||
relay = Chapter.Relay(
|
||||
path = position.path + n,
|
||||
lastMoveAt = DateTime.now.some
|
||||
).some
|
||||
) flatten s"Can't add relay node $position $node"
|
||||
} inject node.mainline.size
|
||||
}
|
||||
|
|
|
@ -237,6 +237,7 @@ object BSONHandlers {
|
|||
Tags(_)
|
||||
)
|
||||
private implicit val ChapterSetupBSONHandler = Macros.handler[Chapter.Setup]
|
||||
implicit val ChapterRelayBSONHandler = Macros.handler[Chapter.Relay]
|
||||
import Chapter.Ply
|
||||
implicit val PlyBSONHandler = intAnyValHandler[Ply](_.value, Ply.apply)
|
||||
implicit val ChapterBSONHandler = Macros.handler[Chapter]
|
||||
|
|
|
@ -22,7 +22,7 @@ case class Chapter(
|
|||
practice: Option[Boolean] = None,
|
||||
gamebook: Option[Boolean] = None,
|
||||
description: Option[String] = None,
|
||||
relayLastMoveAt: Option[DateTime] = None,
|
||||
relay: Option[Chapter.Relay] = None,
|
||||
createdAt: DateTime
|
||||
) extends Chapter.Like {
|
||||
|
||||
|
@ -31,13 +31,11 @@ case class Chapter(
|
|||
copy(root = newRoot)
|
||||
}
|
||||
|
||||
def addNode(node: Node, path: Path, relayMoveAt: Option[DateTime] = None): Option[Chapter] =
|
||||
updateRoot { root =>
|
||||
root.withChildren(_.addNodeAt(node, path))
|
||||
def addNode(node: Node, path: Path, newRelay: Option[Chapter.Relay] = None): Option[Chapter] =
|
||||
updateRoot {
|
||||
_.withChildren(_.addNodeAt(node, path))
|
||||
} map {
|
||||
_.copy(
|
||||
relayLastMoveAt = relayMoveAt orElse relayLastMoveAt
|
||||
)
|
||||
_.copy(relay = newRelay orElse relay)
|
||||
}
|
||||
|
||||
def setShapes(shapes: Shapes, path: Path): Option[Chapter] =
|
||||
|
@ -82,10 +80,6 @@ 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 {
|
||||
|
@ -114,6 +108,15 @@ object Chapter {
|
|||
def isFromFen = ~fromFen
|
||||
}
|
||||
|
||||
case class Relay(
|
||||
path: Path,
|
||||
lastMoveAt: Option[DateTime]
|
||||
) {
|
||||
def secondsSinceLastMove: Option[Int] = lastMoveAt.map { at =>
|
||||
(nowSeconds - at.getSeconds).toInt
|
||||
}
|
||||
}
|
||||
|
||||
case class Metadata(
|
||||
_id: Chapter.Id,
|
||||
name: Chapter.Name,
|
||||
|
|
|
@ -60,8 +60,8 @@ 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 setRelay(chapterId: Chapter.Id, relay: Chapter.Relay) =
|
||||
coll.updateField($id(chapterId), "relay", relay).void
|
||||
|
||||
def setTagsFor(chapter: Chapter) =
|
||||
coll.updateField($id(chapter.id), "tags", chapter.tags).void
|
||||
|
|
|
@ -47,7 +47,7 @@ final class JsonView(
|
|||
"explorer" -> allowed(study.settings.explorer)
|
||||
)
|
||||
).add("description", currentChapter.description)
|
||||
.add("relaySecondsSinceLastMove", currentChapter.relaySecondsSinceLastMove) |> addChapterMode(currentChapter)
|
||||
.add("relay", currentChapter.relay)(relayWrites) |> addChapterMode(currentChapter)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -177,4 +177,9 @@ object JsonView {
|
|||
JsNumber(p.value)
|
||||
}
|
||||
private[study] implicit val likingRefWrites: Writes[Study.Liking] = Json.writes[Study.Liking]
|
||||
|
||||
implicit val relayWrites = OWrites[Chapter.Relay] { r =>
|
||||
Json.obj("path" -> r.path)
|
||||
.add("secondsSinceLastMove", r.secondsSinceLastMove)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package lila.study
|
||||
|
||||
import akka.actor._
|
||||
import org.joda.time.DateTime
|
||||
import play.api.libs.json._
|
||||
import scala.concurrent.duration._
|
||||
import org.joda.time.DateTime
|
||||
|
||||
import chess.Centis
|
||||
import chess.format.pgn.Glyphs
|
||||
import lila.common.PimpedJson._
|
||||
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,
|
||||
|
@ -69,7 +69,7 @@ private final class Socket(
|
|||
"w" -> who(uid).map(whoWriter.writes)
|
||||
), noMessadata)
|
||||
|
||||
case AddNode(pos, node, variant, uid, sticky) =>
|
||||
case AddNode(pos, node, variant, uid, sticky, relay) =>
|
||||
val dests = AnaDests(
|
||||
variant,
|
||||
node.fen,
|
||||
|
@ -83,7 +83,7 @@ private final class Socket(
|
|||
"d" -> dests.dests,
|
||||
"o" -> dests.opening,
|
||||
"s" -> sticky
|
||||
), noMessadata)
|
||||
).add("relay", relay), noMessadata)
|
||||
|
||||
case DeleteNode(pos, uid) => notifyVersion("deleteNode", Json.obj(
|
||||
"p" -> pos,
|
||||
|
@ -300,7 +300,8 @@ object Socket {
|
|||
node: Node,
|
||||
variant: chess.variant.Variant,
|
||||
uid: Uid,
|
||||
sticky: Boolean
|
||||
sticky: Boolean,
|
||||
relay: Option[Chapter.Relay]
|
||||
)
|
||||
case class DeleteNode(position: Position.Ref, uid: Uid)
|
||||
case class Promote(position: Position.Ref, toMainline: Boolean, uid: Uid)
|
||||
|
|
|
@ -84,6 +84,8 @@ final class StudyApi(
|
|||
|
||||
def studyIdOf = chapterRepo.studyIdOf _
|
||||
|
||||
def members(id: Study.Id): Fu[Option[StudyMembers]] = studyRepo membersById id
|
||||
|
||||
def create(data: StudyMaker.Data, user: User): Fu[Option[Study.WithChapter]] = (data.form.as match {
|
||||
case DataForm.AsNewStudy =>
|
||||
studyMaker(data, user) flatMap { res =>
|
||||
|
@ -182,9 +184,9 @@ final class StudyApi(
|
|||
}
|
||||
}
|
||||
|
||||
def doAddNode(userId: User.ID, study: Study, position: Position, rawNode: Node, uid: Uid, opts: MoveOpts, relayMoveAt: Option[DateTime]): Fu[Option[Position]] = {
|
||||
def doAddNode(userId: User.ID, study: Study, position: Position, rawNode: Node, uid: Uid, opts: MoveOpts, relay: Option[Chapter.Relay]): Fu[Option[Position]] = {
|
||||
val node = rawNode.withoutChildren
|
||||
position.chapter.addNode(node, position.path, relayMoveAt) match {
|
||||
position.chapter.addNode(node, position.path, relay) match {
|
||||
case None =>
|
||||
fufail(s"Invalid addNode ${study.id} ${position.ref} $node") >>-
|
||||
reloadUidBecauseOf(study, uid, position.chapter.id) inject none
|
||||
|
@ -192,10 +194,17 @@ 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, _) }) >>
|
||||
(relay ?? { chapterRepo.setRelay(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))
|
||||
sendTo(study, Socket.AddNode(
|
||||
position.ref,
|
||||
node,
|
||||
chapter.setup.variant,
|
||||
uid,
|
||||
sticky = opts.sticky,
|
||||
relay = relay
|
||||
))
|
||||
sendStudyEnters(study, userId)
|
||||
if (opts.promoteToMainline && !Path.isMainline(chapter.root, newPosition.path))
|
||||
promote(userId, study.id, position.ref + node, toMainline = true, uid)
|
||||
|
|
|
@ -5,6 +5,7 @@ import play.api.libs.json.Json
|
|||
|
||||
import actorApi._
|
||||
import lila.hub.actorApi.SendTos
|
||||
import lila.socket.Socket.makeMessage
|
||||
|
||||
private[tournament] final class Reminder extends Actor {
|
||||
|
||||
|
@ -16,9 +17,9 @@ private[tournament] final class Reminder extends Actor {
|
|||
val userIds =
|
||||
if (activeUserIds.size > max) scala.util.Random.shuffle(activeUserIds) take max
|
||||
else activeUserIds
|
||||
context.system.lilaBus.publish(SendTos(userIds.toSet, Json.obj(
|
||||
"t" -> "tournamentReminder",
|
||||
"d" -> Json.obj(
|
||||
context.system.lilaBus.publish(SendTos(userIds.toSet, makeMessage(
|
||||
"tournamentReminder",
|
||||
Json.obj(
|
||||
"id" -> tour.id,
|
||||
"name" -> tour.fullName
|
||||
)
|
||||
|
|
|
@ -20,7 +20,16 @@ export default function(ctrl: AnalyseCtrl): VNode | undefined {
|
|||
whiteCentis = clock;
|
||||
blackCentis = parentClock;
|
||||
}
|
||||
const whitePov = ctrl.bottomColor() === 'white';
|
||||
const study = ctrl.study,
|
||||
whitePov = ctrl.bottomColor() === 'white';
|
||||
|
||||
const relay = study && study.data.chapter.relay;
|
||||
if (relay && relay.lastMoveAt && relay.path === ctrl.path && ctrl.path !== '') {
|
||||
const spent = (Date.now() - relay.lastMoveAt) / 10;
|
||||
if (isWhiteTurn) whiteCentis -= spent;
|
||||
else blackCentis -= spent;
|
||||
}
|
||||
|
||||
const opts = {
|
||||
tenths: !ctrl.study || !ctrl.study.relay
|
||||
};
|
||||
|
|
|
@ -125,6 +125,13 @@ export interface StudyChapter {
|
|||
gamebook: boolean;
|
||||
features: StudyChapterFeatures;
|
||||
description?: string;
|
||||
relay?: StudyChapterRelay;
|
||||
}
|
||||
|
||||
interface StudyChapterRelay {
|
||||
path: Tree.Path;
|
||||
secondsSinceLastMove?: number;
|
||||
lastMoveAt?: number;
|
||||
}
|
||||
|
||||
interface StudyChapterSetup {
|
||||
|
|
|
@ -8,6 +8,7 @@ export default class RelayCtrl {
|
|||
|
||||
constructor(d: RelayData, readonly send: SocketSend, readonly redraw: () => void, readonly members: any) {
|
||||
this.data = d;
|
||||
setInterval(this.redraw, 1000);
|
||||
}
|
||||
|
||||
setSync = (v: Boolean) => {
|
||||
|
|
|
@ -30,6 +30,8 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
|||
|
||||
const sri: string = li.StrongSocket ? li.StrongSocket.sri : '';
|
||||
|
||||
convertRelayDate();
|
||||
|
||||
const vm: StudyVm = (function() {
|
||||
const isManualChapter = data.chapter.id !== data.position.chapterId;
|
||||
const sticked = data.features.sticky && !ctrl.initialPath && !isManualChapter && !practiceData;
|
||||
|
@ -163,6 +165,7 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
|||
members.dict(s.members);
|
||||
chapters.list(s.chapters);
|
||||
ctrl.flipped = false;
|
||||
convertRelayDate();
|
||||
|
||||
const merge = !vm.mode.write && sameChapter;
|
||||
ctrl.reloadData(d.analysis, merge);
|
||||
|
@ -194,6 +197,12 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
|||
ctrl.startCeval();
|
||||
};
|
||||
|
||||
function convertRelayDate() {
|
||||
const relay = data.chapter.relay;
|
||||
if (relay && typeof relay.secondsSinceLastMove !== 'undefined' && !relay.lastMoveAt)
|
||||
relay.lastMoveAt = Date.now() - relay.secondsSinceLastMove * 1000;
|
||||
}
|
||||
|
||||
function xhrReload() {
|
||||
vm.loading = true;
|
||||
return xhr.reload(
|
||||
|
@ -295,6 +304,10 @@ export default function(data: StudyData, ctrl: AnalyseCtrl, tagTypes: TagTypes,
|
|||
data.position.path = position.path + node.id;
|
||||
return;
|
||||
}
|
||||
if (d.relay) {
|
||||
data.chapter.relay = d.relay;
|
||||
convertRelayDate();
|
||||
}
|
||||
const newPath = ctrl.tree.addNode(node, position.path);
|
||||
if (!newPath) return xhrReload();
|
||||
ctrl.tree.addDests(d.d, newPath, d.o);
|
||||
|
|
Loading…
Reference in New Issue