Implemented basic chat with akka-typed
This commit is contained in:
2
.idea/modules/root-build.iml
generated
2
.idea/modules/root-build.iml
generated
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module external.linked.project.id="root-build" external.linked.project.path="$MODULE_DIR$/../../project" external.root.project.path="$MODULE_DIR$/../.." external.system.id="SBT" sbt.imports="SUB:DOLLAR76b0f6bd323a78663921.`root`, _root_.sbt.Keys._, _root_.sbt._, _root_.sbt.plugins.IvyPlugin, _root_.sbt.plugins.JvmPlugin, _root_.sbt.plugins.CorePlugin, _root_.sbt.plugins.JUnitXmlReportPlugin, _root_.sbt.plugins.Giter8TemplatePlugin, _root_.sbtassembly.AssemblyPlugin, _root_.sbtassembly.AssemblyPlugin.autoImport._, _root_.scala.xml.{TopScope=>SUB:DOLLARscope}" sbt.resolvers="https://repo1.maven.org/maven2/|maven|public, file:/Users/pavelkachalouski/.sbt/preloaded/|maven|local-preloaded, /Users/pavelkachalouski/.ivy2/cache|ivy|Local cache" type="SBT_MODULE" version="4">
|
<module external.linked.project.id="root-build" external.linked.project.path="$MODULE_DIR$/../../project" external.root.project.path="$MODULE_DIR$/../.." external.system.id="SBT" sbt.imports="SUB:DOLLAR4d5286406012615efe32.`root`, _root_.sbt.Keys._, _root_.sbt._, _root_.sbt.plugins.IvyPlugin, _root_.sbt.plugins.JvmPlugin, _root_.sbt.plugins.CorePlugin, _root_.sbt.plugins.JUnitXmlReportPlugin, _root_.sbt.plugins.Giter8TemplatePlugin, _root_.sbtassembly.AssemblyPlugin, _root_.sbtassembly.AssemblyPlugin.autoImport._, _root_.scala.xml.{TopScope=>SUB:DOLLARscope}" sbt.resolvers="https://repo1.maven.org/maven2/|maven|public, file:/home/nnm/.sbt/preloaded/|maven|local-preloaded, /home/nnm/.ivy2/cache|ivy|Local cache" type="SBT_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<output url="file://$MODULE_DIR$/../../project/target/idea-classes" />
|
<output url="file://$MODULE_DIR$/../../project/target/idea-classes" />
|
||||||
<output-test url="file://$MODULE_DIR$/../../project/target/idea-test-classes" />
|
<output-test url="file://$MODULE_DIR$/../../project/target/idea-test-classes" />
|
||||||
|
|||||||
1
.idea/modules/root.iml
generated
1
.idea/modules/root.iml
generated
@@ -6,7 +6,6 @@
|
|||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$/../..">
|
<content url="file://$MODULE_DIR$/../..">
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../src/main/scala" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/../../src/main/scala" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../src/test/scala" isTestSource="true" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../target/scala-2.12/src_managed/main" isTestSource="false" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/../../target/scala-2.12/src_managed/main" isTestSource="false" generated="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../target/scala-2.12/src_managed/test" isTestSource="true" generated="true" />
|
<sourceFolder url="file://$MODULE_DIR$/../../target/scala-2.12/src_managed/test" isTestSource="true" generated="true" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/../../src/main/resources" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/../../src/main/resources" type="java-resource" />
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import java.io.InputStream
|
|||||||
import java.security.{KeyStore, SecureRandom}
|
import java.security.{KeyStore, SecureRandom}
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
import akka.actor.{ActorSystem, Props}
|
import akka.actor
|
||||||
|
import akka.actor.Scheduler
|
||||||
|
import akka.actor.typed.scaladsl.adapter._
|
||||||
|
import akka.actor.typed.{ActorSystem, DispatcherSelector}
|
||||||
import akka.http.scaladsl.marshalling.Marshal
|
import akka.http.scaladsl.marshalling.Marshal
|
||||||
import akka.http.scaladsl.model._
|
import akka.http.scaladsl.model._
|
||||||
import akka.http.scaladsl.server.Directives._
|
import akka.http.scaladsl.server.Directives._
|
||||||
@@ -12,24 +15,28 @@ import akka.http.scaladsl.server.{Route, RouteResult}
|
|||||||
import akka.http.scaladsl.unmarshalling.Unmarshal
|
import akka.http.scaladsl.unmarshalling.Unmarshal
|
||||||
import akka.http.scaladsl.{ConnectionContext, Http, HttpExt, HttpsConnectionContext}
|
import akka.http.scaladsl.{ConnectionContext, Http, HttpExt, HttpsConnectionContext}
|
||||||
import akka.stream.ActorMaterializer
|
import akka.stream.ActorMaterializer
|
||||||
import akka.util.ByteString
|
import akka.util.{ByteString, Timeout}
|
||||||
import eu.xeppaka.bot1.actors.UpdateActor2
|
import eu.xeppaka.bot1.actors.UpdateActor
|
||||||
import eu.xeppaka.bot1.actors.UpdateActor2.ReceivedUpdate
|
import eu.xeppaka.bot1.actors.UpdateActor.UpdateResponse
|
||||||
import javax.net.ssl.{KeyManagerFactory, SSLContext, TrustManagerFactory}
|
import javax.net.ssl.{KeyManagerFactory, SSLContext, TrustManagerFactory}
|
||||||
|
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import scala.concurrent.{ExecutionContextExecutor, Future}
|
import scala.concurrent.{ExecutionContextExecutor, Future}
|
||||||
import scala.io.{Source, StdIn}
|
import scala.io.{Source, StdIn}
|
||||||
|
import scala.util.{Failure, Success}
|
||||||
|
|
||||||
|
class TelegramBotServer(botId: String, port: Int, httpsContext: Option[HttpsConnectionContext]) {
|
||||||
|
|
||||||
class TelegramBotServer(botId: String, port: Int, httpsContext: Option[HttpsConnectionContext])(implicit val actorSystem: ActorSystem) {
|
|
||||||
import FailFastCirceSupport._
|
import FailFastCirceSupport._
|
||||||
import io.circe.generic.auto._
|
|
||||||
import eu.xeppaka.bot1.TelegramEntities._
|
import eu.xeppaka.bot1.TelegramEntities._
|
||||||
|
import io.circe.generic.auto._
|
||||||
|
|
||||||
private val botUri = BotUri(botId)
|
private val botUri = BotUri(botId)
|
||||||
|
private implicit val updateSystem: ActorSystem[UpdateActor.UpdateCommand] = ActorSystem(UpdateActor.behavior, "telegram-bot")
|
||||||
|
private implicit val actorSystem: actor.ActorSystem = updateSystem.toUntyped
|
||||||
private implicit val materializer: ActorMaterializer = ActorMaterializer()
|
private implicit val materializer: ActorMaterializer = ActorMaterializer()
|
||||||
private implicit val executionContext: ExecutionContextExecutor = actorSystem.dispatcher
|
private implicit val executionContext: ExecutionContextExecutor = updateSystem.dispatchers.lookup(DispatcherSelector.default())
|
||||||
|
|
||||||
private val http: HttpExt = Http()
|
private val http: HttpExt = Http()
|
||||||
private val hookId = UUID.randomUUID().toString
|
private val hookId = UUID.randomUUID().toString
|
||||||
@@ -38,15 +45,16 @@ class TelegramBotServer(botId: String, port: Int, httpsContext: Option[HttpsConn
|
|||||||
"pkcloud",
|
"pkcloud",
|
||||||
port,
|
port,
|
||||||
connectionContext = httpsContext.getOrElse(http.defaultClientHttpsContext))
|
connectionContext = httpsContext.getOrElse(http.defaultClientHttpsContext))
|
||||||
private val updateActor = actorSystem.actorOf(UpdateActor2.props(botUri, http))
|
|
||||||
|
|
||||||
println(s"webhook path: $webhookUri")
|
println(s"Webhook path: $webhookUri")
|
||||||
|
setWebhook()
|
||||||
|
|
||||||
def stop(): Unit = {
|
def stop(): Unit = {
|
||||||
bindingFuture
|
bindingFuture
|
||||||
.andThen { case _ => http.shutdownAllConnectionPools() }
|
.flatMap(binding => deleteWebhook().map(_ => binding))
|
||||||
.flatMap(_.unbind())
|
.flatMap(binding => http.shutdownAllConnectionPools().map(_ => binding))
|
||||||
.onComplete(_ => actorSystem.terminate())
|
.flatMap(binding => binding.unbind())
|
||||||
|
.onComplete(_ => updateSystem.terminate())
|
||||||
}
|
}
|
||||||
|
|
||||||
def printRequestMethodAndResponseStatus(req: HttpRequest)(res: RouteResult): Unit = {
|
def printRequestMethodAndResponseStatus(req: HttpRequest)(res: RouteResult): Unit = {
|
||||||
@@ -58,22 +66,44 @@ class TelegramBotServer(botId: String, port: Int, httpsContext: Option[HttpsConn
|
|||||||
path(hookId) {
|
path(hookId) {
|
||||||
post {
|
post {
|
||||||
entity(as[Update]) { update =>
|
entity(as[Update]) { update =>
|
||||||
handleWith(processUpdate)
|
handleWith(receivedUpdate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def processUpdate(update: Update): HttpResponse = {
|
private def receivedUpdate(update: Update): Future[HttpResponse] = {
|
||||||
updateActor ! ReceivedUpdate(update)
|
import akka.actor.typed.scaladsl.AskPattern._
|
||||||
HttpResponse()
|
|
||||||
|
implicit val timeout: Timeout = 3.seconds
|
||||||
|
implicit val scheduler: Scheduler = updateSystem.scheduler
|
||||||
|
|
||||||
|
val result: Future[UpdateActor.UpdateResponse] = updateSystem ? (ref => UpdateActor.UpdateReceived(update, ref))
|
||||||
|
|
||||||
|
result.andThen {
|
||||||
|
case Success(response) => sendResponse(response.chatId, response.text)
|
||||||
|
case Failure(ex) => println("Failed to process message...")
|
||||||
|
}
|
||||||
|
|
||||||
|
result.map(res => HttpResponse()).fallbackTo(Future.successful(HttpResponse()))
|
||||||
|
}
|
||||||
|
|
||||||
|
private def sendResponse(chatId: Long, text: String) = {
|
||||||
|
import io.circe._, io.circe.generic.auto._, io.circe.syntax._
|
||||||
|
|
||||||
|
val sendMessage = SendMessage(chatId, text)
|
||||||
|
val printer = Printer.noSpaces.copy(dropNullValues = true)
|
||||||
|
val json = printer.pretty(sendMessage.asJson)
|
||||||
|
val request = HttpRequest(HttpMethods.POST, uri = botUri.sendMessage, entity = HttpEntity.Strict(ContentTypes.`application/json`, ByteString(json)))
|
||||||
|
http.singleRequest(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
def getBotInfo: Future[Response[GetMe]] = {
|
def getBotInfo: Future[Response[GetMe]] = {
|
||||||
http.singleRequest(HttpRequest(uri = botUri.getMe)).flatMap(Unmarshal(_).to[Response[GetMe]])
|
http.singleRequest(HttpRequest(uri = botUri.getMe)).flatMap(Unmarshal(_).to[Response[GetMe]])
|
||||||
}
|
}
|
||||||
|
|
||||||
def setWebhook(): Future[HttpResponse] = {
|
private def setWebhook(): Future[HttpResponse] = {
|
||||||
|
print("Setting webhook...")
|
||||||
val urlEntity = HttpEntity.Strict(ContentTypes.`text/plain(UTF-8)`, ByteString(webhookUri.toString()))
|
val urlEntity = HttpEntity.Strict(ContentTypes.`text/plain(UTF-8)`, ByteString(webhookUri.toString()))
|
||||||
val urlPart = Multipart.FormData.BodyPart.Strict("url", urlEntity)
|
val urlPart = Multipart.FormData.BodyPart.Strict("url", urlEntity)
|
||||||
|
|
||||||
@@ -86,13 +116,20 @@ class TelegramBotServer(botId: String, port: Int, httpsContext: Option[HttpsConn
|
|||||||
Marshal(setWebhookFormData)
|
Marshal(setWebhookFormData)
|
||||||
.to[RequestEntity]
|
.to[RequestEntity]
|
||||||
.flatMap(requestEntity => http.singleRequest(HttpRequest(uri = botUri.setWebhook, method = HttpMethods.POST, entity = requestEntity)))
|
.flatMap(requestEntity => http.singleRequest(HttpRequest(uri = botUri.setWebhook, method = HttpMethods.POST, entity = requestEntity)))
|
||||||
// .flatMap(Unmarshal(_).to[Response[String]])
|
.andThen {
|
||||||
|
case Success(response) => println(s" ${response.status.value}")
|
||||||
|
case Failure(exception) => println(s" failed with exception: ${exception.getMessage}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def deleteWebhook(): Future[Response[String]] = {
|
private def deleteWebhook(): Future[HttpResponse] = {
|
||||||
|
print("Deleting webhook...")
|
||||||
http
|
http
|
||||||
.singleRequest(HttpRequest(uri = botUri.deleteWebhook, method = HttpMethods.POST))
|
.singleRequest(HttpRequest(uri = botUri.deleteWebhook, method = HttpMethods.POST))
|
||||||
.flatMap(Unmarshal(_).to[Response[String]])
|
.andThen {
|
||||||
|
case Success(response) => println(s" ${response.status.value}")
|
||||||
|
case Failure(exception) => println(s" failed with exception: ${exception.getMessage}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getWebhookInfo(): Future[Response[WebhookInfo]] = {
|
def getWebhookInfo(): Future[Response[WebhookInfo]] = {
|
||||||
@@ -105,32 +142,14 @@ class TelegramBotServer(botId: String, port: Int, httpsContext: Option[HttpsConn
|
|||||||
object TelegramBotServer {
|
object TelegramBotServer {
|
||||||
private val botId = "570855144:AAEv7b817cuq2JJI9f2kG5B9G3zW1x-btz4"
|
private val botId = "570855144:AAEv7b817cuq2JJI9f2kG5B9G3zW1x-btz4"
|
||||||
|
|
||||||
def apply(port: Int, httpsContext: Option[HttpsConnectionContext])(implicit actorSystem: ActorSystem): TelegramBotServer = new TelegramBotServer(botId, port, httpsContext)(actorSystem)
|
def apply(port: Int, httpsContext: Option[HttpsConnectionContext]): TelegramBotServer = new TelegramBotServer(botId, port, httpsContext)
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
val httpsContext = createHttpsConnectionContext
|
val httpsContext = createHttpsConnectionContext
|
||||||
|
|
||||||
implicit val actorSystem: ActorSystem = ActorSystem("telegram-bot")
|
|
||||||
implicit val materializer: ActorMaterializer = ActorMaterializer()
|
|
||||||
implicit val executionContext: ExecutionContextExecutor = actorSystem.dispatcher
|
|
||||||
|
|
||||||
val tbs = TelegramBotServer(88, Some(createHttpsConnectionContext))
|
val tbs = TelegramBotServer(88, Some(createHttpsConnectionContext))
|
||||||
|
|
||||||
tbs.setWebhook()
|
|
||||||
.flatMap(response => response.entity.toStrict(5 seconds))
|
|
||||||
.onComplete(entity => {
|
|
||||||
println(entity.get.data.utf8String)
|
|
||||||
entity.get.discardBytes()
|
|
||||||
})
|
|
||||||
|
|
||||||
// tbs
|
|
||||||
// .getWebhookInfo()
|
|
||||||
// .onComplete(println(_))
|
|
||||||
|
|
||||||
StdIn.readLine()
|
StdIn.readLine()
|
||||||
|
tbs.stop()
|
||||||
tbs.deleteWebhook()
|
|
||||||
.onComplete(r => tbs.stop())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def createHttpsConnectionContext: HttpsConnectionContext = {
|
def createHttpsConnectionContext: HttpsConnectionContext = {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ object TelegramEntities {
|
|||||||
username: Option[String] = None,
|
username: Option[String] = None,
|
||||||
language_code: Option[String] = None)
|
language_code: Option[String] = None)
|
||||||
|
|
||||||
case class SendMessage(chat_id: Int,
|
case class SendMessage(chat_id: Long,
|
||||||
text: String,
|
text: String,
|
||||||
parse_mode: Option[String] = None,
|
parse_mode: Option[String] = None,
|
||||||
disable_web_page_preview: Option[Boolean] = None,
|
disable_web_page_preview: Option[Boolean] = None,
|
||||||
@@ -171,7 +171,7 @@ object TelegramEntities {
|
|||||||
|
|
||||||
case class ChatPhoto(small_file_id: String, big_file_id: String)
|
case class ChatPhoto(small_file_id: String, big_file_id: String)
|
||||||
|
|
||||||
case class Chat(id: Int,
|
case class Chat(id: Long,
|
||||||
`type`: String,
|
`type`: String,
|
||||||
title: Option[String] = None,
|
title: Option[String] = None,
|
||||||
username: Option[String] = None,
|
username: Option[String] = None,
|
||||||
|
|||||||
54
src/main/scala/eu/xeppaka/bot1/actors/ChatActor.scala
Normal file
54
src/main/scala/eu/xeppaka/bot1/actors/ChatActor.scala
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package eu.xeppaka.bot1.actors
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.{ActorRef, Behavior}
|
||||||
|
|
||||||
|
object ChatActor {
|
||||||
|
|
||||||
|
sealed trait ChatCommand {
|
||||||
|
def replyTo: ActorRef[Response]
|
||||||
|
}
|
||||||
|
|
||||||
|
case class Response(text: String)
|
||||||
|
|
||||||
|
case class Help(replyTo: ActorRef[Response]) extends ChatCommand
|
||||||
|
|
||||||
|
case class Start(replyTo: ActorRef[Response]) extends ChatCommand
|
||||||
|
|
||||||
|
case class MessageReceived(text: String, replyTo: ActorRef[Response]) extends ChatCommand
|
||||||
|
|
||||||
|
case class Stop(replyTo: ActorRef[Response]) extends ChatCommand
|
||||||
|
|
||||||
|
private val started: Behavior[ChatCommand] = Behaviors.receive { (ctx, msg) =>
|
||||||
|
msg match {
|
||||||
|
case MessageReceived(text, replyTo) =>
|
||||||
|
replyTo ! Response(s"Ok, you said: $text")
|
||||||
|
Behaviors.same
|
||||||
|
case Help(replyTo) =>
|
||||||
|
replyHelp(replyTo)
|
||||||
|
Behaviors.same
|
||||||
|
case Stop(replyTo) =>
|
||||||
|
replyTo ! Response("Bye, bye!")
|
||||||
|
initial
|
||||||
|
case _ =>
|
||||||
|
Behaviors.unhandled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val initial: Behavior[ChatCommand] = Behaviors.receive { (ctx, msg) =>
|
||||||
|
msg match {
|
||||||
|
case Start(replyTo) =>
|
||||||
|
replyTo ! Response("You started. Try /help, motherfucker...")
|
||||||
|
started
|
||||||
|
case c: ChatCommand =>
|
||||||
|
c.replyTo ! Response("Only /start command is supported. Try it...")
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def replyHelp(replyTo: ActorRef[Response]): Unit = {
|
||||||
|
replyTo ! Response("No help is provided for such motherfuckers like you! But... ok, send /stop and we are free.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val behavior: Behavior[ChatCommand] = initial
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package eu.xeppaka.bot1.actors
|
|
||||||
|
|
||||||
import java.util.UUID
|
|
||||||
|
|
||||||
import akka.actor.Actor
|
|
||||||
|
|
||||||
class DialogActor extends Actor {
|
|
||||||
private val dialogId = UUID.randomUUID()
|
|
||||||
private var userId: Option[Int] = None
|
|
||||||
|
|
||||||
override def receive: Receive = {
|
|
||||||
case 1 =>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object DialogActor {
|
|
||||||
case class Start()
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,78 @@
|
|||||||
package eu.xeppaka.bot1.actors
|
package eu.xeppaka.bot1.actors
|
||||||
|
|
||||||
|
import akka.NotUsed
|
||||||
|
import akka.actor.typed.receptionist.Receptionist.Find
|
||||||
|
import akka.actor.typed.receptionist.{Receptionist, ServiceKey}
|
||||||
|
import akka.actor.typed.scaladsl.{ActorContext, Behaviors}
|
||||||
|
import akka.actor.typed.{ActorRef, Behavior}
|
||||||
import eu.xeppaka.bot1.TelegramEntities
|
import eu.xeppaka.bot1.TelegramEntities
|
||||||
|
import eu.xeppaka.bot1.actors.ChatActor.{Help, MessageReceived, Start, Stop}
|
||||||
|
|
||||||
object UpdateActor {
|
object UpdateActor {
|
||||||
final case class ProcessUpdate(update: TelegramEntities.Update)
|
object BotMessages {
|
||||||
|
val start = "/start"
|
||||||
|
val stop = "/stop"
|
||||||
|
val help = "/help"
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait UpdateCommand
|
||||||
|
case class UpdateReceived(update: TelegramEntities.Update, replyTo: ActorRef[UpdateResponse]) extends UpdateCommand
|
||||||
|
case class UpdateResponse(chatId: Long, text: String)
|
||||||
|
|
||||||
|
val behavior: Behavior[UpdateCommand] = Behaviors.receive[UpdateCommand] { (ctx, msg) =>
|
||||||
|
msg match {
|
||||||
|
case UpdateReceived(receivedUpdate, replyTo) =>
|
||||||
|
if (receivedUpdate.message.isDefined) {
|
||||||
|
ctx.spawn(processMessage(ctx, receivedUpdate.message.get, replyTo), s"process-update-${receivedUpdate.update_id}")
|
||||||
|
}
|
||||||
|
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private def processMessage(parentContext: ActorContext[UpdateCommand], message: TelegramEntities.Message, replyTo: ActorRef[UpdateResponse]): Behavior[NotUsed] = {
|
||||||
|
Behaviors.setup[AnyRef] { ctx =>
|
||||||
|
val chatId = message.chat.id
|
||||||
|
val chatKey = ServiceKey[ChatActor.ChatCommand](chatId.toString)
|
||||||
|
|
||||||
|
println(s"Sending Find to receptionist to find actor with id: $chatId")
|
||||||
|
|
||||||
|
ctx.system.receptionist ! Find(chatKey, ctx.self.narrow[Receptionist.Listing])
|
||||||
|
|
||||||
|
Behaviors.receive[AnyRef] { (ctx, msg) =>
|
||||||
|
msg match {
|
||||||
|
case chatKey.Listing(listing) =>
|
||||||
|
if (listing.isEmpty) {
|
||||||
|
println(s"Actor with id: $chatId not found")
|
||||||
|
} else {
|
||||||
|
println(s"Actor with id: $chatId is found")
|
||||||
|
}
|
||||||
|
|
||||||
|
val chat = listing.headOption
|
||||||
|
.getOrElse({
|
||||||
|
val chatActor = parentContext.spawn(ChatActor.behavior, chatId.toString)
|
||||||
|
ctx.system.receptionist ! Receptionist.Register(chatKey, chatActor)
|
||||||
|
chatActor
|
||||||
|
})
|
||||||
|
|
||||||
|
chat ! getChatMessage(message, ctx.self.narrow[ChatActor.Response])
|
||||||
|
Behaviors.same
|
||||||
|
case ChatActor.Response(text) =>
|
||||||
|
replyTo ! UpdateResponse(chatId, text)
|
||||||
|
Behaviors.stopped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.narrow[NotUsed]
|
||||||
|
|
||||||
|
private def getChatMessage(message: TelegramEntities.Message, replyTo: ActorRef[ChatActor.Response]): ChatActor.ChatCommand = {
|
||||||
|
import BotMessages._
|
||||||
|
|
||||||
|
message.text.getOrElse(help) match {
|
||||||
|
case `start` => Start(replyTo)
|
||||||
|
case `stop` => Stop(replyTo)
|
||||||
|
case `help` => Help(replyTo)
|
||||||
|
case msgText@_ => MessageReceived(msgText, replyTo)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user