diff --git a/build.gradle b/build.gradle index c874146..8d9f712 100644 --- a/build.gradle +++ b/build.gradle @@ -77,22 +77,26 @@ repositories { dependencies { - api "org.scala-lang:scala3-library_3:${proj_scala_lib}" - compileOnlyApi "com.github.spotbugs:spotbugs-annotations:${lib_spotbugs_v}" + api group: 'org.scala-lang', name: 'scala3-library_3', version: proj_scala_lib + final scala = (String name) -> "${name}_$proj_scala_api" + compileOnlyApi group: 'com.github.spotbugs', name: 'spotbugs-annotations', version: lib_spotbugs_v - implementation "cc.sukazyo:messiva:${lib_messiva_v}" - implementation "cc.sukazyo:resource-tools:${lib_resourcetools_v}" - testImplementation "cc.sukazyo:resource-tools:${lib_resourcetools_v}" + implementation group: 'cc.sukazyo', name: 'messiva', version: lib_messiva_v + implementation group: 'cc.sukazyo', name: 'resource-tools', version: lib_resourcetools_v + testImplementation group: 'cc.sukazyo', name: 'resource-tools', version: lib_resourcetools_v - implementation "com.github.pengrad:java-telegram-bot-api:${lib_javatelegramapi_v}" - implementation "com.squareup.okhttp3:okhttp:${lib_okhttp_v}" - implementation "com.google.code.gson:gson:${lib_gson_v}" + implementation group: 'com.github.pengrad', name: 'java-telegram-bot-api', version: lib_javatelegramapi_v + implementation group: 'com.softwaremill.sttp.client3', name: scala('core'), version: lib_sttp_v + implementation group: 'com.softwaremill.sttp.client3', name: scala('okhttp-backend'), version: lib_sttp_v + implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: lib_okhttp_v + implementation group: 'com.google.code.gson', name: 'gson', version: lib_gson_v + + testImplementation group: 'org.scalatest', name: scala('scalatest'), version: lib_scalatest_v + testImplementation group: 'org.scalatest', name: scala('scalatest-freespec'), version: lib_scalatest_v + testRuntimeOnly group: 'org.scala-lang.modules', name: scala('scala-xml'), version: lib_scalamodule_xml_v - testImplementation "org.scalatest:scalatest_$proj_scala_api:${lib_scalatest_v}" - testImplementation "org.scalatest:scalatest-freespec_$proj_scala_api:${lib_scalatest_v}" - testRuntimeOnly "org.scala-lang.modules:scala-xml_$proj_scala_api:${lib_scalamodule_xml_v}" - testRuntimeOnly 'com.vladsch.flexmark:flexmark-all:0.64.6' // for generating HTML report // required by gradle-scalatest plugin + testRuntimeOnly group: 'com.vladsch.flexmark', name: 'flexmark-all', version: '0.64.6' } diff --git a/gradle.properties b/gradle.properties index b0a587c..6f5055c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ MORNY_ARCHIVE_NAME = morny-coeur MORNY_CODE_STORE = https://github.com/Eyre-S/Coeur-Morny-Cono MORNY_COMMIT_PATH = https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s -VERSION = 1.2.1-pre1 +VERSION = 1.2.1-pre2 USE_DELTA = false VERSION_DELTA = @@ -22,6 +22,7 @@ lib_resourcetools_v = 0.2.2 lib_javatelegramapi_v = 6.2.0 +lib_sttp_v = 3.9.0 lib_okhttp_v = 4.11.0 lib_gson_v = 2.10.1 diff --git a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala index 543a783..4c0e903 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/bot/command/Nbnhhsh.scala @@ -8,6 +8,7 @@ import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Bot.exec import com.pengrad.telegrambot.model.Update import com.pengrad.telegrambot.model.request.ParseMode import com.pengrad.telegrambot.request.{SendMessage, SendSticker} +import sttp.client3.{HttpError, SttpClientException} import java.io.IOException import scala.language.postfixOps @@ -71,7 +72,7 @@ class Nbnhhsh (using coeur: MornyCoeur) extends ITelegramCommand { message toString ).parseMode(ParseMode HTML).replyToMessageId(event.message.messageId) - } catch case e: IOException => { + } catch case e: (HttpError[_] | SttpClientException) => { coeur.account exec SendMessage( event.message.chat.id, s"""[Exception] in query: diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/BilibiliForms.scala b/src/main/scala/cc/sukazyo/cono/morny/data/BilibiliForms.scala index 962c98b..c2bee8e 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/BilibiliForms.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/BilibiliForms.scala @@ -1,12 +1,13 @@ package cc.sukazyo.cono.morny.data import cc.sukazyo.cono.morny.util.BiliTool +import cc.sukazyo.cono.morny.util.SttpPublic.Schemes import cc.sukazyo.cono.morny.util.UseSelect.select -import okhttp3.{HttpUrl, OkHttpClient, Request} +import sttp.client3.{basicRequest, ignore, HttpError, SttpClientException} +import sttp.client3.okhttp.OkHttpSyncBackend +import sttp.model.Uri -import java.io.IOException import scala.util.matching.Regex -import scala.util.Using object BilibiliForms { @@ -51,11 +52,7 @@ object BilibiliForms { case _ => throw IllegalArgumentException(s"not a valid Bilibili video link: $url") - private val httpClient = OkHttpClient - .Builder() - .followSslRedirects(true) - .followRedirects(false) - .build() + private val httpClient = OkHttpSyncBackend() /** get the bilibili video url from b23.tv share url. * @@ -68,28 +65,32 @@ object BilibiliForms { * @return bilibili video url with tracking params */ @throws[IllegalStateException|IllegalArgumentException] - def destructB23Url (url: String): String = - val _url: HttpUrl = HttpUrl.parse( - if url startsWith "http://" then url.replaceFirst("http://", "https://") else url - ) - if _url == null then throw IllegalArgumentException("not a valid url: " + url) - if _url.host != "b23.tv" then throw IllegalArgumentException(s"not a b23 share link: $url") - if (!_url.pathSegments.isEmpty) && _url.pathSegments.get(0).matches(REGEX_BILI_ID.regex) then - throw IllegalArgumentException(s"is a b23 video link: $url ; (use parse_videoUrl directly)") - val result: Option[String] = - try { - Using(httpClient.newCall(Request.Builder().url(_url).build).execute()) { response => - if response.isRedirect then - val _u = response header "Location" - if _u != null then - Some(_u) - else throw IllegalStateException("unable to get b23.tv redir location from: " + response) - else throw IllegalStateException("unable to get b23.tv redir location from: " + response) - }.get - } catch case e: IOException => - throw IllegalStateException("get b23.tv failed.", e) - result match - case Some(_result) => _result - case None => throw IllegalStateException("unable to parse from b23.tv .") + def destructB23Url (url: String): String = { + + val uri = try Uri.unsafeParse(url).scheme(Schemes.HTTPS) catch + case e: IllegalArgumentException => throw IllegalArgumentException("not a b23.tv url", e) + if uri.host.orNull != "b23.tv" then throw + IllegalArgumentException(s"not a b23.tv url: $uri") + else if uri.pathSegments.segments.size < 1 then + throw IllegalArgumentException(s"empty b23.tv url: $uri") + else if uri.pathSegments.segments.head.v matches REGEX_BILI_ID.regex then + throw IllegalArgumentException(s"is a b23 video link: $uri . (use parse_videoUrl instead)") + + try { + val response = basicRequest + .get(uri) + .followRedirects(false) + .response(ignore) + .send(httpClient) + try response.header("Location").get + catch case _: NoSuchElementException => + throw IllegalStateException("unable to get b23.tv redir location from: " + response) + } catch + case e: HttpError[_] => + throw IllegalStateException("failed parse b23.tv response.", e) + case e: SttpClientException => + throw IllegalStateException("failed request from b23.tv: ", e) + + } } diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala b/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala index 9c2049a..c27bfd5 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/NbnhhshQuery.scala @@ -1,11 +1,9 @@ package cc.sukazyo.cono.morny.data -import cc.sukazyo.cono.morny.util.OkHttpPublic.MediaTypes import com.google.gson.Gson -import okhttp3.{OkHttpClient, Request, RequestBody, ResponseBody} - -import java.io.IOException -import scala.util.Using +import sttp.client3.{asString, basicRequest, HttpError, SttpClientException, UriContext} +import sttp.client3.okhttp.OkHttpSyncBackend +import sttp.model.MediaType object NbnhhshQuery { @@ -14,24 +12,19 @@ object NbnhhshQuery { private case class GuessRequest (text: String) - private val API_URL = "https://lab.magiconch.com/api/nbnhhsh/" - private val API_GUESS_METHOD = "guess/" + private val API_URL = uri"https://lab.magiconch.com/api/nbnhhsh/" + private val API_GUESS_METHOD = uri"$API_URL/guess/" - private val httpClient = OkHttpClient() + private val httpClient = OkHttpSyncBackend() - @throws[IOException] + @throws[HttpError[_]|SttpClientException] def sendGuess (text: String): GuessResult = { - val requestJsonText = Gson().toJson(GuessRequest(text)) - val request = Request.Builder() - .url(API_URL + API_GUESS_METHOD) - .post(RequestBody.create(requestJsonText, MediaTypes.JSON)) - .build - Using (httpClient.newCall(request).execute) { response => - val body = response.body - if body eq null then throw IOException("Nbnhhsh Request: body is null.") - val x = s"{ 'words': ${body.string} }" - Gson().fromJson(x, classOf[GuessResult]) - }.get + val http = basicRequest + .body(Gson().toJson(GuessRequest(text))).contentType(MediaType.ApplicationJson) + .post(API_GUESS_METHOD) + .response(asString.getRight) + .send(httpClient) + Gson().fromJson(s"{ 'words': ${http.body} }", classOf[GuessResult]) } } diff --git a/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala index d045cc5..178e21d 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/data/ip186/IP186QueryHandler.scala @@ -1,27 +1,29 @@ package cc.sukazyo.cono.morny.data.ip186 -import okhttp3.{OkHttpClient, Request} +import cc.sukazyo.cono.morny.util.SttpPublic.Schemes +import sttp.client3.{asString, basicRequest, HttpError, SttpClientException, UriContext} +import sttp.client3.okhttp.OkHttpSyncBackend +import sttp.model.Uri import java.io.IOException import scala.language.postfixOps -import scala.util.Using object IP186QueryHandler { - private val SITE_URL = "https://ip.186526.xyz/" - private val QUERY_PARAM_IP = "type=json&format=true" - private val QUERY_PARAM_WHOIS = "type=plain" + private val SITE_HOST = "ip.186526.xyz" + private val QUERY_PARAM_IP = Map("type" -> "json", "format" -> "true") + private val QUERY_PARAM_WHOIS = Map("type" -> "plain") - private val httpClient = OkHttpClient() + private val httpClient = OkHttpSyncBackend() @throws[IOException] def query_ip (ip: String): IP186Response = - commonQuery(SITE_URL + ip, QUERY_PARAM_IP) + commonQuery(uri"/$ip?$QUERY_PARAM_IP") @throws[IOException] //noinspection ScalaWeakerAccess def query_whois (domain: String): IP186Response = - commonQuery(SITE_URL+"whois/"+domain, QUERY_PARAM_WHOIS) + commonQuery(uri"/whois/$domain?$QUERY_PARAM_WHOIS") @throws[IOException] def query_whoisPretty (domain: String): IP186Response = @@ -29,13 +31,28 @@ object IP186QueryHandler { IP186Response(raw.url, raw.body substring(0, (raw.body indexOf "<<<")+3)) @throws[IOException] - private def commonQuery (requestUrl: String, queryParam: String): IP186Response = { - val request = Request.Builder().url(requestUrl + "?" + queryParam).build - Using ((httpClient newCall request) execute) { response => - val _body = response.body - if _body eq null then throw IOException("Response of ip186: body is empty!") - IP186Response(requestUrl, _body.string) - }.get + private def commonQuery (requestPath: Uri): IP186Response = { + try + val uri = requestPath.scheme(Schemes.HTTPS).host(SITE_HOST) + IP186Response( + uri.toString, + basicRequest + .get(uri) + .response(asString.getRight) + .send(httpClient) + .body + ) + catch + case e: SttpClientException => + throw IOException("request to ip186 failed: " + e.getMessage, e) + case e: HttpError[_] => + throw IOException("failed get from ip186: " + e.getMessage, e) +// val request = Request.Builder().url(requestUrl + "?" + queryParam).build +// Using ((httpClient newCall request) execute) { response => +// val _body = response.body +// if _body eq null then throw IOException("Response of ip186: body is empty!") +// IP186Response(requestUrl, _body.string) +// }.get } } diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala b/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala deleted file mode 100644 index fd7d19e..0000000 --- a/src/main/scala/cc/sukazyo/cono/morny/util/OkHttpPublic.scala +++ /dev/null @@ -1,13 +0,0 @@ -package cc.sukazyo.cono.morny.util - -import okhttp3.MediaType - -/** some public values of [[okhttp3]] */ -object OkHttpPublic { - - /** predefined [[okhttp3]] [[MediaType]]s */ - object MediaTypes: - /** [[MediaType]] of [[https://en.wikipedia.org/wiki/JSON JSON]]. using encoding ''UTF-8'' */ - val JSON: MediaType = MediaType.get("application/json; charset=utf-8") - -} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/SttpPublic.scala b/src/main/scala/cc/sukazyo/cono/morny/util/SttpPublic.scala new file mode 100644 index 0000000..241a394 --- /dev/null +++ b/src/main/scala/cc/sukazyo/cono/morny/util/SttpPublic.scala @@ -0,0 +1,10 @@ +package cc.sukazyo.cono.morny.util + +object SttpPublic { + + object Schemes { + val HTTP = "http" + val HTTPS = "https" + } + +} diff --git a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala index 88a9501..dfaa4e9 100644 --- a/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala +++ b/src/main/scala/cc/sukazyo/cono/morny/util/tgapi/formatting/TelegramUserInformation.scala @@ -1,29 +1,35 @@ package cc.sukazyo.cono.morny.util.tgapi.formatting import com.pengrad.telegrambot.model.User -import okhttp3.{OkHttpClient, Request} +import sttp.client3.{asString, basicRequest, HttpError, SttpClientException, UriContext} +import sttp.client3.okhttp.OkHttpSyncBackend import java.io.IOException import scala.util.matching.Regex -import scala.util.Using object TelegramUserInformation { - private val DC_QUERY_SOURCE_SITE = "https://t.me/" private val DC_QUERY_PROCESSOR_REGEX: Regex = "(cdn[1-9]).tele(sco.pe|gram-cdn.org)"r - private val httpClient = OkHttpClient() + private val httpClient = OkHttpSyncBackend() @throws[IllegalArgumentException|IOException] def getDataCenterFromUser (username: String): String = { - val request = Request.Builder().url(DC_QUERY_SOURCE_SITE + username).build - Using (httpClient.newCall(request) execute) { response => - val body = response.body - if body eq null then "" - else DC_QUERY_PROCESSOR_REGEX.findFirstMatchIn(body.string) match + + try + val body = basicRequest + .get(uri"https://t.me/$username") + .response(asString.getRight) + .send(httpClient) + .body + DC_QUERY_PROCESSOR_REGEX.findFirstMatchIn(body) match case Some(res) => res.group(1) case None => "" - } get + catch + case _: SttpClientException => + "" + case _: HttpError[_] => + "" } def getFormattedInformation (user: User): String = {