package actors import actors.UserActor.{GetName, HostLeaveLobby, LobbyFatal, RefreshLobbyInfo, SecondPlayerLeaveLobby, SetUserAsHost, SetUserAsObs, SetUserAsSecondPlayer} import akka.actor._ import akka.event.LoggingReceive import akka.pattern.ask import akka.util.Timeout import com.typesafe.scalalogging.LazyLogging import play.api.libs.json._ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.duration.DurationInt import scala.util.{Failure, Success} class UserActor(out: ActorRef, userParentActor: ActorRef, lobbiesActor: ActorRef) extends Actor with LazyLogging { implicit val timeout: Timeout = 3.seconds var lobbieActor: Option[ActorRef] = None implicit val mapJson: Writes[DeciderMap] = new Writes[DeciderMap] { def writes(deciderMap: DeciderMap): JsValue = { Json.obj( "map" -> deciderMap.map, "isBanned" -> deciderMap.isBanned ) } } implicit val userInfoWrites: OWrites[UserInfo] = Json.writes[UserInfo] implicit val lobbyWrites: OWrites[LobbyInfo] = Json.writes[LobbyInfo] implicit val lobbyResponseWrites: Writes[List[LobbyInfo]] = new Writes[List[LobbyInfo]] { override def writes(o: List[LobbyInfo]): JsValue = { JsArray(o.map(lobby => Json.toJson(lobby))) } } var name = "" override def preStart(): Unit = { super.preStart() configureDefaultStocks() } def configureDefaultStocks(): Unit = { logger.info(s"Creating user actor") } override def receive: Receive = LoggingReceive { case GetName => sender ! name case SetUserAsHost(lobbyInfo) => val lobbyActor = sender() logger.info(s"Receive set user ${self.path.name} as host from ${lobbyActor.path.name}") setUserAsJoinedOrCreatedLobby(lobbyActor, lobbyInfo) case SetUserAsSecondPlayer(lobbyInfo) => val lobbyActor = sender() logger.info(s"Receive set user ${self.path.name} as second player from ${lobbyActor.path.name}") setUserAsJoinedOrCreatedLobby(lobbyActor, lobbyInfo) case SetUserAsObs(lobbyInfo) => val lobbyActor = sender() logger.info(s"Receive set user ${self.path.name} as second player from ${lobbyActor.path.name}") setUserAsJoinedOrCreatedLobby(lobbyActor, lobbyInfo) case HostLeaveLobby => logger.info(s"Host leave from lobby ${sender.path.name}") out ! Json.obj("type" -> "lobbyError", "error" -> "Host leave lobby") case SecondPlayerLeaveLobby => logger.info(s"Second player lobby ${sender.path.name}") out ! Json.obj("type" -> "lobbyError", "error" -> "Second player leave lobby") case RefreshLobbyInfo(lobbyInfo) => logger.trace(s"Refresh lobby info: $lobbyInfo") out ! Json.obj("type" -> "refreshLobby", "lobby" -> lobbyInfo) case LobbyFatal(message) => // После этого сообщения выход из лобби logger.warn(s"Lobby error: $message") out ! Json.obj("type" -> "lobbyError", "error" -> message) case json: JsValue => // Обрабатываем запросы с фронта val comType = (json \ "type").asOpt[String] comType match { case Some("userName") => name = (json \ "name").as[String] logger.debug(s"Set user name: $name for actor ${this.self}") case Some("getAllUsers") => val userActorsFuture = (userParentActor ? UserParentActor.GetAllUsers).mapTo[Iterable[ActorRef]] userActorsFuture.map(actorRefs => { logger.debug(s"There are ${actorRefs.size} users on site") actorRefs.map(userActorRef => userActorRef ? GetName).map(res => { res.onComplete { case Success(name) => logger.debug(s"There is $name on site") } }) }) case Some("createDecider") => lobbiesActor ! CreateLobby(name) case Some("leaveDecider") => lobbieActor.foreach(lobby => lobby ! LeaveLobby) case Some("setReady") => lobbieActor.foreach(lobby => lobby ! SetReady) case Some("setNotReady") => lobbieActor.foreach(lobby => lobby ! SetNotReady) case Some("kickSecondPlayer") => lobbieActor.foreach(lobby => lobby ! KickSecondPlayer) case Some("joinDecider") => val lobbyActorName = (json \ "lobbyActorName").as[String] logger.info(s"Player ${self.path.name} join lobby $lobbyActorName") lobbiesActor ! JoinLobbyByActorName(lobbyActorName, name) case Some("observerDecider") => val lobbyActorName = (json \ "lobbyActorName").as[String] logger.info(s"Player ${self.path.name} observe lobby $lobbyActorName") lobbiesActor ! ObserveLobbyByActorName(lobbyActorName) case Some("banMap") => val map = (json \ "map").as[String] lobbieActor.foreach(lobby => lobby ! BanMap(map)) case Some("getLobbies") => logger.debug("Get all lobby request") (lobbiesActor ? GetAllLobbies).mapTo[List[RefreshLobbyInfo]] onComplete { case Success(lobbies) => { logger.info(s"Received lobbies: $lobbies") out ! Json.obj("type" -> "lobbies", "lobbies" -> lobbies.map(res => res.lobbyInfo)) } case Failure(ex) => logger.error("Received error", ex) } } } private def setUserAsJoinedOrCreatedLobby(lobbyActor: ActorRef, lobbyInfo: LobbyInfo): Unit = { this.lobbieActor = Some(lobbyActor) out ! Json.obj("type" -> "switchToLobby", "lobby" -> lobbyInfo) } } class UserParentActor(actorSystem: ActorSystem) extends Actor with ActorLogging { import UserParentActor._ override def receive: Receive = LoggingReceive { case Create(id, out, lobbiesActor) => val child: ActorRef = actorSystem.actorOf(Props(classOf[UserActor], out, self, lobbiesActor), s"userActor-$id") sender() ! child case GetAllUsers => sender() ! context.children } } object UserParentActor { case class Create(id: String, out: ActorRef, lobbiesActor: ActorRef) case object GetAllUsers } object UserActor { trait Factory { // Corresponds to the @Assisted parameters defined in the constructor def apply(out: ActorRef): Actor } case object GetName case class RefreshLobbyInfo(lobbyInfo: LobbyInfo) case class SetUserAsHost(lobbyInfo: LobbyInfo) case class SetUserAsSecondPlayer(lobbyInfo: LobbyInfo) case class SetUserAsObs(lobbyInfo: LobbyInfo) case class LobbyFatal(message: String) case object CreateLobby case object HostLeaveLobby case object SecondPlayerLeaveLobby }