net.mamoe.mirai.api.http.context.session.session.kt Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.api.http.context.session
import kotlinx.atomicfu.atomic
import kotlinx.coroutines.*
import net.mamoe.mirai.Bot
import net.mamoe.mirai.api.http.adapter.common.NotVerifiedSessionException
import net.mamoe.mirai.api.http.context.session.manager.SessionManager
import net.mamoe.mirai.api.http.spi.persistence.Persistence
import net.mamoe.mirai.event.Listener
import net.mamoe.mirai.event.events.BotEvent
import kotlin.coroutines.CoroutineContext
/**
* 提供默认 Session 标准实现
*/
class StandardSession constructor(
override val key: String,
override val manager: SessionManager,
) : AbstractSession() {
private val supervisorJob = SupervisorJob()
override val coroutineContext: CoroutineContext = supervisorJob + CoroutineName("session-$key")
private val lifeCounter = atomic(0)
private lateinit var _bot: Bot
private lateinit var _cache: Persistence
@Volatile private var _isAuthed = false
@Volatile private var _closed = false
@Volatile private var _closing = false
override val bot: Bot get() = if (isAuthed) _bot else throw NotVerifiedSessionException
override val sourceCache: Persistence get() = if (isAuthed) _cache else throw NotVerifiedSessionException
override val isAuthed get() = _isAuthed
override val isClosed get() = _closed
override fun authWith(bot: Bot, sourceCache: Persistence) {
if(isAuthed) {
return
}
_isAuthed = true
_bot = bot
_cache = sourceCache
}
override fun ref() {
lifeCounter.incrementAndGet()
}
override fun getRefCount(): Int {
return lifeCounter.value
}
override fun close() {
if (_closing) {
return
}
_closing = true
if (!isClosed && lifeCounter.decrementAndGet() <= 0) {
_closed = true
manager.closeSession(key)
supervisorJob.cancel()
}
_closing = false
}
}
/**
* 提供而外 Job 执行的 Session 包装类
* 1. 提供一个可用的 expired 计时器
* 2. 提供一个用于 Bot 事件监听的监听器
*/
private typealias BotEventHandler = (Session, BotEvent)->Unit
class ListenableSessionWrapper(val session: Session) : Session by session {
companion object Key {
val expiredJob = object : Session.ExtKey{}
val listenerJob = object : Session.ExtKey>{}
val botEventHandler = object : Session.ExtKey{}
}
/**
* 代理方法
* 正常执行认证流程后, 直接开启
*/
override fun authWith(bot: Bot, sourceCache: Persistence) {
session.authWith(bot, sourceCache)
val job = getExtElement(listenerJob)
if (job == null) {
startBotEventListener()
}
}
/**
* 代理方法
* 正常执行关闭流程后, 如果 Session 已关闭, 则停止默认提供的两个 Job
*/
override fun close() {
session.close()
if (session.isClosed) {
getExtElement(expiredJob)?.cancel()
getExtElement(listenerJob)?.cancel()
}
}
fun startExpiredCountdown(expired: Long, callback: (() -> Unit)? = null) {
val element = launch {
delay(expired)
if (!isAuthed) {
close()
callback?.invoke()
}
}
putExtElement(expiredJob, element)
}
fun startBotEventListener(botEventHandler: BotEventHandler? = null) {
check(isAuthed) { "Session is not authed" }
val handler = botEventHandler ?: getExtElement(Key.botEventHandler)
val element = bot.eventChannel.subscribeAlways(BotEvent::class, coroutineContext) { event ->
handler?.invoke(session, event)
}
putExtElement(listenerJob, element)
}
}
/**
* 提供 Session 的默认实现
*/
abstract class AbstractSession : Session {
private val extElement = mutableMapOf, Any?>()
override fun getExtElement(key: Session.ExtKey): T? {
@Suppress("unchecked_cast")
return extElement[key] as T?
}
override fun putExtElement(key: Session.ExtKey, element: T) {
extElement[key] = element
}
override fun removeExtElement(key: Session.ExtKey) {
extElement.remove(key)
}
}
/**
* 通用 Session. 一个 Session 只与一个 Bot 实例绑定.
* Session 可以被多次复用, 通过 ref 开启引用计数器, 并在 close 时检查引用数量
*/
interface Session : CoroutineScope {
val key: String
val bot: Bot
val manager: SessionManager
val isAuthed: Boolean
val isClosed: Boolean
val sourceCache: Persistence
/**
* 通过 Bot 和 cache 完成 Session 的认证过程, 执行 AuthedSession 初始化
*/
fun authWith(bot: Bot, sourceCache: Persistence)
/**
* 引用 Session, 可以使得 Session 在关闭时先检查引用计数
*/
fun ref()
/**
* 获取引用计数的数量
*/
fun getRefCount(): Int
/**
* 关闭当前 Session
*/
fun close()
fun getExtElement(key: ExtKey): T?
fun putExtElement(key: ExtKey, element: T)
fun removeExtElement(key: ExtKey)
interface ExtKey
}