From d342021d6edc9ce852d3b0633c93be2ebda5c216 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Thu, 20 Jun 2024 09:55:12 +0200 Subject: [PATCH] combine lcc sources --- modules/relay/src/main/BSONHandlers.scala | 16 +++++++++++--- modules/relay/src/main/JsonView.scala | 5 ++--- modules/relay/src/main/RelayDelay.scala | 2 +- modules/relay/src/main/RelayFormat.scala | 2 +- modules/relay/src/main/RelayRound.scala | 24 ++++++++++++++------- modules/relay/src/main/RelayRoundForm.scala | 13 +++++++---- 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/modules/relay/src/main/BSONHandlers.scala b/modules/relay/src/main/BSONHandlers.scala index 03b4f2377624..4c6da447cce5 100644 --- a/modules/relay/src/main/BSONHandlers.scala +++ b/modules/relay/src/main/BSONHandlers.scala @@ -10,9 +10,19 @@ object BSONHandlers: given BSONHandler[RelayTeamsTextarea] = stringAnyValHandler(_.text, RelayTeamsTextarea(_)) import RelayRound.Sync - import Sync.{ Upstream, UpstreamIds, UpstreamUrl, UpstreamLcc, UpstreamUrls } - given upstreamUrlHandler: BSONDocumentHandler[UpstreamUrl] = Macros.handler - given upstreamLccHandler: BSONDocumentHandler[UpstreamLcc] = Macros.handler + import Sync.{ Upstream, UpstreamIds, UpstreamUrl, UpstreamLcc, UpstreamUrls, FetchableUpstream } + given upstreamUrlHandler: BSONDocumentHandler[UpstreamUrl] = Macros.handler + given upstreamLccHandler: BSONDocumentHandler[UpstreamLcc] = Macros.handler + given BSONHandler[FetchableUpstream] = tryHandler( + { + case d: BSONDocument if d.contains("url") => upstreamUrlHandler.readTry(d) + case d: BSONDocument if d.contains("lcc") => upstreamLccHandler.readTry(d) + }, + { + case url: UpstreamUrl => upstreamUrlHandler.writeTry(url).get + case lcc: UpstreamLcc => upstreamLccHandler.writeTry(lcc).get + } + ) given upstreamUrlsHandler: BSONDocumentHandler[UpstreamUrls] = Macros.handler given upstreamIdsHandler: BSONDocumentHandler[UpstreamIds] = Macros.handler diff --git a/modules/relay/src/main/JsonView.scala b/modules/relay/src/main/JsonView.scala index 8625ba6c272c..40110e054f14 100644 --- a/modules/relay/src/main/JsonView.scala +++ b/modules/relay/src/main/JsonView.scala @@ -178,9 +178,8 @@ object JsonView: "log" -> s.log.events ) .add("delay" -> s.delay) ++ - s.upstream.so { + s.upstream.so: case Sync.UpstreamUrl(url) => Json.obj("url" -> url) case Sync.UpstreamLcc(url, round) => Json.obj("url" -> url, "round" -> round) - case Sync.UpstreamUrls(urls) => Json.obj("urls" -> urls.map(_.url)) + case Sync.UpstreamUrls(urls) => Json.obj("urls" -> urls.map(_.formUrl)) case Sync.UpstreamIds(ids) => Json.obj("ids" -> ids) - } diff --git a/modules/relay/src/main/RelayDelay.scala b/modules/relay/src/main/RelayDelay.scala index 81add186ced9..2666e314861b 100644 --- a/modules/relay/src/main/RelayDelay.scala +++ b/modules/relay/src/main/RelayDelay.scala @@ -51,7 +51,7 @@ final private class RelayDelay(colls: RelayColls)(using Executor): private object store: - private def idOf(upstream: FetchableUpstream, at: Instant) = s"${upstream.url} ${at.toSeconds}" + private def idOf(upstream: FetchableUpstream, at: Instant) = s"${upstream.formUrl} ${at.toSeconds}" private val longPast = java.time.Instant.ofEpochMilli(0) def putIfNew(upstream: FetchableUpstream, games: RelayGames): Funit = diff --git a/modules/relay/src/main/RelayFormat.scala b/modules/relay/src/main/RelayFormat.scala index 6938a708c357..0270c7a0d843 100644 --- a/modules/relay/src/main/RelayFormat.scala +++ b/modules/relay/src/main/RelayFormat.scala @@ -47,7 +47,7 @@ final private class RelayFormatApi( private def guessFormat(upstream: FetchableUpstream)(using CanProxy): Fu[RelayFormat] = { - def parsedUrl = URL.parse(upstream.url) + def parsedUrl = URL.parse(upstream.fetchUrl) def guessLcc: Fu[Option[RelayFormat]] = upstream.isLcc.so(guessManyFiles(parsedUrl)) diff --git a/modules/relay/src/main/RelayRound.scala b/modules/relay/src/main/RelayRound.scala index 3b70161ee067..6308fe4d0f26 100644 --- a/modules/relay/src/main/RelayRound.scala +++ b/modules/relay/src/main/RelayRound.scala @@ -117,19 +117,27 @@ object RelayRound: sealed trait Upstream: def isLcc = false sealed trait FetchableUpstream extends Upstream: - def url: String + def fetchUrl: String + def formUrl: String case class UpstreamUrl(url: String) extends FetchableUpstream: - def findLccId: Option[String] = url match - case LccRegex(id) => id.some - case _ => none + def fetchUrl = url + def formUrl = url + case class UpstreamUrls(urls: List[FetchableUpstream]) extends Upstream + case class UpstreamIds(ids: List[GameId]) extends Upstream case class UpstreamLcc(lcc: String, round: Int) extends FetchableUpstream: override def isLcc = true def id = lcc - def url = s"http://1.pool.livechesscloud.com/get/$id/round-$round/index.json" + def fetchUrl = s"http://1.pool.livechesscloud.com/get/$id/round-$round/index.json" def viewUrl = s"https://view.livechesscloud.com/#$id" - case class UpstreamUrls(urls: List[UpstreamUrl]) extends Upstream - case class UpstreamIds(ids: List[GameId]) extends Upstream - private val LccRegex = """.*view\.livechesscloud\.com/?#?([0-9a-f\-]+)""".r + def formUrl = s"$viewUrl $round" + object UpstreamLcc: + private val idRegex = """.*view\.livechesscloud\.com/?#?([0-9a-f\-]+)""".r + def findId(url: UpstreamUrl): Option[String] = url.url match + case idRegex(id) => id.some + case _ => none + def find(url: String): Option[UpstreamLcc] = url.split(' ').map(_.trim).filter(_.nonEmpty) match + case Array(idRegex(id), round) => round.toIntOption.map(UpstreamLcc(id, _)) + case _ => none trait AndTour: val tour: RelayTour diff --git a/modules/relay/src/main/RelayRoundForm.scala b/modules/relay/src/main/RelayRoundForm.scala index 3140e3f317b4..ec0a821b282e 100644 --- a/modules/relay/src/main/RelayRoundForm.scala +++ b/modules/relay/src/main/RelayRoundForm.scala @@ -19,15 +19,15 @@ final class RelayRoundForm(using mode: Mode): import RelayRoundForm.* import lila.common.Form.ISOInstantOrTimestamp - private given Formatter[Sync.UpstreamUrl] = formatter.stringTryFormatter(validateUpstreamUrl, _.url) + private given Formatter[Sync.UpstreamUrl] = formatter.stringTryFormatter(validateUpstreamUrl, _.fetchUrl) private given Formatter[Sync.UpstreamUrls] = formatter.stringTryFormatter( _.linesIterator.toList .map(_.trim) .filter(_.nonEmpty) - .traverse(validateUpstreamUrl) + .traverse(validateUpstreamUrlOrLcc) .map(_.distinct) .map(Sync.UpstreamUrls.apply), - _.urls.map(_.url).mkString("\n") + _.urls.map(_.formUrl).mkString("\n") ) private given Formatter[Sync.UpstreamIds] = formatter.stringTryFormatter( _.split(' ').toList @@ -147,6 +147,11 @@ object RelayRoundForm: if !subdomain(host, "chess.com") || url.toString.startsWith("https://api.chess.com/pub") yield url.toString.stripSuffix("/") + private def validateUpstreamUrlOrLcc(s: String)(using Mode): Either[String, Sync.FetchableUpstream] = + Sync.UpstreamLcc.find(s) match + case Some(lcc) => Right(lcc) + case None => validateUpstreamUrl(s) + private def validateUpstreamUrl(s: String)(using Mode): Either[String, Sync.UpstreamUrl] = for url <- cleanUrl(s).toRight("Invalid source URL") url <- if !validSourcePort(url) then Left("The source URL cannot specify a port") else Right(url) @@ -209,7 +214,7 @@ object RelayRoundForm: .map: case url: Sync.UpstreamUrl => val foundLcc = for - lccId <- url.findLccId + lccId <- Sync.UpstreamLcc.findId(url) round <- roundNumberIn(name.value) yield Sync.UpstreamLcc(lccId, round) foundLcc | url