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

com.simbot.component.mirai.MiraiBots.kt Maven / Gradle / Ivy

There is a newer version: 1.11.0-1.17-Final
Show newest version
/*
 * Copyright (c) 2020. ForteScarlet All rights reserved.
 * Project  component-mirai (Codes other than Mirai)
 * File     MiraiBots.kt (Codes other than Mirai)
 *
 * You can contact the author through the following channels:
 * github https://github.com/ForteScarlet
 * gitee  https://gitee.com/ForteScarlet
 * email  [email protected]
 * QQ     1149159218
 *
 * The Mirai code is copyrighted by mamoe-mirai
 * you can see mirai at https://github.com/mamoe/mirai
 *
 *
 */

package com.simbot.component.mirai

import com.forte.qqrobot.MsgProcessor
import com.forte.qqrobot.bot.BotInfo
import com.forte.qqrobot.bot.BotSender
import com.forte.qqrobot.bot.LoginInfo
import com.forte.qqrobot.log.QQLog
import com.simbot.component.mirai.messages.MiraiLoginInfo
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.Bot
import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.closeAndJoin
import net.mamoe.mirai.join
import net.mamoe.mirai.utils.BotConfiguration
import java.util.concurrent.ConcurrentHashMap

/**
 * 记录登录的bot列表以及监听注册的状态
 * 一般会通过[com.forte.qqrobot.bot.BotManager]类记录注册信息,此处记录实际的Bot信息
 */
object MiraiBots {

    /** 记录登录的bot */
    private val bots: MutableMap = ConcurrentHashMap()

    /** 消息处理器 */
    @Volatile
    private lateinit var msgProcessor: MsgProcessor

    /** 未注册监听的bot列表 */
    private val noListenBots: MutableMap = ConcurrentHashMap()


    /** 增加一个bot,如果此bot已经存在则会抛出异常 */
    operator fun set(id: String, bot: MiraiBotInfo){
        bots[id] = bot
        // 注册或等待
        registerOrWait(bot)
    }

    /**
     * 尝试获取一个bot,如果获取不到则会尝试构建一个。
     * 需要在从BotManager中验证存在后在通过此获取,否则BotManager中可能会缺失
     */
    fun get(info: BotInfo, botConfiguration: (String) -> BotConfiguration = { BotConfiguration.Default }): MiraiBotInfo {
        val id = info.botCode
        // 构建一个,构建失败会抛出异常
        val miraiBotInfo = bots[id]
        return if(miraiBotInfo == null){
            // 不存在,尝试获取
            val newBotInfo = MiraiBotInfo(info, botConfiguration(id))
            // 注册/等待并返回
            registerOrWait(newBotInfo)
            newBotInfo
        }else{
            miraiBotInfo
        }
    }

    /** 注册监听或等待 */
    private fun registerOrWait(info: MiraiBotInfo){
        if(started()){
            // 启动了监听,注册
            registerListen(info)
        }else{
            noListenBots[info.botCode] = info
        }
    }

    /** get 根据id获取一个botInfo */
    operator fun get(id: String) = bots[id]


    /** 移除一个bot,移除的时候记得登出 */
    fun remove(id: String): MiraiBotInfo? = bots.remove(id)


    /** 是否启用了监听,即判断消息处理器是否初始化 */
    fun started(): Boolean = ::msgProcessor.isInitialized


    /** 启用监听 */
    fun startListen(msgProcessor: MsgProcessor){
        // 初始化
        this.msgProcessor = msgProcessor
        // 等待区注册监听
        noListenBots.forEach{
            registerListen(it.value)
            val bot = it.value.bot
            QQLog.debug("run.cache.contact", bot.id.toString())
            ContactCache.cache(bot)
        }
        // 清空等待区
        noListenBots.clear()
    }

    /** 注册监听 */
    private fun registerListen(info: MiraiBotInfo){
        info.register(msgProcessor)
    }

    /** 等待所有bot下线 */
    suspend fun joinAll(){
        while(bots.isNotEmpty()){
            delay(2000)
            bots.forEach{
                it.value.join()
            }
        }
    }

    fun closeAll(){
        bots.forEach { it.value.close() }
        bots.clear()
    }


}


/**
 * miraiBotInfo, 传入bot的账号密码,内部会创建并启动一个Bot
 * @param id                // 账号
 * @param pwd               // 密码
 * @param botConfiguration  // 账号配置
 *
 */
class MiraiBotInfo(private val id: String,
                   private val pwd: String,
                   private val botConfiguration: BotConfiguration
): BotInfo {

    /** 使用info的构造 */
    constructor(botInfo: BotInfo, botConfiguration: BotConfiguration): this(botInfo.botCode, botInfo.path, botConfiguration)

    /** bot信息 */
    val bot: Bot
    /** 送信器 */
    val botSender: BotSender
    /**  登录信息 */
    val loginInfo: LoginInfo

    init {
        // 先验证此bot是否已经被注册或是否仍然在线
        val botGet = MiraiBots[id]
        if(botGet != null && botGet.bot.isOnline){
            // 已经注册
            throw IllegalArgumentException("id [$id] has already login")
        }
        // 输入账号密码,填入配置,阻塞登录
        bot = runBlocking { Bot(id.toLong(), pwd, botConfiguration).alsoLogin() }
        // 将自己记录在MiraiBots中
        MiraiBots[id] = this

        // bot sender
        botSender = BotSender(MiraiBotSender(bot))

        // login info
        loginInfo = MiraiLoginInfo(bot)
    }

    /**
     * 获取此bot的上报信息
     * 此处为账号的密码
     * @return bot上报信息
     */
    override fun getPath(): String = pwd

    /**
     * 获取此账号的登录信息
     * @return 获取登录信息
     */
    override fun getInfo(): LoginInfo = loginInfo

    /**
     * 获取Bot的账号信息
     * @return Bot账号信息
     */
    override fun getBotCode(): String = id

    /**
     * 获取当前bot所对应的送信器
     * @return 当前账号送信器
     */
    override fun getSender(): BotSender = botSender

    /**
     * 关闭bot,并从[MiraiBots]中移除此bot信息
     */
    override fun close() {
        // 关闭bot,并移除其相关信息
        runBlocking {
            // close and remove
            bot.closeAndJoin()
            MiraiBots.remove(id)
        }
    }

    /** 一直等待到bot下线 */
    suspend fun join(){
        bot.join()
    }

}










© 2015 - 2025 Weber Informatics LLC | Privacy Policy