mirror of
https://github.com/dyrkin/luxmed-bot.git
synced 2025-12-25 23:03:43 +01:00
Refactoring. Moved some functions. Router is a conversation now, not an actor
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
package com.lbs.server
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem}
|
||||
import akka.actor.ActorSystem
|
||||
import com.lbs.api.json.model.{AvailableVisitsTermPresentation, HistoricVisit, ReservedVisit}
|
||||
import com.lbs.bot.Bot
|
||||
import com.lbs.bot.telegram.TelegramBot
|
||||
@@ -162,7 +162,7 @@ class BootConfig {
|
||||
Some("cancel"), localization, originator)(actorSystem)
|
||||
|
||||
@Bean
|
||||
def router: ActorRef = actorSystem.actorOf(Router.props(authFactory))
|
||||
def router: Router = new Router(authFactory)(actorSystem)
|
||||
|
||||
@Bean
|
||||
def telegram: TelegramBot = new TelegramBot(router ! _, telegramBotToken)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
*/
|
||||
package com.lbs.server.conversation
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem}
|
||||
import akka.actor.ActorSystem
|
||||
import com.lbs.bot.model.Button
|
||||
import com.lbs.bot.{Bot, _}
|
||||
import com.lbs.server.conversation.Account._
|
||||
@@ -33,7 +33,7 @@ import com.lbs.server.lang.{Localizable, Localization}
|
||||
import com.lbs.server.service.DataService
|
||||
import com.lbs.server.util.MessageExtractors.CallbackCommand
|
||||
|
||||
class Account(val userId: UserId, bot: Bot, dataService: DataService, val localization: Localization, router: ActorRef)(val actorSystem: ActorSystem) extends Conversation[Unit] with Localizable {
|
||||
class Account(val userId: UserId, bot: Bot, dataService: DataService, val localization: Localization, router: Router)(val actorSystem: ActorSystem) extends Conversation[Unit] with Localizable {
|
||||
|
||||
entryPoint(askAction)
|
||||
|
||||
@@ -49,32 +49,33 @@ class Account(val userId: UserId, bot: Bot, dataService: DataService, val locali
|
||||
action match {
|
||||
case -1L =>
|
||||
router ! cmd.copy(message = cmd.message.copy(text = Some("/login")))
|
||||
stay()
|
||||
case -2L =>
|
||||
bot.sendMessage(userId.source, "Not implemented yet")
|
||||
stay()
|
||||
case accountId =>
|
||||
val accountMaybe = dataService.findUserCredentialsByAccountId(userId.userId, accountId)
|
||||
accountMaybe match {
|
||||
case Some(account) => //account was found
|
||||
val userMaybe = dataService.findUser(userId.userId)
|
||||
userMaybe.foreach { user =>
|
||||
user.activeAccountId = accountId
|
||||
dataService.saveUser(user)
|
||||
router ! SwitchUser(UserId(account.userId, account.accountId, userId.source))
|
||||
bot.sendMessage(userId.source, lang.accountSwitched(account.username))
|
||||
}
|
||||
stay()
|
||||
case None =>
|
||||
error(s"This is not user [#${userId.userId}] account [#$accountId]")
|
||||
stay()
|
||||
}
|
||||
switchAccount(accountId)
|
||||
}
|
||||
end()
|
||||
}
|
||||
|
||||
private def switchAccount(accountId: Long): Unit = {
|
||||
val accountMaybe = dataService.findUserCredentialsByAccountId(userId.userId, accountId)
|
||||
accountMaybe match {
|
||||
case Some(account) =>
|
||||
val userMaybe = dataService.findUser(userId.userId)
|
||||
userMaybe.foreach { user =>
|
||||
user.activeAccountId = accountId
|
||||
dataService.saveUser(user)
|
||||
router ! SwitchAccount(UserId(account.userId, account.accountId, userId.source))
|
||||
bot.sendMessage(userId.source, lang.accountSwitched(account.username))
|
||||
}
|
||||
case None =>
|
||||
error(s"This is not user [#${userId.userId}] account [#$accountId]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object Account {
|
||||
|
||||
case class SwitchUser(userId: UserId)
|
||||
case class SwitchAccount(userId: UserId)
|
||||
|
||||
}
|
||||
@@ -50,64 +50,72 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
|
||||
|
||||
entryPoint(helpChat)
|
||||
|
||||
private def helpChat: Step = dialogue(help) {
|
||||
case Msg(cmd@TextCommand("/help"), _) =>
|
||||
help ! cmd
|
||||
stay()
|
||||
case Msg(cmd@TextCommand("/start"), _) =>
|
||||
help ! cmd
|
||||
stay()
|
||||
}
|
||||
private def helpChat: Step =
|
||||
dialogue(help) {
|
||||
case Msg(cmd@TextCommand("/help"), _) =>
|
||||
help ! cmd
|
||||
stay()
|
||||
case Msg(cmd@TextCommand("/start"), _) =>
|
||||
help ! cmd
|
||||
stay()
|
||||
}
|
||||
|
||||
private def bookChat: Step = dialogue(book) {
|
||||
case Msg(TextCommand("/book"), _) =>
|
||||
book.restart()
|
||||
stay()
|
||||
}
|
||||
private def bookChat: Step =
|
||||
dialogue(book) {
|
||||
case Msg(TextCommand("/book"), _) =>
|
||||
book.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def historyChat: Step = dialogue(history) {
|
||||
case Msg(TextCommand("/history"), _) =>
|
||||
history.restart()
|
||||
stay()
|
||||
}
|
||||
private def historyChat: Step =
|
||||
dialogue(history) {
|
||||
case Msg(TextCommand("/history"), _) =>
|
||||
history.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def visitsChat: Step = dialogue(visits) {
|
||||
case Msg(TextCommand("/reserved"), _) =>
|
||||
visits.restart()
|
||||
stay()
|
||||
}
|
||||
private def visitsChat: Step =
|
||||
dialogue(visits) {
|
||||
case Msg(TextCommand("/reserved"), _) =>
|
||||
visits.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def bugChat: Step = dialogue(bug) {
|
||||
case Msg(TextCommand("/bug"), _) =>
|
||||
bug.restart()
|
||||
stay()
|
||||
}
|
||||
private def bugChat: Step =
|
||||
dialogue(bug) {
|
||||
case Msg(TextCommand("/bug"), _) =>
|
||||
bug.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def monitoringsChat: Step = dialogue(monitorings) {
|
||||
case Msg(TextCommand("/monitorings"), _) =>
|
||||
monitorings.restart()
|
||||
stay()
|
||||
}
|
||||
private def monitoringsChat: Step =
|
||||
dialogue(monitorings) {
|
||||
case Msg(TextCommand("/monitorings"), _) =>
|
||||
monitorings.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def settingsChat: Step = dialogue(settings) {
|
||||
case Msg(TextCommand("/settings"), _) =>
|
||||
settings.restart()
|
||||
stay()
|
||||
}
|
||||
private def settingsChat: Step =
|
||||
dialogue(settings) {
|
||||
case Msg(TextCommand("/settings"), _) =>
|
||||
settings.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def accountChat: Step = dialogue(account) {
|
||||
case Msg(TextCommand("/accounts"), _) =>
|
||||
account.restart()
|
||||
stay()
|
||||
}
|
||||
private def accountChat: Step =
|
||||
dialogue(account) {
|
||||
case Msg(TextCommand("/accounts"), _) =>
|
||||
account.restart()
|
||||
stay()
|
||||
}
|
||||
|
||||
private def dialogue(interactional: Interactional)(mainStateFunction: MessageProcessorFn): Step =
|
||||
private def dialogue(interactional: Interactional)(mainMessageProcessor: MessageProcessorFn): Step =
|
||||
monologue {
|
||||
case event: Msg =>
|
||||
if (mainStateFunction.isDefinedAt(event)) mainStateFunction(event)
|
||||
if (mainMessageProcessor.isDefinedAt(event)) mainMessageProcessor(event)
|
||||
else {
|
||||
val secondaryStateFunction = secondaryState(interactional)
|
||||
secondaryStateFunction(event)
|
||||
val defaultMessageProcessor = secondaryState(interactional)
|
||||
defaultMessageProcessor(event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +147,7 @@ class Chat(val userId: UserId, dataService: DataService, monitoringService: Moni
|
||||
case Msg(cmd@TextCommand("/accounts"), _) =>
|
||||
self ! cmd
|
||||
goto(accountChat)
|
||||
case Msg(cmd@TextCommand(MonitoringId(monitoringIdStr, scheduleIdStr, timeStr)), _) =>
|
||||
case Msg(TextCommand(MonitoringId(monitoringIdStr, scheduleIdStr, timeStr)), _) =>
|
||||
val monitoringId = monitoringIdStr.toLong
|
||||
val scheduleId = scheduleIdStr.toLong
|
||||
val time = timeStr.toLong
|
||||
|
||||
@@ -23,17 +23,19 @@
|
||||
*/
|
||||
package com.lbs.server.conversation
|
||||
|
||||
import akka.actor.{Actor, Cancellable, Props}
|
||||
import akka.actor.{ActorSystem, Cancellable}
|
||||
import com.lbs.bot.model.{Command, MessageSource}
|
||||
import com.lbs.common.Logger
|
||||
import com.lbs.server.conversation.Account.SwitchUser
|
||||
import com.lbs.server.conversation.Router.DestroyChat
|
||||
import com.lbs.server.conversation.Account.SwitchAccount
|
||||
import com.lbs.server.conversation.base.Conversation
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.ExecutionContextExecutor
|
||||
import scala.concurrent.duration.DurationLong
|
||||
|
||||
class Router(authFactory: MessageSourceTo[Auth]) extends Actor with Logger {
|
||||
class Router(authFactory: MessageSourceTo[Auth])(val actorSystem: ActorSystem) extends Conversation[Unit] with Logger {
|
||||
|
||||
private case class DestroyChat(source: MessageSource)
|
||||
|
||||
private val chats = mutable.Map.empty[MessageSource, Auth]
|
||||
|
||||
@@ -41,38 +43,41 @@ class Router(authFactory: MessageSourceTo[Auth]) extends Actor with Logger {
|
||||
|
||||
private val idleTimeout = 1.hour
|
||||
|
||||
private implicit val dispatcher: ExecutionContextExecutor = context.system.dispatcher
|
||||
private implicit val dispatcher: ExecutionContextExecutor = actorSystem.dispatcher
|
||||
|
||||
override def receive: Receive = {
|
||||
case cmd@Command(source, _, _) =>
|
||||
scheduleIdleChatDestroyer(source)
|
||||
val chat = chats.get(source) match {
|
||||
case Some(actor) => actor
|
||||
case None => addNewChat(source)
|
||||
}
|
||||
chat ! cmd
|
||||
case DestroyChat(source) =>
|
||||
destroyChat(source)
|
||||
case SwitchUser(userId) =>
|
||||
switchUser(userId)
|
||||
case what => info(s"Unknown message: $what")
|
||||
}
|
||||
entryPoint(routeMessage)
|
||||
|
||||
private def addNewChat(source: MessageSource): Auth = {
|
||||
val actor = authFactory(source)
|
||||
chats += source -> actor
|
||||
actor
|
||||
private def routeMessage: Step =
|
||||
monologue {
|
||||
case Msg(cmd@Command(source, _, _), _) =>
|
||||
val chat = instantiateChatOrGet(source)
|
||||
chat ! cmd
|
||||
stay()
|
||||
case Msg(DestroyChat(source), _) =>
|
||||
info(s"Destroying chat for $source due to $idleTimeout of inactivity")
|
||||
destroyChat(source)
|
||||
stay()
|
||||
case Msg(SwitchAccount(userId), _) =>
|
||||
switchAccount(userId)
|
||||
stay()
|
||||
case msg: Msg =>
|
||||
info(s"Unknown message received: $msg")
|
||||
stay()
|
||||
}
|
||||
|
||||
private def instantiateChatOrGet(source: MessageSource) = {
|
||||
scheduleIdleChatDestroyer(source)
|
||||
chats.getOrElseUpdate(source, authFactory(source))
|
||||
}
|
||||
|
||||
private def destroyChat(source: MessageSource): Unit = {
|
||||
info(s"Destroying chat for $source due to $idleTimeout of inactivity")
|
||||
timers.remove(source)
|
||||
removeChat(source)
|
||||
}
|
||||
|
||||
private def switchUser(userId: Login.UserId): Unit = {
|
||||
private def switchAccount(userId: Login.UserId): Unit = {
|
||||
removeChat(userId.source)
|
||||
addNewChat(userId.source)
|
||||
chats += userId.source -> authFactory(userId.source)
|
||||
}
|
||||
|
||||
private def removeChat(source: MessageSource): Unit = {
|
||||
@@ -81,20 +86,13 @@ class Router(authFactory: MessageSourceTo[Auth]) extends Actor with Logger {
|
||||
|
||||
private def scheduleIdleChatDestroyer(source: MessageSource): Unit = {
|
||||
timers.remove(source).foreach(_.cancel())
|
||||
val cancellable = context.system.scheduler.scheduleOnce(idleTimeout) {
|
||||
val cancellable = actorSystem.scheduler.scheduleOnce(idleTimeout) {
|
||||
self ! DestroyChat(source)
|
||||
}
|
||||
timers += source -> cancellable
|
||||
}
|
||||
|
||||
override def postStop(): Unit = {
|
||||
chats.foreach(chat => removeChat(chat._1))
|
||||
beforeDestroy {
|
||||
chats.foreach(chat => destroyChat(chat._1))
|
||||
}
|
||||
}
|
||||
|
||||
object Router {
|
||||
def props(authFactory: MessageSourceTo[Auth]) = Props(new Router(authFactory))
|
||||
|
||||
case class DestroyChat(source: MessageSource)
|
||||
|
||||
}
|
||||
@@ -15,14 +15,14 @@ trait Interactional extends Logger {
|
||||
|
||||
protected def actorSystem: ActorSystem
|
||||
|
||||
protected val self: Interactional = this
|
||||
|
||||
private[base] def initializeConversation(): Unit
|
||||
|
||||
private[base] def executeCurrentStep(): Unit
|
||||
|
||||
private[base] def makeStepTransition(any: Any): Unit
|
||||
|
||||
protected val self: Interactional = this
|
||||
|
||||
private var onDestroy: () => Unit = () => {}
|
||||
|
||||
private def actorCreator: Actor = new Actor {
|
||||
|
||||
Reference in New Issue
Block a user