Skip to content

Instantly share code, notes, and snippets.

@mukel
Created August 17, 2017 21:42
Show Gist options
  • Select an option

  • Save mukel/24ee75aeb1a1622527b8664d8f7d2a8b to your computer and use it in GitHub Desktop.

Select an option

Save mukel/24ee75aeb1a1622527b8664d8f7d2a8b to your computer and use it in GitHub Desktop.
scalaj-http client for TelegramBot4s
package info.mukel.telegrambot4s.client
import java.nio.file.Files
import info.mukel.telegrambot4s.api.RequestHandler
import info.mukel.telegrambot4s.marshalling.JsonMarshallers
import info.mukel.telegrambot4s.methods.{ApiRequest, ApiRequestJson, ApiRequestMultipart, ApiResponse}
import info.mukel.telegrambot4s.models.InputFile
import scala.concurrent.{ExecutionContext, Future}
import scalaj.http.{Http, HttpRequest, MultiPart}
/** Scalaj-http Telegram Bot API client
*
* Provide transparent camelCase <-> underscore_case conversions during serialization/deserialization.
*
* The Scalaj-http client only supports the following InputFiles:
* InputFile.FileId
* InputFile.Contents
* InputFile.Path
*
* It throws UnsupportedOperationException if the InputFile type is not supported
* e.g InputFile.ByteString
*
* Note that the exception is thrown from the method,
* it's not silently wrapped in the returning Future.
*
* @param token Bot token
*/
class ScalajHttpClient(token: String, telegramHost: String = "api.telegram.org")(implicit ec: ExecutionContext) extends RequestHandler {
import JsonMarshallers._
val connectionTimeoutMs = 10000 // default 1000
val readTimeoutMs = 50000 // default 5000
private val apiBaseUrl = s"https://$telegramHost/bot$token/"
private def sendRequest[R](r: HttpRequest): Future[R] = {
Future {
r.asString
} map {
x =>
if (x.isSuccess)
fromJson[ApiResponse[R]](x.body)
else
throw new Exception(s"Error ${x.code} on network request")
} flatMap (parseApiResponse)
}
/** Spawns a type-safe request.
*
* @param request
* @tparam R Request's expected result type
* @return The request result wrapped in a Future (async)
*/
override def apply[R: Manifest](request: ApiRequest[R]): Future[R] = {
val url = apiBaseUrl + request.methodName
request match {
case r : ApiRequestJson[R] =>
val jsonData = toJson(r)
sendRequest(
Http(url).postData(jsonData).header("content-type", "application/json")
)
case r : ApiRequestMultipart[R] =>
val fields = r.getClass.getDeclaredFields
val params = fields.map {
f =>
f.setAccessible(true)
(f.getName, f.get(r))
}
val scalajRequest = params.foldLeft(Http(url)) {
case (q, (key, value)) => value match {
case InputFile.FileId(fileId) =>
q.param(key, fileId)
case InputFile.Path(path) =>
q.postMulti(MultiPart(
key,
path.getFileName.toString(),
"application/octet-stream",
Files.newInputStream(path),
Files.size(path),
_ => ()))
case InputFile.Contents(filename, contents) =>
q.postMulti(MultiPart(key, filename, "application/octet-stream", contents))
// Throw when using unsupported files.
case _: InputFile =>
throw new UnsupportedOperationException("Scalaj-http client does not support this InputFile")
case other =>
def unquote(s: String): String = {
val quote = "\""
s.stripSuffix(quote).stripPrefix(quote)
}
q.param(key, unquote(toJson(other)))
}
}
sendRequest(scalajRequest)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment