Skip to content

Commit

Permalink
opaque type UserId: /api
Browse files Browse the repository at this point in the history
  • Loading branch information
ornicar committed Nov 29, 2022
1 parent d05ca42 commit 809e610
Show file tree
Hide file tree
Showing 24 changed files with 65 additions and 56 deletions.
10 changes: 6 additions & 4 deletions modules/api/src/main/AccountClosure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ final class AccountClosure(
_ <- pushEnv.unregisterDevices(u)
_ <- streamerApi.demote(u.id)
reports <- reportApi.processAndGetBySuspect(lila.report.Suspect(u))
_ <- if (selfClose) modLogApi.selfCloseAccount(u.id, reports) else modLogApi.closeAccount(by.id, u.id)
_ <-
if (selfClose) modLogApi.selfCloseAccount(u.id, reports)
else modLogApi.closeAccount(by.id into ModId, u.id)
_ <- appealApi.onAccountClose(u)
_ <- u.marks.troll ?? relationApi.fetchFollowing(u.id).flatMap {
activityWrite.unfollowAll(u, _)
Expand All @@ -70,7 +72,7 @@ final class AccountClosure(
_ ?? { case (lichess, user) => close(user, lichess) }
}

def eraseClosed(username: String): Fu[Either[String, String]] =
def eraseClosed(username: UserId): Fu[Either[String, String]] =
userRepo byId username map {
case None => Left("No such user.")
case Some(user) =>
Expand All @@ -80,8 +82,8 @@ final class AccountClosure(
Right(s"Erasing all data about $username in 24h")
}

def closeThenErase(username: String, by: Holder): Fu[Either[String, String]] =
def closeThenErase(username: UserStr, by: Holder): Fu[Either[String, String]] =
userRepo byId username flatMap {
case None => fuccess(Left("No such user."))
case Some(u) => (u.enabled ?? close(u, by)) >> eraseClosed(u.username)
case Some(u) => (u.enabled ?? close(u, by)) >> eraseClosed(u.id)
}
2 changes: 1 addition & 1 deletion modules/api/src/main/ApiConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ object ApiConfig:
val blindCookieMaxAge = 365 days
def hash(using ctx: lila.user.UserContext) =
import com.roundeights.hasher.Implicits.*
(ctx.userId | "anon").salt(blindCookieSalt.value).md5.hex
ctx.userId.fold("anon")(_.value).salt(blindCookieSalt.value).md5.hex

final class PagerDuty(val serviceId: String, val apiKey: Secret)

Expand Down
4 changes: 2 additions & 2 deletions modules/api/src/main/Cli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ final private[api] class Cli(
import lila.common.AssetVersion
AssetVersion.change()
fuccess(s"Changed to ${AssetVersion.current}")
case "gdpr" :: "erase" :: username :: "forever" :: Nil =>
accountClosure.eraseClosed(username).map(_.fold(identity, identity))
case "gdpr" :: "erase" :: user :: "forever" :: Nil =>
accountClosure.eraseClosed(UserStr(user).id).map(_.fold(identity, identity))
case "announce" :: "cancel" :: Nil =>
AnnounceStore set none
Bus.publish(AnnounceStore.cancel, "announce")
Expand Down
3 changes: 2 additions & 1 deletion modules/api/src/main/LobbyApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import play.api.libs.json.{ JsArray, JsObject, Json }

import lila.game.Pov
import lila.lobby.{ LobbySocket, SeekApi }
import lila.common.Json.given

final class LobbyApi(
lightUserApi: lila.user.LightUserApi,
seekApi: SeekApi,
gameProxyRepo: lila.round.GameProxyRepo,
gameJson: lila.game.JsonView,
lobbySocket: LobbySocket
)(using ec: scala.concurrent.ExecutionContext):
)(using scala.concurrent.ExecutionContext):

def apply(using ctx: Context): Fu[(JsObject, List[Pov])] =
ctx.me.fold(seekApi.forAnon)(seekApi.forUser).mon(_.lobby segment "seeks") zip
Expand Down
6 changes: 3 additions & 3 deletions modules/api/src/main/PersonalDataExport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ final class PersonalDataExport(
val followedUsers =
Source.futureSource {
relationEnv.api.fetchFollowing(user.id) map { userIds =>
Source(List(textTitle("Followed players")) ++ userIds)
Source(List(textTitle("Followed players")) ++ userIds.map(_.value))
}
}

Expand Down Expand Up @@ -146,7 +146,7 @@ final class PersonalDataExport(
)
}
.documentSource()
.map { doc => doc.string("l").??(_.drop(user.id.size + 1)) }
.map { doc => doc.string("l").??(_.drop(user.id.value.size + 1)) }
.throttle(heavyPerSecond, 1 second)

val privateGameChats =
Expand Down Expand Up @@ -219,7 +219,7 @@ final class PersonalDataExport(

val outro = Source(List(textTitle("End of data export.")))

List(
List[Source[String, _]](
intro,
connections,
followedUsers,
Expand Down
8 changes: 4 additions & 4 deletions modules/api/src/main/RealPlayer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ final class RealPlayerApi(
}

private def make(id: String, name: Option[String], rating: Option[String]) =
val (n, r) = name.filter(_.nonEmpty) -> rating.flatMap(_.toIntOption)
val (n, r) = UserName.from(name.filter(_.nonEmpty)) -> rating.flatMap(_.toIntOption)
(n.isDefined || r.isDefined) option {
User.normalize(id) -> RealPlayer(name = n, rating = r)
UserStr(id).id -> RealPlayer(name = n, rating = IntRating from r)
}

case class RealPlayers(players: Map[UserId, RealPlayer]):
Expand All @@ -61,12 +61,12 @@ case class RealPlayers(players: Map[UserId, RealPlayer]):
game.players.flatMap { player =>
player.userId.flatMap(players.get) ?? { rp =>
List(
rp.name.map { name => Tag(player.color.fold(Tag.White, Tag.Black), name) },
rp.name.map { name => Tag(player.color.fold(Tag.White, Tag.Black), name.value) },
rp.rating.map { rating => Tag(player.color.fold(Tag.WhiteElo, Tag.BlackElo), rating.toString) }
).flatten
}
}
}
)

case class RealPlayer(name: Option[String], rating: Option[Int])
case class RealPlayer(name: Option[UserName], rating: Option[IntRating])
12 changes: 6 additions & 6 deletions modules/api/src/main/UserApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@ final class UserApi(
shieldApi: lila.tournament.TournamentShieldApi,
revolutionApi: lila.tournament.RevolutionApi,
net: NetConfig
)(using ec: scala.concurrent.ExecutionContext):
)(using scala.concurrent.ExecutionContext):

def one(u: User): JsObject =
addStreaming(jsonView.full(u, withRating = true, withProfile = true), u.id) ++
Json.obj("url" -> makeUrl(s"@/${u.username}")) // for app BC

def extended(
username: String,
username: UserName,
as: Option[User],
withFollows: Boolean,
withTrophies: Boolean
)(using lang: Lang): Fu[Option[JsObject]] =
)(using Lang): Fu[Option[JsObject]] =
userRepo byId username flatMap {
_ ?? { extended(_, as, withFollows, withTrophies) dmap some }
}
Expand All @@ -47,7 +47,7 @@ final class UserApi(
as: Option[User],
withFollows: Boolean,
withTrophies: Boolean
)(using lang: Lang): Fu[JsObject] =
)(using Lang): Fu[JsObject] =
if (u.disabled) fuccess(jsonView disabled u.light)
else
gameProxyRepo.urgentGames(u).dmap(_.headOption) zip
Expand Down Expand Up @@ -116,7 +116,7 @@ final class UserApi(
UserApi.TrophiesAndAwards(userCache.rankingsOf(u.id), trophies ::: roleTrophies, shields, revols)
}

private def trophiesJson(all: UserApi.TrophiesAndAwards)(using lang: Lang): JsArray =
private def trophiesJson(all: UserApi.TrophiesAndAwards)(using Lang): JsArray =
JsArray {
all.ranks.toList.sortBy(_._2).collect {
case (perf, rank) if rank == 1 => perfTopTrophy(perf, 1, "Champion")
Expand All @@ -135,7 +135,7 @@ final class UserApi(
}
}

private def perfTopTrophy(perf: PerfType, top: Int, name: String)(using lang: Lang) = Json.obj(
private def perfTopTrophy(perf: PerfType, top: Int, name: String)(using Lang) = Json.obj(
"type" -> "perfTop",
"perf" -> perf.key,
"top" -> top,
Expand Down
2 changes: 1 addition & 1 deletion modules/bot/src/main/BotJsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ final class BotJsonView(
.add("rematch" -> rematches.getAcceptedId(game.id))
}

def chatLine(username: String, text: String, player: Boolean) =
def chatLine(username: UserName, text: String, player: Boolean) =
Json.obj(
"type" -> "chatLine",
"room" -> (if (player) "player" else "spectator"),
Expand Down
4 changes: 2 additions & 2 deletions modules/bot/src/main/BotPlayer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class BotPlayer(
def apply(pov: Pov, me: User, uciStr: String, offeringDraw: Option[Boolean]): Funit =
lila.common.Future.delay((pov.game.hasAi ?? 500) millis) {
Uci(uciStr).fold(clientError[Unit](s"Invalid UCI: $uciStr")) { uci =>
lila.mon.bot.moves(me.username).increment()
lila.mon.bot.moves(me.username.value).increment()
if (!pov.isMyTurn) clientError("Not your turn, or game already over")
else
val promise = Promise[Unit]()
Expand All @@ -42,7 +42,7 @@ final class BotPlayer(
def chat(gameId: GameId, me: User, d: BotForm.ChatData) =
!spam.detect(d.text) ??
fuccess {
lila.mon.bot.chats(me.username).increment()
lila.mon.bot.chats(me.username.value).increment()
val chatId = ChatId(if (d.room == "player") gameId.value else s"$gameId/w")
val source = d.room == "spectator" option {
lila.hub.actorApi.shutup.PublicSource.Watcher(gameId)
Expand Down
2 changes: 1 addition & 1 deletion modules/bot/src/main/GameStateStream.scala
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ final class GameStateStream(
def pushState(g: Game): Funit =
jsonView gameState Game.WithInitialFen(g, init.fen) dmap some flatMap queue.offer void

def pushChatLine(username: String, text: String, player: Boolean) =
def pushChatLine(username: UserName, text: String, player: Boolean) =
queue offer jsonView.chatLine(username, text, player).some

def opponentGone(claimInSeconds: Option[Int]) = queue offer {
Expand Down
2 changes: 1 addition & 1 deletion modules/challenge/src/main/BSONHandlers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private object BSONHandlers:
"p" -> w.boolO(r.provisional)
)
given registeredHandler: BSON[Challenger.Registered] with
def reads(r: Reader) = Challenger.Registered(r.str("id"), r.get[Rating]("r"))
def reads(r: Reader) = Challenger.Registered(r.get[UserId]("id"), r.get[Rating]("r"))
def writes(w: Writer, r: Challenger.Registered) =
$doc(
"id" -> r.id,
Expand Down
6 changes: 3 additions & 3 deletions modules/challenge/src/main/ChallengeApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ final class ChallengeApi(
socket.foreach(_ reload id)

private object notifyUser:
private val throttler = new lila.hub.EarlyMultiThrottler(logger)
private val throttler = new lila.hub.EarlyMultiThrottler[UserId](logger)
def apply(userId: UserId): Unit = throttler(userId, 3.seconds) {
for {
for
all <- allFor(userId)
lang <- userRepo langOf userId map I18nLangPicker.byStrOrDefault
_ <- lightUserApi.preloadMany(all.all.flatMap(_.userIds))
} yield Bus.publish(
yield Bus.publish(
SendTo(userId, lila.socket.Socket.makeMessage("challenges", jsonView(all)(using lang))),
"socketUsers"
)
Expand Down
8 changes: 4 additions & 4 deletions modules/challenge/src/main/ChallengeBulk.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ final class ChallengeBulkApi(
.updateField($doc("_id" -> id, "by" -> me.id, "pairedAt" $exists true), "startClocksAt", DateTime.now)
.map(_.n == 1)

def schedule(bulk: ScheduledBulk): Fu[Either[String, ScheduledBulk]] = workQueue(UserId(bulk.by)) {
def schedule(bulk: ScheduledBulk): Fu[Either[String, ScheduledBulk]] = workQueue(bulk.by) {
coll.list[ScheduledBulk]($doc("by" -> bulk.by, "pairedAt" $exists false)) flatMap { bulks =>
val nbGames = bulks.map(_.games.size).sum
if (bulks.sizeIs >= 10) fuccess(Left("Already too many bulks queued"))
Expand All @@ -79,7 +79,7 @@ final class ChallengeBulkApi(
private def checkForPairing: Funit =
coll.one[ScheduledBulk]($doc("pairAt" $lte DateTime.now, "pairedAt" $exists false)) flatMap {
_ ?? { bulk =>
workQueue(UserId(bulk.by)) {
workQueue(bulk.by) {
makePairings(bulk).void
}
}
Expand All @@ -88,7 +88,7 @@ final class ChallengeBulkApi(
private def checkForClocks: Funit =
coll.one[ScheduledBulk]($doc("startClocksAt" $lte DateTime.now, "pairedAt" $exists true)) flatMap {
_ ?? { bulk =>
workQueue(UserId(bulk.by)) {
workQueue(bulk.by) {
startClocksNow(bulk)
}
}
Expand Down Expand Up @@ -138,7 +138,7 @@ final class ChallengeBulkApi(
.toMat(LilaStream.sinkCount)(Keep.right)
.run()
.addEffect { nb =>
lila.mon.api.challenge.bulk.createNb(bulk.by).increment(nb).unit
lila.mon.api.challenge.bulk.createNb(bulk.by.value).increment(nb).unit
} >> {
if (bulk.startClocksAt.isDefined)
coll.updateField($id(bulk._id), "pairedAt", DateTime.now)
Expand Down
2 changes: 1 addition & 1 deletion modules/challenge/src/main/JsonView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class JsonView(
Json
.obj(
"id" -> r.id,
"name" -> light.fold(r.id)(_.name),
"name" -> light.fold(r.id into UserName)(_.name),
"title" -> light.map(_.title),
"rating" -> r.rating.int
)
Expand Down
11 changes: 5 additions & 6 deletions modules/challenge/src/main/model.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package lila.challenge
case class AllChallenges(in: List[Challenge], out: List[Challenge]):
def all = in ::: out

sealed trait Direction:
val name = toString.toLowerCase
object Direction:
case object In extends Direction // I can accept this challenge
case object Out extends Direction // I created this challenge
enum Direction:
def name = Direction.this.toString.toLowerCase
case In // I can accept this challenge
case Out // I created this challenge

object Event:
case class Create(c: Challenge)
case class Accept(c: Challenge, joinerId: Option[String])
case class Accept(c: Challenge, joinerId: Option[UserId])
case class Decline(c: Challenge)
case class Cancel(c: Challenge)
10 changes: 7 additions & 3 deletions modules/hub/src/main/EarlyMultiThrottler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ import lila.log.Logger
/** Runs the work then waits cooldown only runs once at a time per id. Guarantees that work is ran as early as
* possible. Also saves work and runs it after cooldown.
*/
final class EarlyMultiThrottler(logger: Logger)(using ec: ExecutionContext, system: ActorSystem):
final class EarlyMultiThrottler[K](logger: Logger)(using
sr: StringRuntime[K],
ec: ExecutionContext,
system: ActorSystem
):

private val actor = system.actorOf(Props(new EarlyMultiThrottlerActor(logger)))

def apply(id: String, cooldown: FiniteDuration)(run: => Funit) =
actor ! EarlyMultiThrottlerActor.Work(id, run = () => run, cooldown)
def apply(id: K, cooldown: FiniteDuration)(run: => Funit) =
actor ! EarlyMultiThrottlerActor.Work(sr(id), run = () => run, cooldown)

// actor based implementation
final private class EarlyMultiThrottlerActor(logger: Logger)(using ec: ExecutionContext) extends Actor:
Expand Down
2 changes: 1 addition & 1 deletion modules/push/src/main/PushApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ final private class PushApi(
}
}

def challengeAccept(c: Challenge, joinerId: Option[String]): Funit =
def challengeAccept(c: Challenge, joinerId: Option[UserId]): Funit =
c.challengerUser.ifTrue(c.finalColor.white && !c.hasClock) ?? { challenger =>
joinerId ?? lightUser flatMap { lightJoiner =>
pushToAll(
Expand Down
4 changes: 2 additions & 2 deletions modules/relay/src/main/RelayPush.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ final class RelayPush(sync: RelaySync, api: RelayApi)(using
ec: scala.concurrent.ExecutionContext
):

private val throttler = new lila.hub.EarlyMultiThrottler(logger)
private val throttler = new lila.hub.EarlyMultiThrottler[RelayRoundId](logger)

def apply(rt: RelayRound.WithTour, pgn: String): Fu[Option[String]] =
if (rt.round.sync.hasUpstream)
fuccess("The relay has an upstream URL, and cannot be pushed to.".some)
else
fuccess {
throttler(rt.round.id.value, if (rt.tour.official) 3.seconds else 7.seconds) {
throttler(rt.round.id, if (rt.tour.official) 3.seconds else 7.seconds) {
pushNow(rt, pgn)
}
none
Expand Down
2 changes: 1 addition & 1 deletion modules/setup/src/main/HookConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ case class HookConfig(
sri: lila.socket.Socket.Sri,
user: Option[User],
sid: Option[String],
blocking: Set[String]
blocking: Set[UserId]
): Either[Hook, Option[Seek]] =
timeMode match
case TimeMode.RealTime =>
Expand Down
4 changes: 2 additions & 2 deletions modules/setup/src/main/OpenConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ object OpenConfig:
days: Option[Days],
rated: Boolean,
pos: Option[FEN],
usernames: Option[List[String]],
usernames: Option[List[UserStr]],
rules: Option[Set[GameRule]]
) =
new OpenConfig(
Expand All @@ -47,7 +47,7 @@ object OpenConfig:
days = days,
rated = rated,
position = pos,
userIds = usernames.map(_.map(User.normalize)) collect { case List(w, b) =>
userIds = usernames.map(_.map(_.id)) collect { case List(w, b) =>
(w, b)
},
rules = ~rules
Expand Down
2 changes: 1 addition & 1 deletion modules/setup/src/main/Processor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final private[setup] class Processor(
configBase: HookConfig,
sri: lila.socket.Socket.Sri,
sid: Option[String],
blocking: Set[String]
blocking: Set[UserId]
)(using ctx: UserContext): Fu[Processor.HookResult] =
import Processor.HookResult.*
val config = configBase.fixColor
Expand Down
Loading

0 comments on commit 809e610

Please sign in to comment.