-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
724 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ | |
target | ||
project/target | ||
.bsp | ||
secret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.github.mmvpm.bot | ||
|
||
import cats.effect.{IO, IOApp} | ||
import com.github.mmvpm.bot.model.MessageID | ||
import com.github.mmvpm.bot.render.RendererImpl | ||
import com.github.mmvpm.bot.state.{State, StateManagerImpl, StorageImpl} | ||
import com.github.mmvpm.bot.util.ResourceUtils | ||
import org.asynchttpclient.Dsl.asyncHttpClient | ||
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend | ||
|
||
object Main extends IOApp.Simple { | ||
|
||
override def run: IO[Unit] = | ||
for { | ||
_ <- IO.println("Starting telegram bot...") | ||
|
||
token = ResourceUtils.readTelegramToken() | ||
sttpBackend = AsyncHttpClientCatsBackend.usingClient[IO](asyncHttpClient) | ||
renderer = new RendererImpl | ||
manager = new StateManagerImpl[IO] | ||
stateStorage = new StorageImpl[State](State.Started) | ||
lastMessageStorage = new StorageImpl[Option[MessageID]](None) | ||
bot = new OfferServiceBot[IO](token, sttpBackend, renderer, manager, stateStorage, lastMessageStorage) | ||
|
||
_ <- bot.startPolling() | ||
} yield () | ||
} |
87 changes: 87 additions & 0 deletions
87
bot/src/main/scala/com/github/mmvpm/bot/OfferServiceBot.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package com.github.mmvpm.bot | ||
|
||
import cats.effect.Concurrent | ||
import cats.implicits.toFlatMapOps | ||
import cats.syntax.functor._ | ||
import com.bot4s.telegram.api.declarative.{Callbacks, Command, Commands} | ||
import com.bot4s.telegram.cats.{Polling, TelegramBot} | ||
import com.bot4s.telegram.methods.{EditMessageText, SendDice, SendMessage} | ||
import com.bot4s.telegram.models._ | ||
import com.github.mmvpm.bot.model.MessageID | ||
import com.github.mmvpm.bot.render.Renderer | ||
import com.github.mmvpm.bot.state.{State, StateManager, Storage} | ||
import com.github.mmvpm.bot.state.State._ | ||
import sttp.client3.SttpBackend | ||
|
||
class OfferServiceBot[F[_]: Concurrent]( | ||
token: String, | ||
sttpBackend: SttpBackend[F, Any], | ||
renderer: Renderer, | ||
manager: StateManager[F], | ||
stateStorage: Storage[State], | ||
lastMessageStorage: Storage[Option[MessageID]]) | ||
extends TelegramBot[F](token, sttpBackend) | ||
with Polling[F] | ||
with Commands[F] | ||
with Callbacks[F] { | ||
|
||
// user sent a message (text, image, etc) to the chat | ||
onMessage { implicit message => | ||
command(message) match { | ||
case Some(Command("roll", _)) => roll | ||
case Some(Command("start", _)) => start | ||
case None => | ||
getNextStateTag(stateStorage.get) match { | ||
case UnknownTag => fail | ||
case nextTag => replyResolved(nextTag) | ||
} | ||
} | ||
} | ||
|
||
// user pressed the button | ||
onCallbackQuery { implicit cq => | ||
replyResolved(cq.data.get)(cq.message.get) | ||
} | ||
|
||
// scenarios | ||
|
||
private def roll(implicit message: Message): F[Unit] = | ||
request(SendDice(message.chat.id)).void | ||
|
||
private def start(implicit message: Message): F[Unit] = | ||
requestLogged(renderer.render(stateStorage.get, lastMessageStorage.get)).void | ||
|
||
private def replyResolved(tag: String)(implicit message: Message): F[Unit] = | ||
for { | ||
nextState <- manager.getNextState(tag, stateStorage.get) | ||
_ = stateStorage.set(withoutError(nextState)) | ||
reply = renderer.render(nextState, lastMessageStorage.get) | ||
_ <- requestLogged(reply) | ||
} yield () | ||
|
||
private def fail(implicit message: Message): F[Unit] = | ||
reply("Не понял вас :(").void | ||
|
||
// internal | ||
|
||
private def withoutError(state: State): State = | ||
state match { | ||
case Error(returnTo, _) => returnTo | ||
case _ => state | ||
} | ||
|
||
private def requestLogged(req: Either[EditMessageText, SendMessage]): F[Unit] = | ||
req match { | ||
case Left(toEdit) => | ||
for { | ||
sent <- request(toEdit) | ||
_ = println(s"Edit $sent") | ||
} yield () | ||
case Right(toSend) => | ||
for { | ||
sent <- request(toSend) | ||
_ = lastMessageStorage.set(Some(sent.messageId))(sent) | ||
_ = println(s"Sent $sent") | ||
} yield () | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.github.mmvpm.bot.model | ||
|
||
case class Draft( | ||
name: Option[String] = None, | ||
price: Option[Long] = None, | ||
description: Option[String] = None, | ||
photos: Seq[String] = Seq.empty) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.github.mmvpm.bot | ||
|
||
package object model { | ||
type ChatID = Long | ||
type MessageID = Int | ||
type Tag = String | ||
type Button = String | ||
} |
15 changes: 15 additions & 0 deletions
15
bot/src/main/scala/com/github/mmvpm/bot/render/Renderer.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.github.mmvpm.bot.render | ||
|
||
import com.bot4s.telegram.methods.{EditMessageText, SendMessage} | ||
import com.bot4s.telegram.models.Message | ||
import com.github.mmvpm.bot.model.MessageID | ||
import com.github.mmvpm.bot.state.State | ||
|
||
trait Renderer { | ||
|
||
def render( | ||
state: State, | ||
editMessage: Option[MessageID] | ||
)(implicit message: Message | ||
): Either[EditMessageText, SendMessage] | ||
} |
29 changes: 29 additions & 0 deletions
29
bot/src/main/scala/com/github/mmvpm/bot/render/RendererImpl.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.github.mmvpm.bot.render | ||
|
||
import com.bot4s.telegram.methods.{EditMessageText, SendMessage} | ||
import com.bot4s.telegram.models.{InlineKeyboardButton, InlineKeyboardMarkup, Message} | ||
import com.github.mmvpm.bot.model.MessageID | ||
import com.github.mmvpm.bot.state.State | ||
import com.github.mmvpm.bot.state.State._ | ||
|
||
class RendererImpl extends Renderer { | ||
|
||
override def render( | ||
state: State, | ||
editMessage: Option[MessageID] = None | ||
)(implicit message: Message): Either[EditMessageText, SendMessage] = { | ||
val buttons = state.next.map { tag => | ||
InlineKeyboardButton.callbackData(buttonBy(tag), tag) | ||
} | ||
val markup = Some(InlineKeyboardMarkup.singleColumn(buttons)) | ||
|
||
lazy val send = SendMessage(message.source, state.text, replyMarkup = markup) | ||
lazy val edit = EditMessageText(Some(message.source), editMessage, text = state.text, replyMarkup = markup) | ||
|
||
if (editMessage.contains(message.messageId)) // the last message was sent by the bot | ||
Left(edit) | ||
else | ||
Right(send) | ||
} | ||
} | ||
|
Oops, something went wrong.