mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-25 21:23:55 +08:00
Platform adjustment
This commit is contained in:
parent
00959ab291
commit
8bab12854b
mirai-core/src
androidMain/kotlin/net/mamoe/mirai
event
network/protocol/tim
utils
commonMain/kotlin/net.mamoe.mirai
jvmMain/kotlin/net/mamoe/mirai
event
network/protocol/tim
task
utils
mirai-demos/mirai-demo-android/src/main/kotlin/net/mamoe/mirai/demo
@ -0,0 +1,8 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
/**
|
||||
* 直接抛出异常. 需自行处理验证码
|
||||
*/
|
||||
actual var DefaultCaptchaSolver: CaptchaSolver = {
|
||||
error("No CaptchaSolver found. BotConfiguration.captchaSolver should be assigned manually")
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import kotlinx.io.core.IoBuffer
|
||||
|
||||
internal actual suspend fun solveCaptcha(captchaBuffer: IoBuffer): String? {
|
||||
TODO("Unsupported yet")
|
||||
}
|
@ -10,7 +10,7 @@ import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
|
||||
@ -71,7 +71,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
|
||||
*/
|
||||
@JvmOverloads
|
||||
suspend fun reinitializeNetworkHandler(
|
||||
configuration: BotNetworkConfiguration,
|
||||
configuration: BotConfiguration,
|
||||
cause: Throwable? = null
|
||||
): LoginResult {
|
||||
logger.info("Initializing BotNetworkHandler")
|
||||
|
@ -8,7 +8,7 @@ import net.mamoe.mirai.network.BotSession
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.network.session
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.internal.PositiveNumbers
|
||||
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
|
||||
|
||||
@ -52,12 +52,12 @@ suspend inline fun Bot.sendPacket(packet: OutgoingPacket) = this.network.sendPac
|
||||
/**
|
||||
* 使用在默认配置基础上修改的配置进行登录
|
||||
*/
|
||||
suspend inline fun Bot.login(noinline configuration: BotNetworkConfiguration.() -> Unit): LoginResult = this.network.login(BotNetworkConfiguration().apply(configuration))
|
||||
suspend inline fun Bot.login(noinline configuration: BotConfiguration.() -> Unit): LoginResult = this.network.login(BotConfiguration().apply(configuration))
|
||||
|
||||
/**
|
||||
* 使用默认的配置 ([BotNetworkConfiguration.Default]) 登录
|
||||
* 使用默认的配置 ([BotConfiguration.Default]) 登录
|
||||
*/
|
||||
suspend inline fun Bot.login(): LoginResult = this.network.login(BotNetworkConfiguration.Default)
|
||||
suspend inline fun Bot.login(): LoginResult = this.network.login(BotConfiguration.Default)
|
||||
|
||||
/**
|
||||
* 取得机器人的 QQ 号
|
||||
|
@ -13,7 +13,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.io.PlatformDatagramChannel
|
||||
|
||||
/**
|
||||
@ -62,7 +62,7 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : CoroutineScope {
|
||||
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果
|
||||
* 本函数将挂起直到登录成功.
|
||||
*/
|
||||
suspend fun login(configuration: BotNetworkConfiguration): LoginResult
|
||||
suspend fun login(configuration: BotConfiguration): LoginResult
|
||||
|
||||
/**
|
||||
* 添加一个临时包处理器, 并发送相应的包
|
||||
|
@ -22,10 +22,9 @@ import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.*
|
||||
import net.mamoe.mirai.network.session
|
||||
import net.mamoe.mirai.qqAccount
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.OnlineStatus
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.solveCaptcha
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@ -66,7 +65,7 @@ internal class TIMBotNetworkHandler internal constructor(override val bot: Bot)
|
||||
temporaryPacketHandler.send(this[ActionPacketHandler].session)
|
||||
}
|
||||
|
||||
override suspend fun login(configuration: BotNetworkConfiguration): LoginResult =
|
||||
override suspend fun login(configuration: BotConfiguration): LoginResult =
|
||||
withContext(this.coroutineContext) {
|
||||
TIMProtocol.SERVER_IP.forEach { ip ->
|
||||
bot.logger.info("Connecting server $ip")
|
||||
@ -124,7 +123,7 @@ internal class TIMBotNetworkHandler internal constructor(override val bot: Bot)
|
||||
|
||||
override suspend fun sendPacket(packet: OutgoingPacket) = socket.sendPacket(packet)
|
||||
|
||||
internal inner class BotSocketAdapter(override val serverIp: String, val configuration: BotNetworkConfiguration) :
|
||||
internal inner class BotSocketAdapter(override val serverIp: String, val configuration: BotConfiguration) :
|
||||
DataPacketSocketAdapter {
|
||||
|
||||
override val channel: PlatformDatagramChannel = PlatformDatagramChannel(serverIp, 8000)
|
||||
@ -290,7 +289,7 @@ internal class TIMBotNetworkHandler internal constructor(override val bot: Bot)
|
||||
/**
|
||||
* 处理登录过程
|
||||
*/
|
||||
inner class LoginHandler(private val configuration: BotNetworkConfiguration) {
|
||||
inner class LoginHandler(private val configuration: BotConfiguration) {
|
||||
private lateinit var token00BA: ByteArray
|
||||
private lateinit var token0825: ByteArray//56
|
||||
private var loginTime: Int = 0
|
||||
@ -329,7 +328,7 @@ internal class TIMBotNetworkHandler internal constructor(override val bot: Bot)
|
||||
else -> {
|
||||
error("No decrypter found")
|
||||
}
|
||||
} as? D ?: error("Internal error: could not cast decrypter found for factory to class Decrypter")
|
||||
} as? D ?: error("Internal error: could not cast decrypter which is found for factory to class Decrypter")
|
||||
|
||||
suspend fun onPacketReceived(packet: Any) {//complex function, but it doesn't matter
|
||||
when (packet) {
|
||||
@ -412,10 +411,10 @@ internal class TIMBotNetworkHandler internal constructor(override val bot: Bot)
|
||||
this.token00BA = packet.token00BA
|
||||
|
||||
if (packet.transmissionCompleted) {
|
||||
val code = solveCaptcha(captchaCache!!)
|
||||
val code = configuration.captchaSolver(bot, captchaCache!!)
|
||||
|
||||
this.captchaCache = null
|
||||
if (code == null) {
|
||||
if (code == null || code.length != 4) {
|
||||
this.captchaSectionId = 1//意味着正在刷新验证码
|
||||
socket.sendPacket(CaptchaPacket.Refresh(bot.qqAccount, token0825))
|
||||
} else {
|
||||
|
@ -2,14 +2,29 @@ package net.mamoe.mirai.utils
|
||||
|
||||
import com.soywiz.klock.TimeSpan
|
||||
import com.soywiz.klock.seconds
|
||||
import kotlinx.io.core.IoBuffer
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.TouchPacket.TouchResponse
|
||||
import kotlin.jvm.JvmField
|
||||
|
||||
/**
|
||||
* 验证码处理器. 需阻塞直到处理完成验证码.
|
||||
*
|
||||
* 返回
|
||||
*/
|
||||
typealias CaptchaSolver = suspend Bot.(IoBuffer) -> String?
|
||||
|
||||
/**
|
||||
* 在各平台实现的默认的验证码处理器.
|
||||
*/
|
||||
expect var DefaultCaptchaSolver: CaptchaSolver
|
||||
|
||||
/**
|
||||
* 网络和连接配置
|
||||
*/
|
||||
class BotNetworkConfiguration {
|
||||
class BotConfiguration {
|
||||
/**
|
||||
* 等待 [TouchRespnose] 的时间
|
||||
* 等待 [TouchResponse] 的时间
|
||||
*/
|
||||
var touchTimeout: TimeSpan = 2.seconds
|
||||
/**
|
||||
@ -28,11 +43,16 @@ class BotNetworkConfiguration {
|
||||
*/
|
||||
var heartbeatTimeout: TimeSpan = 2.seconds
|
||||
|
||||
/**
|
||||
* 验证码处理器
|
||||
*/
|
||||
var captchaSolver: CaptchaSolver = DefaultCaptchaSolver
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* 默认的配置实例
|
||||
*/
|
||||
@JvmField
|
||||
val Default = BotNetworkConfiguration()
|
||||
val Default = BotConfiguration()
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import kotlinx.io.core.IoBuffer
|
||||
|
||||
/**
|
||||
* 让用户处理验证码
|
||||
*
|
||||
* @return 用户输入得到的验证码. 非 null 时一定 `length==4`.
|
||||
*/
|
||||
internal expect suspend fun solveCaptcha(captchaBuffer: IoBuffer): String?
|
@ -1,135 +0,0 @@
|
||||
package net.mamoe.mirai.task
|
||||
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.Future
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Predicate
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
|
||||
/*
|
||||
class MiraiTaskManager private constructor() {
|
||||
|
||||
private val pool: MiraiThreadPool
|
||||
|
||||
init {
|
||||
this.pool = MiraiThreadPool()
|
||||
}
|
||||
|
||||
/**
|
||||
* 基础Future处理
|
||||
*/
|
||||
|
||||
fun execute(runnable: Runnable) {
|
||||
this.execute(runnable, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun execute(runnable: Runnable, handler: MiraiTaskExceptionHandler) {
|
||||
this.pool.execute {
|
||||
try {
|
||||
runnable.run()
|
||||
} catch (e: Exception) {
|
||||
handler.onHandle(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun <D> submit(callable: Callable<D>): Future<D> {
|
||||
return this.submit(callable, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun <D> submit(callable: Callable<D>, handler: MiraiTaskExceptionHandler): Future<D> {
|
||||
return this.pool.submit<D> {
|
||||
try {
|
||||
callable.call()
|
||||
} catch (e: Throwable) {
|
||||
handler.onHandle(e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步任务
|
||||
*/
|
||||
fun <D> ansycTask(callable: Callable<D>, callback: Consumer<D>) {
|
||||
this.ansycTask(callable, callback, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun <D> ansycTask(callable: Callable<D>, callback: Consumer<D>, handler: MiraiTaskExceptionHandler) {
|
||||
this.pool.execute {
|
||||
try {
|
||||
callback.accept(callable.call())
|
||||
} catch (e: Throwable) {
|
||||
handler.onHandle(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
*/
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long) {
|
||||
this.repeatingTask(runnable, intervalMillis, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long, handler: MiraiTaskExceptionHandler) {
|
||||
this.repeatingTask<Runnable>(runnable, intervalMillis, { a -> true }, handler)
|
||||
}
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long, times: Int) {
|
||||
this.repeatingTask(runnable, intervalMillis, times, MiraiTaskExceptionHandler.printing())
|
||||
}
|
||||
|
||||
fun repeatingTask(runnable: Runnable, intervalMillis: Long, times: Int, handler: MiraiTaskExceptionHandler) {
|
||||
val integer = AtomicInteger(times - 1)
|
||||
this.repeatingTask<Runnable>(
|
||||
runnable, intervalMillis, { a -> integer.getAndDecrement() > 0 }, handler
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun <D : Runnable> repeatingTask(runnable: D, intervalMillis: Long, shouldContinue: Predicate<D>, handler: MiraiTaskExceptionHandler) {
|
||||
Thread {
|
||||
do {
|
||||
this.pool.execute {
|
||||
try {
|
||||
runnable.run()
|
||||
} catch (e: Exception) {
|
||||
handler.onHandle(e)
|
||||
}
|
||||
}
|
||||
try {
|
||||
Thread.sleep(intervalMillis)
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} while (shouldContinue.test(runnable))
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun deletingTask(runnable: Runnable, intervalMillis: Long) {
|
||||
Thread {
|
||||
try {
|
||||
Thread.sleep(intervalMillis)
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
this.pool.execute(runnable)
|
||||
}.start()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val instance = MiraiTaskManager()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
@ -1,35 +0,0 @@
|
||||
package net.mamoe.mirai.task
|
||||
|
||||
import net.mamoe.mirai.Mirai
|
||||
|
||||
import java.io.Closeable
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
*/
|
||||
class MiraiThreadPool internal constructor()/*super(0,
|
||||
Integer.MAX_VALUE,
|
||||
60L,
|
||||
TimeUnit.SECONDS,
|
||||
new SynchronousQueue<>()
|
||||
);*/ : ScheduledThreadPoolExecutor(10), Closeable {
|
||||
|
||||
|
||||
override fun close() {
|
||||
this.shutdown()
|
||||
if (!this.isShutdown) {
|
||||
this.shutdownNow()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val instance = MiraiThreadPool()
|
||||
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
println(Mirai.VERSION)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -6,42 +6,40 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.IoBuffer
|
||||
import java.awt.Image
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.File
|
||||
import javax.imageio.ImageIO
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
/**
|
||||
* 让用户处理验证码
|
||||
* 平台默认的验证码识别器.
|
||||
*
|
||||
* @return 用户输入得到的验证码
|
||||
* 可被修改, 除覆盖配置外全局生效.
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
internal actual suspend fun solveCaptcha(captchaBuffer: IoBuffer): String? = captchaLock.withLock {
|
||||
val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() }
|
||||
withContext(Dispatchers.IO) {
|
||||
tempFile.createNewFile()
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
MiraiLogger.info("需要验证码登录, 验证码为 4 字母")
|
||||
try {
|
||||
tempFile.writeChannel().writeFully(captchaBuffer)
|
||||
MiraiLogger.info("若看不清字符图片, 请查看 ${tempFile.absolutePath}")
|
||||
} catch (e: Exception) {
|
||||
MiraiLogger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片")
|
||||
}
|
||||
actual var DefaultCaptchaSolver: CaptchaSolver = {
|
||||
captchaLock.withLock {
|
||||
val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() }
|
||||
withContext(Dispatchers.IO) {
|
||||
tempFile.createNewFile()
|
||||
@Suppress("EXPERIMENTAL_API_USAGE")
|
||||
MiraiLogger.info("需要验证码登录, 验证码为 4 字母")
|
||||
try {
|
||||
tempFile.writeChannel().writeFully(it)
|
||||
MiraiLogger.info("若看不清字符图片, 请查看 ${tempFile.absolutePath}")
|
||||
} catch (e: Exception) {
|
||||
MiraiLogger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片")
|
||||
}
|
||||
|
||||
MiraiLogger.info(ImageIO.read(tempFile.inputStream()).createCharImg())
|
||||
MiraiLogger.info(ImageIO.read(tempFile.inputStream()).createCharImg())
|
||||
}
|
||||
MiraiLogger.info("若要更换验证码, 请直接回车")
|
||||
readLine()?.takeUnless { it.isEmpty() || it.length != 4 }
|
||||
}
|
||||
MiraiLogger.info("若要更换验证码, 请直接回车")
|
||||
readLine()?.takeUnless { it.isEmpty() || it.length != 4 }
|
||||
}
|
||||
|
||||
private val captchaLock = Mutex()
|
||||
|
||||
private val captchaLock = Mutex()
|
||||
|
||||
/**
|
||||
* @author NaturalHG
|
||||
@ -60,7 +58,7 @@ internal fun BufferedImage.createCharImg(outputWidth: Int = 100, ignoreRate: Dou
|
||||
return (r * 30 + g * 59 + b * 11 + 50) / 100
|
||||
}
|
||||
|
||||
fun grayCompare(g1: Int, g2: Int): Boolean = min(g1, g2).toDouble() / max(g1, g2) >= ignoreRate
|
||||
fun grayCompare(g1: Int, g2: Int): Boolean = kotlin.math.min(g1, g2).toDouble() / kotlin.math.max(g1, g2) >= ignoreRate
|
||||
|
||||
val background = gray(image.getRGB(0, 0))
|
||||
|
@ -41,7 +41,14 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
val bot = Bot(qq, password).apply { login().requireSuccess() }
|
||||
val bot = Bot(qq, password).apply {
|
||||
login {
|
||||
captchaSolver = {
|
||||
|
||||
"ABCD"
|
||||
}
|
||||
}.requireSuccess()
|
||||
}
|
||||
|
||||
bot.subscribeFriendMessages {
|
||||
"Hello" reply "Hello Mirai!"
|
||||
|
Loading…
Reference in New Issue
Block a user