-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathLilaHandler.scala
216 lines (189 loc) · 8.56 KB
/
LilaHandler.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package lila.ws
import akka.actor.typed.ActorRef
import com.typesafe.scalalogging.Logger
import ipc._
import scala.concurrent.{ ExecutionContext, Promise }
final class LilaHandler(
lila: Lila,
users: Users,
friendList: FriendList,
roomCrowd: RoomCrowd,
roundCrowd: RoundCrowd,
mongo: Mongo,
clients: ActorRef[Clients.Control],
services: Services
)(implicit ec: ExecutionContext) {
import LilaOut._
import Bus.publish
private val logger = Logger(getClass)
private val siteHandler: Emit[LilaOut] = {
case Mlat(millis) => publish(_.mlat, ClientIn.Mlat(millis))
case TellFlag(flag, payload) => publish(_ flag flag, ClientIn.Payload(payload))
case TellSri(sri, payload) => publish(_ sri sri, ClientIn.Payload(payload))
case TellAll(payload) => publish(_.all, ClientIn.Payload(payload))
case TellUsers(us, json) => users.tellMany(us, ClientIn.Payload(json))
case DisconnectUser(user) => users.kick(user)
case TellRoomUser(roomId, user, json) =>
users.tellOne(user, ClientIn.onlyFor(_ Room roomId, ClientIn.Payload(json)))
case TellRoomUsers(roomId, us, json) =>
users.tellMany(us, ClientIn.onlyFor(_ Room roomId, ClientIn.Payload(json)))
case SetTroll(user, v) =>
users.setTroll(user, v)
mongo.troll.set(user, v)
case Follow(left, right) => friendList.follow(left, right)
case UnFollow(left, right) => friendList.unFollow(left, right)
case ApiUserOnline(user, true) =>
clients ! Clients.Start(
ApiActor start ApiActor.Deps(User(user), services),
Promise[_root_.lila.ws.Client]()
)
case ApiUserOnline(user, false) => users.tellOne(user, ClientCtrl.ApiDisconnect)
case Impersonate(user, by) => Impersonations(user, by)
case Pong(pingAt) => Monitor.ping.record("site", pingAt)
case LilaStop(reqId) =>
logger.info("******************** LILA STOP ********************")
lila.emit.site(LilaIn.ReqResponse(reqId, "See you on the other side"))
lila.status.setOffline()
case msg => logger.warn(s"Unhandled site: $msg")
}
private val lobbyHandler: Emit[LilaOut] = {
case TellLobbyUsers(us, json) =>
users.tellMany(us, ClientIn.onlyFor(_.Lobby, ClientIn.Payload(json)))
case TellLobby(payload) => publish(_.lobby, ClientIn.Payload(payload))
case TellLobbyActive(payload) =>
publish(_.lobby, ClientIn.LobbyNonIdle(ClientIn.Payload(payload)))
case TellSris(sris, payload) =>
sris foreach { sri =>
publish(_ sri sri, ClientIn.Payload(payload))
}
case LobbyPairings(pairings) =>
pairings.foreach { case (sri, fullId) => publish(_ sri sri, ClientIn.LobbyPairing(fullId)) }
case msg => roomHandler(msg)
}
private val simulHandler: Emit[LilaOut] = {
case LilaOut.RoomFilterPresent(reqId, roomId, userIds) =>
lila.emit.simul(LilaIn.ReqResponse(reqId, roomCrowd.filterPresent(roomId, userIds).mkString(",")))
case LilaBoot => roomBoot(_.idFilter.simul, lila.emit.simul)
case msg => roomHandler(msg)
}
private val teamHandler: Emit[LilaOut] = {
case LilaBoot => roomBoot(_.idFilter.team, lila.emit.team)
case msg => roomHandler(msg)
}
private val swissHandler: Emit[LilaOut] = {
case LilaBoot => roomBoot(_.idFilter.swiss, lila.emit.swiss)
case msg => roomHandler(msg)
}
private val tourHandler: Emit[LilaOut] = {
case GetWaitingUsers(roomId, name) =>
mongo.tournamentActiveUsers(roomId.value) zip mongo.tournamentPlayingUsers(roomId.value) foreach {
case (active, playing) =>
val present = roomCrowd getUsers roomId
val standby = active diff playing
val allAbsent = standby diff present
lila.emit.tour(LilaIn.WaitingUsers(roomId, name, present, standby))
val absent = {
if (allAbsent.sizeIs > 100) util.Util.threadLocalRandom.shuffle(allAbsent) take 80
else allAbsent
}
if (absent.nonEmpty) users.tellMany(absent, ClientIn.TourReminder(roomId.value, name))
}
case LilaBoot => roomBoot(_.idFilter.tour, lila.emit.tour)
case msg => roomHandler(msg)
}
private val studyHandler: Emit[LilaOut] = {
case LilaOut.RoomIsPresent(reqId, roomId, userId) =>
lila.emit.study(LilaIn.ReqResponse(reqId, roomCrowd.isPresent(roomId, userId).toString))
case LilaBoot => roomBoot(_.idFilter.study, lila.emit.study)
case msg => roomHandler(msg)
}
private val roundHandler: Emit[LilaOut] = {
implicit def gameRoomId(gameId: Game.Id): RoomId = RoomId(gameId)
implicit def roomGameId(roomId: RoomId): Game.Id = Game.Id(roomId.value)
({
case RoundVersion(gameId, version, flags, tpe, data) =>
val versioned = ClientIn.RoundVersioned(version, flags, tpe, data)
History.round.add(gameId, versioned)
publish(_ room gameId, versioned)
if (
List("move", "drop", "lift", "undo", "endturn", "pass", "diceroll", "cubeaction", "selectSquares").contains(tpe)
)
Fens.move(gameId, data, flags.moveBy)
case TellRoom(roomId, payload) => publish(_ room roomId, ClientIn.Payload(payload))
case RoundResyncPlayer(fullId) =>
publish(_ room RoomId(fullId.gameId), ClientIn.RoundResyncPlayer(fullId.playerId))
case RoundGone(fullId, gone) =>
publish(_ room RoomId(fullId.gameId), ClientIn.RoundGone(fullId.playerId, gone))
case RoundGoneIn(fullId, seconds) =>
publish(_ room RoomId(fullId.gameId), ClientIn.RoundGoneIn(fullId.playerId, seconds))
case RoundTourStanding(tourId, data) =>
publish(_ tourStanding tourId, ClientIn.roundTourStanding(data))
case o: TvSelect => Tv select o
case RoomStop(roomId) =>
History.round.stop(roomId)
publish(_ room roomId, ClientCtrl.Disconnect)
case RoundBotOnline(gameId, playerIndex, v) => roundCrowd.botOnline(gameId, playerIndex, v)
case GameStart(users) =>
users.foreach { u =>
friendList.startPlaying(u)
publish(_ userTv u, ClientIn.Resync)
}
case GameFinish(gameId, winner, playerScores, users) =>
users foreach friendList.stopPlaying
Fens.finish(gameId, winner, playerScores)
case Pong(pingAt) => Monitor.ping.record("round", pingAt)
case LilaBoot =>
logger.info("#################### LILA BOOT ####################")
lila.emit.round(LilaIn.RoomSetVersions(History.round.allVersions))
case VersioningReady =>
logger.info("#################### LILA VERSIONING READY ####################")
lila.status.setOnline()
Impersonations.reset()
case msg => roomHandler(msg)
})
}
private val racerHandler: Emit[LilaOut] = {
case RacerState(raceId, data) => publish(_ room RoomId(raceId), ClientIn.racerState(data))
case msg => roomHandler(msg)
}
private val roomHandler: Emit[LilaOut] = {
def tellVersion(roomId: RoomId, version: SocketVersion, troll: IsTroll, payload: JsonString) = {
val versioned = ClientIn.Versioned(payload, version, troll)
History.room.add(roomId, versioned)
publish(_ room roomId, versioned)
}
{
case TellRoomVersion(roomId, version, troll, payload) =>
tellVersion(roomId, version, troll, payload)
case TellRoomChat(roomId, version, troll, payload) =>
tellVersion(roomId, version, troll, payload)
publish(_ externalChat roomId, ClientIn.Payload(payload))
case TellRoom(roomId, payload) => publish(_ room roomId, ClientIn.Payload(payload))
case RoomStop(roomId) => History.room.stop(roomId)
case site: SiteOut => siteHandler(site)
case msg => logger.warn(s"Unhandled room: $msg")
}
}
private def roomBoot(
filter: Mongo => Mongo.IdFilter,
lilaIn: Emit[LilaIn.RoomSetVersions]
): Unit = {
val versions = History.room.allVersions
filter(mongo)(versions.map(_._1)) foreach { ids =>
lilaIn(LilaIn.RoomSetVersions(versions.filter(v => ids(v._1))))
}
}
lila.setHandlers({
case Lila.chans.round.out => roundHandler
case Lila.chans.site.out => siteHandler
case Lila.chans.lobby.out => lobbyHandler
case Lila.chans.tour.out => tourHandler
case Lila.chans.swiss.out => swissHandler
case Lila.chans.simul.out => simulHandler
case Lila.chans.study.out => studyHandler
case Lila.chans.team.out => teamHandler
case Lila.chans.challenge.out => roomHandler
case Lila.chans.racer.out => racerHandler
case chan => in => logger.warn(s"Unknown channel $chan sent $in")
})
}