bot4s / telegram Goto Github PK
View Code? Open in Web Editor NEWTelegram Bot API Wrapper for Scala
License: Apache License 2.0
Telegram Bot API Wrapper for Scala
License: Apache License 2.0
Hi!
I'm making a request with SendMessage, but info.mukel.telegrambot4s.api.TelegramApiException: Not Found
I looked into the code of info.mukel.telegrambot4s.methods.ApiRequest[R] and found this:
def methodName: String = getClass.getSimpleName.reverse.dropWhile(_ == '$').reverse
but this code return SendMessage, expected sendMessage (in Telegram API).
Any interest in releasing to sonatype? I can help with that..
Printing to console all http messages by default leads to verbose output: https://github.com/mukel/telegrambot4s/blob/e1d6c9938d43d1daef5e1f16460f37da5c7a6372/src/main/scala/info/mukel/telegrambot4s/api/TelegramApiAkka.scala#L59.
In many case i would like to ignore this messages, but i can't. Please, use logging instead of printing to console. For example, using https://github.com/typesafehub/scala-logging. It will help users to control library output.
Hello, my bot is failing to start with error
Failed to clear webhook
akka.stream.StreamTcpException: The connection closed with error: Connection reset by peer
My guess is my connection to Telegram servers gets blocked.
Among your resent issues I saw your answer about proxy support. Is it still possible to access your refactored version (3.1.0-RC1)?
Hello,
I'm having a problem with answering inline queries.
Library version is 4.0.0-RC1.
System information:
~/testproject $ uname -a
FreeBSD scaladev 11.1-RELEASE-p10 FreeBSD 11.1-RELEASE-p10 #0: Tue May 8 05:21:56 UTC 2018 [email protected]:/usr/obj/usr/src/sys/GENERIC amd64
~/testproject $ scala -version
Scala code runner version 2.12.6 -- Copyright 2002-2018, LAMP/EPFL and Lightbend, Inc.
~/testproject $ java -version
openjdk version "1.8.0_172"
OpenJDK Runtime Environment (build 1.8.0_172-b11)
OpenJDK 64-Bit Server VM (build 25.172-b11, mixed mode)
sbt version is 1.0.
This is the whole code (things are named like that because I'm just starting to try out things):
import com.bot4s.telegram.api.declarative.InlineQueries
import com.softwaremill.sttp.okhttp.OkHttpFutureBackend
import com.bot4s.telegram.clients.SttpClient
import com.bot4s.telegram.methods._
import com.bot4s.telegram.models._
import slogging.{LogLevel, LoggerConfig, PrintLoggerFactory}
class EchoBot(val token: String) extends TelegramBot with Polling with InlineQueries {
LoggerConfig.factory = PrintLoggerFactory()
LoggerConfig.level = LogLevel.TRACE
onInlineQuery { implicit q =>
val results = Seq(
InlineQueryResultArticle("1", "Klingt lustig",
inputMessageContent = InputTextMessageContent("Klingt lustig")))
answerInlineQuery(results, Some(60))
}
implicit val backend = OkHttpFutureBackend()
override val client: RequestHandler = new SttpClient(token)
}
object Hello extends App {
new EchoBot("<bot token>").run()
}
When the bot receives an inline query, the output looks like this:
[trace, com.bot4s.telegram.clients.SttpClient] REQUEST c529aba4-79d6-4cca-87eb-cb8c9d9f8a77 AnswerInlineQuery(1302304079610336554,List(InlineQueryResultArticle(1,Klingt lustig,InputTextMessageContent(Klingt lustig,None,None),None,None,None,None,None,None,None,article)),Some(60),None,None,None,None)
[error, com.bot4s.telegram.clients.SttpClient] RESPONSE c529aba4-79d6-4cca-87eb-cb8c9d9f8a77 java.util.NoSuchElementException: Status code 400: {"ok":false,"error_code":400,"description":"Bad Request: can't find field \"type\""}
I don't actually know if this is a problem with the library, but I think it might be. If it's a user error, then I'm sorry and would like to know how to do it properly.
Thanks!
With the last change the added support to self-signed certificates ;-)
Currently, when a message is received and the receiver is extracted from the received text, it is compared against the first name of the bot instead of comparing it with its username, as the Telegram client suggests while typing a command like here.
This is because, in info.mukel.telegrambot4s.api.declarative.Commands
, the field botName
holds the first name of the bot instead of its username.
There is a SocketTimeoutException when the bot does not receive any messages from the user. How to handle long polling properly? Increase timeout or switch to using webhooks?
The full stack trace is quite long…
GetUpdates failed
org.json4s.package$MappingException: No usable value for result
No usable value for message
No usable value for entities
No usable value for type
No usable value for $outer
Can't find field scala$Enumeration$$vmap from class scala.Enumeration
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:526)
at org.json4s.Extraction$ClassInstanceBuilder.$anonfun$instantiate$4(Extraction.scala:546)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:400)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:392)
at org.json4s.Extraction$.extract(Extraction.scala:39)
at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21)
at info.mukel.telegrambot4s.marshalling.JsonMarshallers.fromJson(JsonMarshallers.scala:46)
at info.mukel.telegrambot4s.marshalling.JsonMarshallers.fromJson$(JsonMarshallers.scala:46)
at info.mukel.telegrambot4s.marshalling.JsonMarshallers$.fromJson(JsonMarshallers.scala:49)
at info.mukel.telegrambot4s.marshalling.AkkaHttpMarshalling$.$anonfun$camelCaseJsonUnmarshaller$1(AkkaHttpMarshalling.scala:16)
at akka.http.scaladsl.util.FastFuture$.$anonfun$map$1(FastFuture.scala:23)
at akka.http.scaladsl.util.FastFuture$.strictTransform$1(FastFuture.scala:41)
at akka.http.scaladsl.util.FastFuture$.$anonfun$transformWith$3(FastFuture.scala:51)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: org.json4s.package$MappingException: No usable value for message
No usable value for entities
No usable value for type
No usable value for $outer
Can't find field scala$Enumeration$$vmap from class scala.Enumeration
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:526)
at org.json4s.Extraction$ClassInstanceBuilder.$anonfun$instantiate$4(Extraction.scala:546)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:400)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:392)
at org.json4s.Extraction$CollectionBuilder.$anonfun$mkCollection$1(Extraction.scala:410)
at scala.collection.immutable.List.map(List.scala:283)
at org.json4s.Extraction$CollectionBuilder.mkCollection(Extraction.scala:410)
at org.json4s.Extraction$CollectionBuilder.result(Extraction.scala:443)
at org.json4s.Extraction$.$anonfun$extract$8(Extraction.scala:382)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:382)
at org.json4s.Extraction$.$anonfun$extract$6(Extraction.scala:366)
at scala.Option.flatMap(Option.scala:171)
at org.json4s.Extraction$.$anonfun$extract$5(Extraction.scala:366)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:366)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:514)
... 28 more
Caused by: org.json4s.package$MappingException: No usable value for entities
No usable value for type
No usable value for $outer
Can't find field scala$Enumeration$$vmap from class scala.Enumeration
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:526)
at org.json4s.Extraction$ClassInstanceBuilder.$anonfun$instantiate$4(Extraction.scala:546)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:400)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:392)
at org.json4s.Extraction$.$anonfun$extract$6(Extraction.scala:366)
at scala.Option.flatMap(Option.scala:171)
at org.json4s.Extraction$.$anonfun$extract$5(Extraction.scala:366)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:366)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:514)
... 54 more
Caused by: org.json4s.package$MappingException: No usable value for type
No usable value for $outer
Can't find field scala$Enumeration$$vmap from class scala.Enumeration
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:526)
at org.json4s.Extraction$ClassInstanceBuilder.$anonfun$instantiate$4(Extraction.scala:546)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:400)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:392)
at org.json4s.Extraction$CollectionBuilder.$anonfun$mkCollection$1(Extraction.scala:410)
at scala.collection.immutable.List.map(List.scala:283)
at org.json4s.Extraction$CollectionBuilder.mkCollection(Extraction.scala:410)
at org.json4s.Extraction$CollectionBuilder.result(Extraction.scala:443)
at org.json4s.Extraction$.$anonfun$extract$8(Extraction.scala:382)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:382)
at org.json4s.Extraction$.$anonfun$extract$6(Extraction.scala:366)
at scala.Option.flatMap(Option.scala:171)
at org.json4s.Extraction$.$anonfun$extract$5(Extraction.scala:366)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:366)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:514)
... 73 more
Caused by: org.json4s.package$MappingException: No usable value for $outer
Can't find field scala$Enumeration$$vmap from class scala.Enumeration
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:526)
at org.json4s.Extraction$ClassInstanceBuilder.$anonfun$instantiate$4(Extraction.scala:546)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:400)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:392)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:514)
... 99 more
Caused by: org.json4s.package$MappingException: Can't find field scala$Enumeration$$vmap from class scala.Enumeration
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.reflect.ScalaSigReader$.read$1(ScalaSigReader.scala:43)
at org.json4s.reflect.ScalaSigReader$.$anonfun$readField$3(ScalaSigReader.scala:47)
at scala.Option.getOrElse(Option.scala:121)
at org.json4s.reflect.ScalaSigReader$.read$1(ScalaSigReader.scala:47)
at org.json4s.reflect.ScalaSigReader$.readField(ScalaSigReader.scala:49)
at org.json4s.reflect.Reflector$ClassDescriptorBuilder.$anonfun$fields$3(Reflector.scala:69)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at org.json4s.reflect.Reflector$ClassDescriptorBuilder.fields(Reflector.scala:68)
at org.json4s.reflect.Reflector$ClassDescriptorBuilder.properties(Reflector.scala:85)
at org.json4s.reflect.Reflector$ClassDescriptorBuilder.result(Reflector.scala:184)
at org.json4s.reflect.Reflector$.createDescriptor(Reflector.scala:53)
at org.json4s.reflect.Reflector$.$anonfun$describe$1(Reflector.scala:48)
at org.json4s.reflect.package$Memo.apply(package.scala:36)
at org.json4s.reflect.Reflector$.describe(Reflector.scala:48)
at org.json4s.Extraction$.$anonfun$extract$9(Extraction.scala:393)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
at org.json4s.Extraction$.extract(Extraction.scala:392)
at org.json4s.Extraction$ClassInstanceBuilder.buildCtorArg(Extraction.scala:514)
... 113 more
I'm not sure that the problem is on your side. I think the actual JSON value would be helpful, I can send it to you privately if you wish.
Hi,
There's a way to send gifs in the older version 3.16, apart from senting the Gif URL?
Cheers
May be it's a good idea to wrap handleUpdate in a Future object
Because getUpdates return Future[Array] and increment of a updateOffset value happens after update will be handled.
It lead to if getUpdates return more then 1 item and/or handle will take more then 1 second, getUpdate will call again with same updateOffset value.
override def run(): Unit = {
// setWebhook(None)
var updatesOffset = 0
while (running) {
for (updates <- getUpdates(offset = updatesOffset)) {
for (u <- updates ) {
Future(handleUpdate(u))
updatesOffset = updatesOffset max (u.updateId + 1)
}
}
Thread.sleep(pollingCycle)
}
}
I can't see any place where we configure HTTPS in telegrambot4s..
As a result we can see that telegrambot4s is served in HTTP:
[WARN] [11/06/2017 12:03:39.680] [default-akka.actor.default-dispatcher-5] [akka.actor.ActorSystemImpl(default)] Illegal request, responding with status '400 Bad Request': Unsupported HTTP method: HTTP method too long (started with '����ᅡ���ᄒ��→¢£��'). Increase `akka.http.server.parsing.max-method-length` to support HTTP methods with more characters.
In every example you show use like this
bot.on("/command") {...}
I got confused, cause in this way it doesn't work.
But it works like this:
bot.on("command") {...}
Hello @mukel
It is great pleasure to read your code and use this project. I have some idea that I found useful and also I have implementation and I can contribute if you let me.
So when we give commands with on(some:String){function} they don't preserve order and if we have "registered"command twice in code it will be executed twice. What if we will make commands ordered, execute them once so that we will play around with commands that match from specific to more general one?
Cheers,
/Jakhongir
Bot name after the @
is not checked. If a bot has been granted full access to messages in a chat, it will inspect all commands and execute their callbacks while ignoring which bot the command was actually adressed to.
for example, typing /start@youtube
while my bot is present with access to messages will execute the /start
command on my bot.
I'm planning a major refactor, these are some of the planned changes/features, please leave your feature in the comments.
Hello @mukel
I try to use your library like this:
class telegBotWH(log :org.slf4j.Logger, config :Config) extends AkkaTelegramBot with Webhook with Commands[Future] { ...
and next want explisitely load certificate with:
val cfile :java.io.File= new File("C:\\tcert\\mtspredbot.pem") val inpCertFilePath :java.nio.file.Path = cfile.toPath override val certificate :Option[InputFile] = Option(InputFile(inpCertFilePath))
I use next WebHook address https://xxx.xxx.xxx.xxx
where xxx.xxx.xxx.xxx is my VDS
When I run bot there is next output
[trace, com.bot4s.telegram.clients.AkkaHttpClient] REQUEST 5ebe2b43-f7da-4fe9-80f3-a04448d3df8e SetWebhook(https://xxx.xxx.xxx.xxx,Some(Path(C:\tcert\mtspredbot.pem)),None,None) Press [ENTER] to shutdown the bot, it may take a few seconds... [trace, com.bot4s.telegram.clients.AkkaHttpClient] RESPONSE 5ebe2b43-f7da-4fe9-80f3-a04448d3df8e true [WARN] [06/28/2019 15:58:30.996] [default-akka.actor.default-dispatcher-16] [akka.actor.ActorSystemImpl(default)] Illegal request, responding with status '400 Bad Request': Unsupported HTTP method: The HTTP method started with 0x16 rather than any known HTTP method. Perhaps this was an HTTPS request sent to an HTTP endpoint?
My question. Is it possible to use bot wuth this configuration as destination for telegram with https.
I know about ngrok and it works fine but wants to use it directly, because it's vds.
The project went through a major refactor, some changes/additions :
To try the latest version add to your build.sbt
:
resolvers += Resolver.sonatypeRepo("staging")
libraryDependencies ++= Seq(
"com.bot4s" %% "telegram-core" % "4.0.0-RC1",
"com.bot4s" %% "telegram-akka" % "4.0.0-RC1"
)
Hi,
I would like to implement a secure bot feature, meaning that the bot could only respond to specific channels (groups or users), I thought the best would be to add the filter inside the handleUpdate methods of the Commands
class, allowing us not to call the action if the msg.chat.id
does not match any of the authorized one.
Here are my questions:
Please point me to the right direction on implementing this.
I have the snippet so far:
onMessage{ implicit msg =>
request(GetFile(msg.voice.map(_.fileId).getOrElse(""))
.onComplete{
case Success(file) => ??? //what to do next to get the actual file (when i try file.filePath it gives me something like this --> voice/file_1)
}
}
Thanks,
here is the code
object PokerTelegramBot extends TelegramBot with Polling with Messages {
lazy val token = "SOME_TOKEN"
override def receiveMessage(msg: Message) = {
msg.text.foreach {
case "/start" ⇒
println("start handled")
val inlineBtns = InlineKeyboardMarkup(Seq(Seq(InlineKeyboardButton(
text = "Play now!",
callbackData = Some("{ game_short_name: \"cpptest\" }")))))
reply("To play game press button", replyMarkup = Some(inlineBtns))(msg)
case any ⇒ println(s"unhandled message <$any>")
}
}
override def receiveCallbackQuery(callbackQuery: CallbackQuery) = {
println(s"gameShortName: ${callbackQuery.gameShortName}")
println(s"data: ${callbackQuery.data}")
}
}
after button click we see callbackQuery.gameShortName = None
and callbackQuery.data = Some({ game_short_name: "cpptest" })
Code example from readme not compiling, version "info.mukel" %% "telegrambot4s" % "2.9.5".
error: not found: value onCommand
code:
object WebhookBot extends TelegramBot with Webhook with Commands {
import info.mukel.telegrambot4s.Implicits._
def token = "TOKEN"
override val port = 443
override val webhookUrl = "https://ed88ff73.ngrok.io"
val rng = new Random(System.currentTimeMillis())
onCommand("/coin") { implicit msg => reply(if (rng.nextBoolean()) "Head!" else "Tail!") }
onCommand("/real") { implicit msg => reply(rng.nextDouble().toString) }
onCommand("/die") { implicit msg => reply((rng.nextInt(6) + 1).toString) }
onCommand("/dice") { implicit msg => reply((rng.nextInt(6) + 1) + " " + (rng.nextInt(6) + 1)) }
onCommand("/random") { implicit msg =>
withArgs {
case Seq(Extractor.Int(n)) if n > 0 =>
reply(rng.nextInt(n).toString)
case _ =>
reply("Invalid argumentヽ(ಠ_ಠ)ノ")
}
}
onCommand("/choose") { implicit msg =>
withArgs { args =>
reply(if (args.isEmpty) "Empty list." else args(rng.nextInt(args.size)))
}
}
}
Hi
Examples cover only primitive commands like: onCommand, onCallbackQuery, etc
What about Methods, how to use them?
As example i want to GetUserProfilePhotos
what should i do?
There seems to be an error in your README, I guess the version for the SBT example should be 2.0.1 and not 2.1.0.
Best regards
Fabian
There is an incorrect order of messages (sent by api.request(SendMessage)), when the polling method is used. How to keep sent messages in order? Is there any way to fix that without using webhooks?
I start sbt
and then run
my bot. How do I stop it? And another small question. I was using ~run
with tilda at the beginning of the command, it means something like watch mode I think and it this working (when I change source code sbt detects it and was recomplining automatically) but now doesn't.
Hello, i've got error java.lang.NoClassDefFoundError: com/softwaremill/sttp/package$UriContext$
when i'm trying run example bot.
Dependencies
libraryDependencies += "com.bot4s" %% "telegram-core" % "4.0.0-RC1" libraryDependencies += "com.bot4s" %% "telegram-akka" % "4.0.0-RC1" libraryDependencies += "com.softwaremill.sttp" %% "core" % "1.3.8"
The error
[trace, com.bot4s.telegram.clients.SttpClient] REQUEST c67d3f8a-996b-4808-aa04-5ff784e2c700 DeleteWebhook Exception in thread "main" java.lang.NoClassDefFoundError: com/softwaremill/sttp/package$UriContext$ at com.bot4s.telegram.clients.SttpClient.sendRequest(SttpClient.scala:41) at com.bot4s.telegram.api.RequestHandler.apply(RequestHandler.scala:37) at com.bot4s.telegram.api.RequestHandler.apply$(RequestHandler.scala:24) at com.bot4s.telegram.clients.SttpClient.apply(SttpClient.scala:22) at com.bot4s.telegram.api.Polling.run(Polling.scala:95) at com.bot4s.telegram.api.Polling.run$(Polling.scala:90) at HelloWorld.com$bot4s$telegram$api$declarative$Commands$$super$run(HelloWorld.scala:12) at com.bot4s.telegram.api.declarative.Commands.run(Commands.scala:99) at com.bot4s.telegram.api.declarative.Commands.run$(Commands.scala:97) at HelloWorld.run(HelloWorld.scala:12) at Main$.delayedEndpoint$Main$1(Main.scala:5) at Main$delayedInit$body.apply(Main.scala:4) at scala.Function0.apply$mcV$sp(Function0.scala:34) at scala.Function0.apply$mcV$sp$(Function0.scala:34) at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12) at scala.App.$anonfun$main$1$adapted(App.scala:76) at scala.collection.immutable.List.foreach(List.scala:389) at scala.App.main(App.scala:76) at scala.App.main$(App.scala:74) at Main$.main(Main.scala:4) at Main.main(Main.scala) Caused by: java.lang.ClassNotFoundException: com.softwaremill.sttp.package$UriContext$ at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 21 more
$ sbt
[info] Set current project to bobot (in build file:/home/jmerelo/Asignaturas/cloud-computing/BoBot/)
> run
[info] Updating {file:/home/jmerelo/Asignaturas/cloud-computing/BoBot/}bobot...
[info] Resolving com.github.mukel#telegrambot4s_2.10;v1.2.2 ...
[warn] module not found: com.github.mukel#telegrambot4s_2.10;v1.2.2
[warn] ==== local: tried
[warn] /home/jmerelo/.ivy2/local/com.github.mukel/telegrambot4s_2.10/v1.2.2/ivys/ivy.xml
[warn] ==== public: tried
[warn] https://repo1.maven.org/maven2/com/github/mukel/telegrambot4s_2.10/v1.2.2/telegrambot4s_2.10-v1.2.2.pom
[warn] ==== jitpack: tried
[warn] https://jitpack.io/com/github/mukel/telegrambot4s_2.10/v1.2.2/telegrambot4s_2.10-v1.2.2.pom
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: com.github.mukel#telegrambot4s_2.10;v1.2.2: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn]
[warn] Note: Unresolved dependencies path:
[warn] com.github.mukel:telegrambot4s_2.10:v1.2.2 (/home/jmerelo/Asignaturas/cloud-computing/BoBot/build.sbt#L3-4)
[warn] +- default:bobot_2.10:0.1-SNAPSHOT
[trace] Stack trace suppressed: run last *:update for the full output.
[error] (*:update) sbt.ResolveException: unresolved dependency: com.github.mukel#telegrambot4s_2.10;v1.2.2: not found
Hello! looks like link in Games section of README broken
https://github.com/bot4s/telegram#games
for self-hosted bot link in docs looks like:
https://github.com/bot4s/telegram/blob/master/examples/src-jvm/main/scala/SelfHosted2048Bot.scala
actual link is:
https://github.com/bot4s/telegram/blob/master/examples/src-jvm/SelfHosted2048Bot.scala
for github hosted bot link in docs looks like:
https://github.com/bot4s/telegram/blob/master/examples/src-jvm/main/scala/GitHubHosted2048Bot.scala
actual link is:
https://github.com/bot4s/telegram/blob/master/examples/src-jvm/GitHubHosted2048Bot.scala
the "main/scala/" part of the link is not needed
I have been searching for a way to implement filters in a non-blocking way. I have read a few parts of the source codes but could not implement that.
For Instance, code authenticates user against db
def isChatAuthenticated(msg: Message): Future[Boolean] =
db.users.find(msg.chat.id).map(_.isDefined)
when(onCommand("post") isChatAuthenticated) {....}
but currently, when
is implement as
def when[T](actionInstaller: Action[Action[T]], filter: Filter[T])(action: Action[T]): Unit = {
val newAction = {
t: T =>
if (filter(t))
action(t)
}
actionInstaller(newAction)
}
where if is blocking
I need to start command without prefix "/". Add possibility to api change CommandPrefix
.
Would be nice to have a telegram error code available in exception. I.e. in case of 429 ([Error]: Too many requests: retry later) API user might want to resend the message with some delay instead of failing.
Telegram keeps adding new entity types without proper notice.
To keep bots from breaking randomly I added a safe fallback for unknown/new entity types.
I backported this fix to v3, but hit json4s/json4s#142
json4s relies on reflection but Scala enums are indistinguishable at runtime; json4s tries all defined enum parsers until one succeeds; this is dangerous since it can break type safety.
My attempt to fix this was mostly correct, but didn't consider that the order in which the enum deserializers are added actually matters; WTF. At least is deterministic...
I just pushed a fix to avoid future breakages due to new entity types; but bot masters should port bots to v4 which is based on circe and gracefully accepts unknown/new entity types.
Released v3.0.16 with the fix.
/cc @Rovak
here is the code
object PokerTelegramBot extends TelegramBot with Polling with Messages {
lazy val token = "SOME_TOKEN"
override def receiveMessage(msg: Message) = {
msg.text.foreach {
case "/start" ⇒
println("start handled")
val inlineBtns = InlineKeyboardMarkup(Seq(Seq(InlineKeyboardButton(
text = "Play now!",
callbackData = Some("{ game_short_name: \"cpptest\" }")))))
reply("To play game press button", replyMarkup = Some(inlineBtns))(msg)
case any ⇒ println(s"unhandled message <$any>")
}
}
override def receiveCallbackQuery(callbackQuery: CallbackQuery) = {
println(s"gameShortName: ${callbackQuery.gameShortName}")
println(s"data: ${callbackQuery.data}")
callbackQuery.data.foreach { data ⇒
if (data.contains("game_short_name: \"cpptest\""))
request(AnswerCallbackQuery(callbackQuery.id, url = Some("http://google.com")))
}
}
}
exception happens
info.mukel.telegrambot4s.api.TelegramApiException: Bad Request: URL_INVALID
at info.mukel.telegrambot4s.clients.AkkaClient$$anonfun$apply$3.apply(AkkaClient.scala:56)
at info.mukel.telegrambot4s.clients.AkkaClient$$anonfun$apply$3.apply(AkkaClient.scala:51)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:253)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:36)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
Hello! It is possible to set socks5 proxy for long polling bot? And how it can be done if it is?
I am using deep link to start telegram mobile app. I want to add a command to the bot and one of this is to start voice recording when chat app opens.
Is this possible with telegrambot4s?
Thanks,
Sorry about this but I didn't find the way to extract an Audio file from server, I'm using this code:
val fileRequest:GetFile = new GetFile(msg.audio.get.fileId) // whats the next step
Regards
Right now you are using synchronous http api which wrapped into Future
. Let use truly async clients like spray-client, dispatch or so to provide real async communication
Hi.
I'm developing a bot to send messages to a channel.
Locally, while I develop the bot and run it, it works fine and receives all commands.
But in a production environment, were a firewall blocks all requests by default, it doesn't work. My bot isn't receiving messages or commands.
I already allowed "api.telegram.org:443" in the firewall. This liberation works. I can send requests to it via telnet. But wasn't enough.
There another port or address that I need allow?
Steps to reproduce:
Expected behavior:
Bot will correctly handle all these events
Actual behavior:
Bot cannot parse one of the update messages and fails with:
[info] No usable value for id
[info] Did not find value which can be converted into long
[info] at org.json4s.reflect.package$.fail(package.scala:95)
[info] at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:526)
[info] at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$15.apply(Extraction.scala:546)
[info] at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$15.apply(Extraction.scala:546)
[info] at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info] at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info] at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
[info] at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
[info] at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
[info] at scala.collection.AbstractTraversable.map(Traversable.scala:104)
[info] Caused by: org.json4s.package$MappingException: No usable value for id
[info] Did not find value which can be converted into long
[info] at org.json4s.reflect.package$.fail(package.scala:95)
[info] at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:526)
[info] at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$15.apply(Extraction.scala:546)
[info] at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$15.apply(Extraction.scala:546)
[info] at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info] at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:234)
[info] at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
[info] at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
[info] at scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
[info] at scala.collection.AbstractTraversable.map(Traversable.scala:104)
[info] Caused by: org.json4s.package$MappingException: Did not find value which can be converted into long
[info] at org.json4s.reflect.package$.fail(package.scala:95)
[info] at org.json4s.Extraction$$anonfun$org$json4s$Extraction$$convert$2.apply(Extraction.scala:704)
[info] at org.json4s.Extraction$$anonfun$org$json4s$Extraction$$convert$2.apply(Extraction.scala:704)
[info] at scala.Option.getOrElse(Option.scala:121)
[info] at org.json4s.Extraction$.org$json4s$Extraction$$convert(Extraction.scala:704)
[info] at org.json4s.Extraction$$anonfun$extract$6.apply(Extraction.scala:394)
[info] at org.json4s.Extraction$$anonfun$extract$6.apply(Extraction.scala:392)
[info] at org.json4s.Extraction$.customOrElse(Extraction.scala:606)
[info] at org.json4s.Extraction$.extract(Extraction.scala:392)
[info] at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:514)
Telegram4s v3.0.9
I've updated library from 3.0.4
to 3.0.13
and faced the problem with line breaks in document title. They are sent as plain text.
SendDocument(chatId, InputFile("file.png", byteArray),
caption = Some("first line\nsecond line"))
Resulting message in 3.0.4
:
first line
second line
In 3.0.13
:
first line\nsecond line
Can I remove the service message using the this
for eg
xyz joined the group
pqr left the group
I want to remove the telegram message whenever user join or leave the group
The actor bindings open new ways of building bots; FSM actors will greatly simplify the creation of stateful workflows leveraging over a widely known and used model (FSM Actors).
Actor bindings can be added by mixing ActorDispatcher.
Here's an example of a very simple per-chat dispatcher:
Per-chat actor dispatcher
The purpose of this issue is to agree on a general design for a more powerful abstraction.
Possibly including:
Problem:
We are using webhooks and have scaling environment (e.g. k8s) and we scale our bot app from 1 to 3+ instances. They are launched in parallel and each one tries to set the same webhook via setWebhook
.
And as expected Telegram responds with 429 Too Many Requests
.
Solution:
Before setting the webhook execute getWebhookInfo
method and compare it with com.bot4s.telegram.methods.SetWebhook
parameters.
Concerns:
certificate
was changes than there is no way to find this outOr at least we can provide some sort of parameter which configures this behavior.
I am fine with submitting PR after we agree on solution.
I run a bot on a server and I noticed that there are some reoccuring exceptions with the Polling. The Exception reads as follows:
ERROR - GetUpdates failed
akka.http.scaladsl.unmarshalling.Unmarshaller$UnsupportedContentTypeException: Unsupported Content-Type, supported: application/json
at akka.http.scaladsl.unmarshalling.Unmarshaller$UnsupportedContentTypeException$.apply(Unmarshaller.scala:158)
at akka.http.scaladsl.unmarshalling.Unmarshaller$EnhancedFromEntityUnmarshaller$.$anonfun$forContentTypes$3(Unmarshaller.scala:114)
at akka.http.scaladsl.unmarshalling.Unmarshaller$$anon$1.apply(Unmarshaller.scala:58)
at akka.http.scaladsl.unmarshalling.Unmarshaller.$anonfun$transform$3(Unmarshaller.scala:23)
at akka.http.scaladsl.unmarshalling.Unmarshaller$$anon$1.apply(Unmarshaller.scala:58)
at akka.http.scaladsl.unmarshalling.Unmarshal.to(Unmarshal.scala:25)
at info.mukel.telegrambot4s.clients.AkkaClient.toApiResponse(AkkaClient.scala:38)
at info.mukel.telegrambot4s.clients.AkkaClient.$anonfun$apply$2(AkkaClient.scala:50)
at scala.concurrent.Future.$anonfun$flatMap$1(Future.scala:304)
at scala.concurrent.impl.Promise.$anonfun$transformWith$1(Promise.scala:37)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:60)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:140)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
The really bad part about this is not the uncaught exception, but that the error occurs multiple times afterwards. I checked the logs and apparently the error appeared 382 times in about 12 seconds, in my example between 2:32:25 and 2:32:37. To show the frequency, I'll add an excerpt of the logs:
2017-12-09 02:32:25,980 ERROR h.i.t.IWINewsBot [Polling.scala:39] GetUpdates failed
2017-12-09 02:32:26,006 ERROR h.i.t.IWINewsBot [Polling.scala:39] GetUpdates failed
2017-12-09 02:32:26,035 ERROR h.i.t.IWINewsBot [Polling.scala:39] GetUpdates failed
2017-12-09 02:32:26,060 ERROR h.i.t.IWINewsBot [Polling.scala:39] GetUpdates failed
2017-12-09 02:32:26,090 ERROR h.i.t.IWINewsBot [Polling.scala:39] GetUpdates failed
2017-12-09 02:32:26,113 ERROR h.i.t.IWINewsBot [Polling.scala:39] GetUpdates failed
Hello @mukel.
This issue is continue #76
I have configured bot as HTTPS destination, it works fine and needs a small CPU resource (in my configuration 1-2%.)
Now I need to use Cassandra session (CqlSession) inside bot. My idea is using bot to send it commands like /info /lastbar /lasttick. Bot receive commands and in method(s) onCommand execute Cassandra query(ies) and return results to telegram chat.
val bot = new telegBotWH(log, config, sessSrc)
val eol = bot.run
...
where
class telegBotWH(log :org.slf4j.Logger,
config :Config,
sessSrc :CassSessionSrc)
extends AkkaTelegramBot
with Webhook
with CommonFuncs
with Commands[Future]
{
...
onCommand('ticksall) { implicit msg =>
onCommandLog(msg)
val ticksCounts: Seq[TicksCnt] = sessSrc.getTicksDistrib
reply(ticksCounts.sortBy(t => t.tickCount)(Ordering[Long].reverse).mkString(EOL))
Future.successful()
}
...
it works as expected, stable and fast.
But application use high cpu, jumps 20-50% (in my VDS). Also in silent mode, when I do not communicate with bot.
It's inappropriate for me.
I use jmc, jconsole for research and found that a lot of cpu spend on thread s0-timer-0 (s0 cassandra). But there are no queries to DB at all, no explicit timers or scheduled tasks.
I can understand why a silent session uses high CPU.
My second idea is moving Cassandra session from parameter of telegBotWH and convert it into children Actor.
Code:
inside telegBotWH, after
port
def httpsContext
client
I create child Actor
val cassSessActor = system.actorOf(CassSessActor.props(config), "CassSessActor")
From logs I see that when child Actor created it successful open session to db.
Next onCommand and send message to Actor to execute db query.
onCommand('tickers) { implicit msg =>
log.info("onCommand[tickers]")
cassSessActor ! "get_tickers"
Future.successful()
}
Also from log I see that child Actor real read DB and has data. But,
I have 2 ways to send result back to bot
override def receive: Receive = {
case "get_tickers" => {
val listTickers :Seq[Ticker] = sessSrc.getTickersDict.toList
log.info("inside CassSessActor read tickers, size="+listTickers.size+" send it back to bot.")
context.parent ! listTickers
}
in bot
def receive: Receive = {
case seqTickers : Seq[Ticker] => {
log.info("Receive tickers dict from cassSessActor")
log.info("Output inside telegBotWH")
seqTickers.foreach(t => log.info("["+t.tickerId+"] - "+t.tickerCode))
}
In this case Bot don't receive message from child actor, there is no error.
If I change context.parent ! listTickers to sender ! listTickers
There is error:
10:18:07.220 [default-akka.actor.default-dispatcher-4] INFO mtspredbot.Main$ - onCommand[check]
[INFO] [07/03/2019 10:18:07.245] [default-akka.actor.default-dispatcher-16] [akka://default/user/CassSessActor] Receive check message from bot.
[INFO] [07/03/2019 10:18:07.247] [default-akka.actor.default-dispatcher-6] [akka://default/deadLetters] Message [java.lang.String]
from Actor[akka://default/user/CassSessActor#1672889139]
to Actor[akka://default/deadLetters] was not delivered.
[2] dead letters encountered.
If this is not an expected behavior, then [Actor[akka://default/deadLetters]] may have terminated unexpectedly,
This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: UNRESOLVED DEPENDENCIES ::
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
[warn] :: com.bot4s#telegram-core_2.12;4.0.0-RC1: not found
[warn] :: com.bot4s#telegram-akka_2.12;4.0.0-RC1: not found
[warn] ::::::::::::::::::::::::::::::::::::::::::::::
Thank you for great library, I'm beginner in Scala, but everything looks very easy to use for me.
Recently Telegram announced Bot API 2.0. Do you have any plans to implement new features like inline keyboards, location and phone number sharing?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.