scalatelegram-bot

Scala bot4s: could not find implicit value for parameter backend: sttp.client3.SttpBackend[scala.concurrent.Future,Any]


I copied code from telegram/bot4s repository, put part of code to "object Main extends App", create sbt file, install libraries.

import cats.instances.future._
import cats.syntax.functor._
import com.bot4s.telegram.api.RequestHandler
import com.bot4s.telegram.api.declarative.Commands
import com.bot4s.telegram.clients.{FutureSttpClient, ScalajHttpClient}
import com.bot4s.telegram.future.{Polling, TelegramBot}
import com.bot4s.telegram.methods.SendDice

import scala.util.Try
import scala.concurrent.Future

/** Generates random values.
 */


class RandomBot(val token: String) extends TelegramBot
  with Polling
  with Commands[Future] {

  //LoggerConfig.factory = PrintLoggerFactory()
  // set log level, e.g. to TRACE
  //LoggerConfig.level = LogLevel.TRACE

  // Use sttp-based backend
  implicit val backend = SttpBackends.default
  override val client: RequestHandler[Future] = new FutureSttpClient(token)

  // Or just the scalaj-http backend
  // override val client: RequestHandler[Future] = new ScalajHttpClient(token)

  val rng = new scala.util.Random(System.currentTimeMillis())
  onCommand("coin" or "flip") { implicit msg =>
    reply(if (rng.nextBoolean()) "Head!" else "Tail!").void
  }
  onCommand("real" | "double" | "float") { implicit msg =>
    reply(rng.nextDouble().toString).void
  }
  onCommand("/die" | "roll") { implicit msg =>
    reply("⚀⚁⚂⚃⚄⚅" (rng.nextInt(6)).toString).void
  }
  onCommand("random" or "rnd") { implicit msg =>
    withArgs {
      case Seq(Int(n)) if n > 0 =>
        reply(rng.nextInt(n).toString).void
      case _ => reply("Invalid argumentヽ(ಠ_ಠ)ノ").void
    }
  }
  onCommand("choose" | "pick" | "select") { implicit msg =>
    withArgs { args =>
      replyMd(if (args.isEmpty) "No arguments provided." else args(rng.nextInt(args.size))).void
    }
  }

  onCommand("auto") { implicit msg =>
    request(SendDice(msg.chat.id)).void
  }
  // Extractor
  object Int {
    def unapply(s: String): Option[Int] = Try(s.toInt).toOption
  }
}


object Main extends App {
  val bot = new RandomBot("tokenhere")
  val eol = bot.run()
  println("Press [ENTER] to shutdown the bot, it may take a few seconds...")
  scala.io.StdIn.readLine()
  bot.shutdown() // initiate shutdown
  // Wait for the bot end-of-life
  Await.result(eol, Duration.Inf)
}

ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "2.13.16"

lazy val root = (project in file("."))
  .settings(
    name := "Meower"
  )

// Core with minimal dependencies, enough to spawn your first bot.
libraryDependencies += "com.bot4s" %% "telegram-core" % "5.8.4"

// Extra goodies: Webhooks, support for games, bindings for actors.
libraryDependencies += "com.bot4s" %% "telegram-akka" % "5.8.4"

but after that I have failed build with:

C:\Users\днс\Music\play-samples-3.0.x\Meower\src\main\scala\Main.scala:25:26 not found: value SttpBackends implicit val backend = SttpBackends.default

C:\Users\днс\Music\play-samples-3.0.x\Meower\src\main\scala\Main.scala:26:49 could not find implicit value for parameter backend: sttp.client3.SttpBackend[scala.concurrent.Future,Any] Error occurred in an application involving default arguments. override val client: RequestHandler[Future] = new FutureSttpClient(token)

C:\Users\днс\Music\play-samples-3.0.x\Meower\src\main\scala\Main.scala:71:3 not found: value Await Await.result(eol, Duration.Inf)

C:\Users\днс\Music\play-samples-3.0.x\Meower\src\main\scala\Main.scala:71:21 not found: value Duration Await.result(eol, Duration.Inf)

What I need to do to fix these problems?

I've researced Can't find SttpBackends + "Error occurred in an application involving default arguments." and tried to fix my code, but i didn't have any success...


Solution

  • First you need to add two imports to solve Await and Duration not found. So, just adding the following will solve that problem

    import scala.concurrent.{Await, Future}
    

    Then you have to decide which backend from sttp supported backends you want to use

    Supported backends

    sttp supports a number of synchronous and asynchronous backends. It’s the backends that take care of managing connections, sending requests and receiving responses: sttp defines only the API to describe the requests to be sent and handle the response data. Backends do all the heavy-lifting. Typically, a single backend instance is created for the lifetime of the application

    Let's say we choose OkHttpFutureBackend.

    Using OkHttp

    To use, add the following dependency to your project:

    "com.softwaremill.sttp.client3" %% "okhttp-backend" % "3.10.3"
    

    Create the backend using:

    import sttp.client3.okhttp.OkHttpFutureBackend
    import scala.concurrent.ExecutionContext.Implicits.global
    
    val backend = OkHttpFutureBackend()
    

    So, all you have to do is add the following dependency in your build.sbt

    libraryDependencies += "com.softwaremill.sttp.client3" %% "okhttp-backend" % "3.10.3"
    

    And then in your RandomBot class you have to replace the line

    implicit val backend = SttpBackends.default
    

    for this other one

    //remember to add the import
    import sttp.client3.okhttp.OkHttpFutureBackend
    
    // the sttp backend for ok http, but you should be able to choose any of the supported ones
    implicit val backend: SttpBackend[Future, capabilities.WebSockets] = OkHttpFutureBackend()
    

    If you want to have your own class SttpBackends to not replace the line mentioned before, you can create it as it is showed in the bot4s/telegram - examples - jvm - SttpBackends - v5.8.4

    import sttp.client3.okhttp.OkHttpFutureBackend
    import sttp.client3.SttpBackend
    import scala.concurrent.Future
    
    // the SttpBackends class definition
    object SttpBackends {
      // the val `default` invoked from `RandomBot`
      val default: SttpBackend[Future, Any] = OkHttpFutureBackend()
    }