All Downloads are FREE. Search and download functionalities are using the official Maven repository.

love.forte.simbot.component.lovelycat.LovelyCatHttpServer.kt Maven / Gradle / Ivy

/*
 *
 *  * Copyright (c) 2021. ForteScarlet All rights reserved.
 *  * Project  simple-robot
 *  * File     MiraiAvatar.kt
 *  *
 *  * You can contact the author through the following channels:
 *  * github https://github.com/ForteScarlet
 *  * gitee  https://gitee.com/ForteScarlet
 *  * email  [email protected]
 *  * QQ     1149159218
 *
 */
@file:JvmName("lovelycatHttpServers")

package love.forte.simbot.component.lovelycat

import io.ktor.application.*
import io.ktor.features.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.util.pipeline.*
import io.ktor.utils.io.*
import love.forte.simbot.bot.NoSuchBotException
import love.forte.simbot.component.lovelycat.configuration.LovelyCatServerProperties
import love.forte.simbot.component.lovelycat.message.event.LovelyCatParser
import love.forte.simbot.core.TypedCompLogger
import love.forte.simbot.listener.ListenResult
import love.forte.simbot.listener.MsgGetProcessor
import love.forte.simbot.listener.onMsg
import love.forte.simbot.serialization.json.JsonSerializer
import love.forte.simbot.serialization.json.JsonSerializerFactory
import java.io.Closeable
import java.net.InetAddress
import java.time.LocalDateTime
import kotlin.reflect.jvm.jvmErasure


private val jsonContentType = ContentType.parse("application/json")
private val htmlContentType = ContentType.parse("text/html")

/**
 * maybe not use.
 */
private class JsonContentConverter(private val fac: JsonSerializerFactory) : ContentConverter {

    override suspend fun convertForReceive(
        context: PipelineContext,
    ): Any? {
        val channel = context.subject.value as ByteReadChannel
        val message = StringBuilder().apply {
            var readLine: Boolean
            do {
                readLine = channel.readUTF8LineTo(this)
            } while (readLine)
            channel.cancel()
        }.toString()
        return fac.getJsonSerializer(context.subject.typeInfo.jvmErasure.java).fromJson(message)
    }

    override suspend fun convertForSend(
        context: PipelineContext,
        contentType: ContentType,
        value: Any,
    ): Any? {
        val jsonSerializer: JsonSerializer = fac.getJsonSerializer(context.subject.javaClass)
        return jsonSerializer.toJson(context.subject)
    }


}


interface LovelyCatHttpServer : Closeable {
    /**
     * 启动可爱猫服务器。
     */
    @Throws(Exception::class)
    fun start()

    /**
     * 关闭可爱猫服务器。
     */
    override fun close()
}


/**
 * 可爱猫事件监听http server。
 */
public class LovelyCatKtorHttpServer(
    /** 类型转化函数,根据 'Event' 参数获取对应的解析对象 */
    lovelyCatParser: LovelyCatParser,
    applicationEngineFactory: ApplicationEngineFactory,
    apiManager: LovelyCatApiManager,
    jsonSerializerFactory: JsonSerializerFactory,
    msgGetProcessor: MsgGetProcessor,
    private val lovelyCatServerProperties: LovelyCatServerProperties,
) : LovelyCatHttpServer {
    private companion object : TypedCompLogger(LovelyCatKtorHttpServer::class.java)

    private val mapSerializer = jsonSerializerFactory.getJsonSerializer>(Map::class.java)

    private val port get() = lovelyCatServerProperties.port
    private val path get() = lovelyCatServerProperties.path

    private var startedTime: LocalDateTime? = null
        set(value) {
            field = value
            if (value != null) {
                showInfo =
                    """
                    
                    
                    
                    Simbot Lovely Cat Server
                    
                    
                    
                    
                    

Lovely cat server enabled!

Started time: ${value.toString().replaceFirst('T', ' ')}

""".trimIndent() } } private var showInfo: String = """ Simbot Lovely Cat Server

Lovely cat server enabled?

""".trimIndent() /** * the server instance. */ private val server: ApplicationEngine by lazy { embeddedServer(applicationEngineFactory, port) { install(ContentNegotiation) { register(jsonContentType, JsonContentConverter(jsonSerializerFactory)) } if (lovelyCatServerProperties.cors) { install(CORS) } routing { // listen path. post(path) { try { val originalData = call.receive() val params = mapSerializer.fromJson(originalData) val eventType = params["Event"]?.toString() logger.debug("On event request. type: $eventType, originalData: $originalData") if (eventType == null) { // 404. no event. call.respond(HttpStatusCode.NotFound, message = "Param 'Event' not found: Event is Empty.") } else { val botId = (params["robot_wxid"] ?: params["rob_wxid"])?.toString() ?: throw NoSuchBotException("No param 'robot_wxid' or 'rob_wxid' in lovelycat request param.") val api = apiManager[botId] ?: run { val e = IllegalStateException("Cannot found Bot($botId)'s api template. This bot may not be registered.") call.respond(HttpStatusCode.BadRequest, message = e.localizedMessage) if (logger.isDebugEnabled) { logger.error(e.localizedMessage, e) } else { logger.error(e.localizedMessage) } return@post } try { // val parse = // if (parse != null) { lovelyCatParser.type(eventType).let { t -> if (t != null) { msgGetProcessor.onMsg(t) { lovelyCatParser.parse(eventType, originalData, api, jsonSerializerFactory, params) } } else { val msg = lovelyCatParser.parse(eventType, originalData, api, jsonSerializerFactory, params) msg?.let { m -> msgGetProcessor.onMsg(m::class.java) { m } } } }?.let { // ok call.respond(HttpStatusCode.OK, message = ListenResult) } ?: kotlin.run { val respMsg = "Cannot found any event type for event '$eventType'." call.respond(HttpStatusCode.NotFound, message = respMsg) logger.warn("$respMsg response 404.") } // } // ok status. // call.respond(HttpStatusCode.OK) } catch (e: Exception) { call.respond(HttpStatusCode.InternalServerError, message = e.toString()) logger.error("Parse event instance failed by originalData: $originalData", e) } } } catch (ex: Exception) { call.respond(HttpStatusCode.InternalServerError, message = ex.toString()) logger.error("Internal server error.", ex) } } get("/simbot/lovelyCat") { call.respondText(htmlContentType) { showInfo } } } } } override fun start() { server.start() startedTime = LocalDateTime.now() try { val localHost = InetAddress.getLocalHost() val address = localHost.hostAddress logger.info("Lovelycat ktor server started on http://$address:$port$path") logger.info("You can try visit http://$address:$port/simbot/lovelyCat for test.") } catch (e: Exception) { logger.info("Lovelycat ktor server started on http://:$port$path") } } /** * close server. */ override fun close() { server.stop(1000, 6000) } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy