Created
August 17, 2017 21:42
-
-
Save mukel/24ee75aeb1a1622527b8664d8f7d2a8b to your computer and use it in GitHub Desktop.
scalaj-http client for TelegramBot4s
This file contains hidden or 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
| 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