make http:sticker/id basic usable

This commit is contained in:
A.C.Sukazyo Eyre 2024-04-20 20:38:21 +08:00
parent f2bd0a38c2
commit 9ddfa6539d
Signed by: Eyre_S
GPG Key ID: C17CE40291207874
4 changed files with 70 additions and 5 deletions

View File

@ -2,23 +2,45 @@ package cc.sukazyo.cono.morny.core.http.api
import cats.effect.IO import cats.effect.IO
import cc.sukazyo.cono.morny.data.TelegramImages import cc.sukazyo.cono.morny.data.TelegramImages
import cc.sukazyo.cono.morny.util.StringEnsure.firstLine
import cc.sukazyo.cono.morny.util.UseThrowable.toLogString import cc.sukazyo.cono.morny.util.UseThrowable.toLogString
import org.http4s.{Header, MediaType, Response} import org.http4s.{Header, MediaType, Response}
import org.http4s.dsl.io.* import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type` import org.http4s.headers.`Content-Type`
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
object HttpStatus extends HttpStatus
trait HttpStatus { trait HttpStatus {
private type ResponseT = Response[IO] private type ResponseT = Response[IO]
private type ResponseIO = IO[ResponseT] private type ResponseIO = IO[ResponseT]
extension (response: ResponseT) { extension (response: ResponseT) {
def setMornyInternalErrorHeader (e: Throwable): ResponseT = def setMornyInternalErrorHeader (e: Throwable): ResponseT =
response.setMornyInternalErrorHeader( response.setMornyInternalErrorHeader(
e.getClass.getSimpleName, e.getClass.getSimpleName.firstLine,
e.getMessage, e.getMessage.firstLine,
e.toLogString URLEncoder.encode(e.toLogString, StandardCharsets.UTF_8) // todo: maybe extract this const
) )
/** Set HTTP Header that shows Morny's Internal Server Error related information.
*
* It will set the following headers, corresponding to this method's parameters, you
* can customize those values.
* - Morny-Internal-Error-Type
* - Morny-Internal-Error-Message
* - Morny-Internal-Error-Detail
*
* **Notice that ANY header value MUST NOT contains line breaking!** Or it will only
* returns an empty 500 response.
*
* @return the [[ResponseT]], with above headers added.
*/
def setMornyInternalErrorHeader ( def setMornyInternalErrorHeader (
`Morny-Internal-Error-Type`: String, `Morny-Internal-Error-Type`: String,
`Morny-Internal-Error-Message`: String, `Morny-Internal-Error-Message`: String,
@ -43,7 +65,7 @@ trait HttpStatus {
.map(_.withContentType(`Content-Type`(MediaType.image.png))) .map(_.withContentType(`Content-Type`(MediaType.image.png)))
/** 500 Internal Server Error */ /** 500 Internal Server Error */
def MornyInternalServerError (): ResponseIO = def MornyInternalServerError (): ResponseIO =
InternalServerError(TelegramImages.IMG_500.get) InternalServerError(TelegramImages.IMG_500.get)
.map(_.withContentType(`Content-Type`(MediaType.image.png))) .map(_.withContentType(`Content-Type`(MediaType.image.png)))

View File

@ -0,0 +1,24 @@
package cc.sukazyo.cono.morny.stickers_get
import java.nio.charset.StandardCharsets
enum StickerType {
case WEBP
case WEBM
case PNG
}
object StickerType {
class UnknownStickerTypeException (message: String)
extends Exception (s"Unknown sticker type: $message")
// @throws[UnknownStickerTypeException]
def check (stickerFile: Array[Byte]): StickerType =
val header = new String(stickerFile.take(50), StandardCharsets.UTF_8)
if header.contains("WEBP") then WEBP
else if header.contains("webm") then WEBM
else if header.contains("PNG") then PNG
else throw UnknownStickerTypeException("Unable to infer file type.")
}

View File

@ -3,12 +3,15 @@ package cc.sukazyo.cono.morny.stickers_get.http
import cats.effect.IO import cats.effect.IO
import cc.sukazyo.cono.morny.core.http.api.HttpService4Api import cc.sukazyo.cono.morny.core.http.api.HttpService4Api
import cc.sukazyo.cono.morny.core.MornyCoeur import cc.sukazyo.cono.morny.core.MornyCoeur
import cc.sukazyo.cono.morny.stickers_get.StickerType
import cc.sukazyo.cono.morny.stickers_get.StickerType.UnknownStickerTypeException
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.File.getContent import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.File.getContent
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.execute import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.execute
import com.pengrad.telegrambot.request.GetFile import com.pengrad.telegrambot.request.GetFile
import com.pengrad.telegrambot.TelegramBot import com.pengrad.telegrambot.TelegramBot
import org.http4s.HttpRoutes import org.http4s.{HttpRoutes, MediaType}
import org.http4s.dsl.io.* import org.http4s.dsl.io.*
import org.http4s.headers.`Content-Type`
import java.io.IOException import java.io.IOException
@ -23,8 +26,16 @@ class StickerService (using coeur: MornyCoeur) extends HttpService4Api {
try { try {
given TelegramBot = coeur.account given TelegramBot = coeur.account
val file = response.file.getContent val file = response.file.getContent
val file_type: MediaType = StickerType.check(file) match
case StickerType.WEBP => MediaType.image.webp
case StickerType.WEBM => MediaType.video.webm
case StickerType.PNG => MediaType.image.png
Ok(file) Ok(file)
.map(_.withContentType(`Content-Type`(file_type)))
} catch { } catch {
case e: UnknownStickerTypeException =>
MornyInternalServerError()
.map(_.setMornyInternalErrorHeader(e))
case e: IOException => case e: IOException =>
MornyServiceUnavailable() MornyServiceUnavailable()
.map(_.setMornyInternalErrorHeader(e)) .map(_.setMornyInternalErrorHeader(e))

View File

@ -4,6 +4,14 @@ object StringEnsure {
extension (str: String) { extension (str: String) {
/** Take the first line of this String.
*
* It will find the first `\n` (unicode 0x0a, aka. LF) or `\n` (unicode 0x0e, aka. CR)
* and take all the chars before it, and ignores all the contents after it.
*/
def firstLine : String =
str.takeWhile(c => (c != '\n') && (c != '\r'))
/** Ensure the string have a length not smaller that the given length. /** Ensure the string have a length not smaller that the given length.
* *
* If the length of the string is smaller than the given length, then the string will be padded * If the length of the string is smaller than the given length, then the string will be padded