mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-10 04:00:08 +08:00
Cleanup
This commit is contained in:
parent
0717ff77a9
commit
046d8968a4
@ -25,7 +25,7 @@ actual val deviceName: String get() = InetAddress.getLocalHost().hostName
|
||||
* Ktor HttpClient. 不同平台使用不同引擎.
|
||||
*/
|
||||
@KtorExperimentalAPI
|
||||
internal actual val httpClient: HttpClient
|
||||
internal actual val Http: HttpClient
|
||||
get() = HttpClient(CIO)
|
||||
|
||||
/**
|
||||
|
@ -226,6 +226,7 @@ Mirai 22:04:48 : Packet received: UnknownEventPacket(id=00 D6, identity=(2092749
|
||||
* 添加一个好友
|
||||
*
|
||||
* @param lazyMessage 若需要验证请求时的验证消息.
|
||||
* @param lazyRemark 好友备注
|
||||
*/
|
||||
suspend fun ContactSystem.addFriend(id: UInt, lazyMessage: () -> String = { "" }, lazyRemark: () -> String = { "" }): AddFriendResult = bot.withSession {
|
||||
when (CanAddFriendPacket(bot.qqAccount, id, bot.sessionKey).sendAndExpect<CanAddFriendResponse>()) {
|
||||
|
@ -5,7 +5,9 @@ package net.mamoe.mirai.message
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdRequestPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.download
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.Http
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.Volatile
|
||||
|
||||
@ -154,17 +156,6 @@ inline class Image(inline val id: ImageId) : Message {
|
||||
override val stringValue: String get() = "[${id.value}]"
|
||||
override fun toString(): String = stringValue
|
||||
|
||||
/**
|
||||
* 下载这个图片
|
||||
*/
|
||||
suspend fun download(): ExternalImage {
|
||||
// http://101.89.39.21/offpic_new/892185277C8A24AB9BB91AE888A6BC910C4D48CBA84BBB2F0D800761F1DD2F71F205364442C451A82D2F6FAD38CF71A9D65B6873409BD10CCF22BBF7DFA73DD7DA06FBB7386E31E4/0?vuin=1040400290&term=255&srvver=26933&rf=naio
|
||||
// http://61.151.234.54/offpic_new/A47CAC5D3C5EF955A77ECE13DA969A69238167886464C00FD75FFC49A76EF15A1F05ED04BC2DE91190A40048AAF97BB6DFDB25BFB0EFE6A9516DC3BE0532A9A93A87A4C8D2E9729C/0?vuin=1040400290&term=255&srvver=26933&rf=naio
|
||||
|
||||
|
||||
TODO()
|
||||
}
|
||||
|
||||
companion object Key : Message.Key<Image>
|
||||
}
|
||||
|
||||
@ -181,7 +172,11 @@ inline class ImageId(inline val value: String)
|
||||
/**
|
||||
* 图片数据地址.
|
||||
*/
|
||||
inline class ImageLink(inline val value: String)
|
||||
inline class ImageLink(inline val value: String) {
|
||||
|
||||
// TODO: 2019/11/15 应添加更多方法. 避免使用 byte[]
|
||||
suspend fun downloadAsByteArray(): ByteArray = Http.download(value)
|
||||
}
|
||||
|
||||
fun ImageId.checkLength() = check(value.length == 37 || value.length == 42) { "Illegal ImageId length" }
|
||||
fun ImageId.requireLength() = require(value.length == 37 || value.length == 42) { "Illegal ImageId length" }
|
||||
|
@ -31,7 +31,6 @@ import kotlin.coroutines.coroutineContext
|
||||
*/
|
||||
@Suppress("FunctionName", "NOTHING_TO_INLINE")
|
||||
internal inline fun TIMBotNetworkHandler.BotSession(
|
||||
bot: Bot,
|
||||
sessionKey: SessionKey,
|
||||
socket: DataPacketSocketAdapter
|
||||
): BotSession = BotSession(bot, sessionKey, socket, this)
|
||||
@ -42,7 +41,7 @@ internal inline fun TIMBotNetworkHandler.BotSession(
|
||||
*
|
||||
* @author Him188moe
|
||||
*/
|
||||
class BotSession(
|
||||
data class BotSession(
|
||||
val bot: Bot,
|
||||
val sessionKey: SessionKey,
|
||||
val socket: DataPacketSocketAdapter,
|
||||
@ -105,39 +104,11 @@ class BotSession(
|
||||
return deferred
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket][P].
|
||||
* 将能从本函数的返回值 [CompletableDeferred] 接收到所期待的 [P]
|
||||
* 本函数将能帮助实现清晰的包处理逻辑
|
||||
*
|
||||
* 实现方法:
|
||||
* ```kotlin
|
||||
* with(session){
|
||||
* val deferred = ClientPacketXXX(...).sendAndExpectAsync<ServerPacketXXX>()
|
||||
* // do something
|
||||
*
|
||||
* deferred.await() // or deferred.join()
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpectAsync(checkSequence: Boolean = true): Deferred<P> =
|
||||
sendAndExpectAsync<P, P>(checkSequence) { it }
|
||||
|
||||
/**
|
||||
* 发送一个数据包, 并期待接受一个特定的 [ServerPacket][P].
|
||||
* 将调用 [CompletableDeferred.await], 挂起等待接收到指定的包后才返回.
|
||||
* 本函数将能帮助实现清晰的包处理逻辑
|
||||
*
|
||||
* 实现方法:
|
||||
* ```kotlin
|
||||
* with(session){
|
||||
* val packet:AddFriendPacket.Response = AddFriendPacket(...).sendAndExpect<AddFriendPacket.Response>()
|
||||
* }
|
||||
* ```
|
||||
* @sample Bot.addFriend 添加好友
|
||||
*/
|
||||
suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpect(checkSequence: Boolean = true, crossinline block: (P) -> R): R =
|
||||
sendAndExpectAsync<P, R>(checkSequence) { block(it) }.await()
|
||||
suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpect(checkSequence: Boolean = true, crossinline mapper: (P) -> R): R =
|
||||
sendAndExpectAsync<P, R>(checkSequence) { mapper(it) }.await()
|
||||
|
||||
suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpect(checkSequence: Boolean = true): P =
|
||||
sendAndExpectAsync<P, P>(checkSequence) { it }.await()
|
||||
|
@ -62,7 +62,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
||||
handlersLock.withLock {
|
||||
temporaryPacketHandlers.add(temporaryPacketHandler)
|
||||
}
|
||||
temporaryPacketHandler.send(this[ActionPacketHandler].session)
|
||||
temporaryPacketHandler.send(this.session)
|
||||
}
|
||||
|
||||
override suspend fun login(configuration: BotConfiguration): LoginResult {
|
||||
@ -90,7 +90,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
||||
//private | internal
|
||||
private fun onLoggedIn() {
|
||||
require(size == 0) { "Already logged in" }
|
||||
val session = BotSession(bot, sessionKey, socket)
|
||||
val session = BotSession(sessionKey, socket)
|
||||
|
||||
add(ActionPacketHandler(session).asNode(ActionPacketHandler))
|
||||
bot.logger.info("Successfully logged in")
|
||||
|
@ -36,5 +36,5 @@ internal fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHand
|
||||
|
||||
internal open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key === key }.instance as T
|
||||
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key == key }.instance as T
|
||||
}
|
||||
|
@ -9,11 +9,10 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* 包 ID. 除特殊外, [PacketFactory] 都需要这个注解来指定包 ID.
|
||||
*/
|
||||
@Deprecated("Reflection is not supported in JS. Consider to remove")
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class AnnotatedId(
|
||||
annotation class AnnotatedId( // 注解无法在 JS 平台使用, 但现在暂不需要考虑 JS
|
||||
val id: KnownPacketId
|
||||
)
|
||||
|
||||
@ -40,7 +39,7 @@ annotation class CorrespondingEvent(
|
||||
internal annotation class PacketVersion(val date: String, val timVersion: String)
|
||||
|
||||
/**
|
||||
* 带有这个注解的 [Packet], 将不会被记录在 log 中.
|
||||
* 带有这个注解的 [Packet] 将不会被记录在 log 中.
|
||||
*/
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
|
@ -26,7 +26,7 @@ abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val d
|
||||
*/
|
||||
private val annotatedId: AnnotatedId
|
||||
get() = (this::class.annotations.firstOrNull { it is AnnotatedId } as? AnnotatedId)
|
||||
?: error("Annotation AnnotatedId not found")
|
||||
?: error("Annotation AnnotatedId not found for class ${this::class.simpleName}")
|
||||
|
||||
/**
|
||||
* 包 ID.
|
||||
|
@ -205,7 +205,7 @@ object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
|
||||
/**
|
||||
* 备注名
|
||||
*/
|
||||
remark: String,
|
||||
remark: String, //// TODO: 2019/11/15 无备注的情况
|
||||
key: FriendAdditionKey
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey) {
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.contact.withSession
|
||||
import net.mamoe.mirai.message.Image
|
||||
import net.mamoe.mirai.message.ImageLink
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageIdDownloadLinkRequestPacket.ImageLinkResponse
|
||||
import net.mamoe.mirai.network.sessionKey
|
||||
import net.mamoe.mirai.qqAccount
|
||||
|
||||
|
||||
suspend fun QQ.getLink(image: Image): ImageLink = withSession {
|
||||
FriendImageIdDownloadLinkRequestPacket(bot.qqAccount, bot.sessionKey, id, image.id).sendAndExpect<ImageLinkResponse>().link
|
||||
}
|
||||
|
||||
suspend inline fun QQ.downloadAsByteArray(image: Image): ByteArray = this.getLink(image).downloadAsByteArray()
|
@ -12,6 +12,8 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
|
||||
@AnnotatedId(KnownPacketId.SEND_GROUP_MESSAGE)
|
||||
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2 (21173)")
|
||||
object SendGroupMessagePacket : SessionPacketFactory<SendGroupMessagePacket.Response>() {
|
||||
operator fun invoke(
|
||||
botQQ: UInt,
|
||||
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
import net.mamoe.mirai.message.ImageLink
|
||||
import net.mamoe.mirai.message.requireLength
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
@ -22,8 +23,8 @@ import net.mamoe.mirai.network.protocol.tim.packet.event.EventPacket
|
||||
import net.mamoe.mirai.network.qqAccount
|
||||
import net.mamoe.mirai.qqAccount
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.Http
|
||||
import net.mamoe.mirai.utils.configureBody
|
||||
import net.mamoe.mirai.utils.httpClient
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.withSession
|
||||
import kotlin.coroutines.coroutineContext
|
||||
@ -47,7 +48,7 @@ suspend fun Group.uploadImage(image: ExternalImage): ImageId = withSession {
|
||||
|
||||
withContext(userContext) {
|
||||
when (response) {
|
||||
is GroupImageIdRequestPacket.Response.RequireUpload -> httpClient.postImage(
|
||||
is GroupImageIdRequestPacket.Response.RequireUpload -> Http.postImage(
|
||||
htcmd = "0x6ff0071",
|
||||
uin = bot.qqAccount,
|
||||
groupId = GroupId(id),
|
||||
@ -79,7 +80,7 @@ suspend fun QQ.uploadImage(image: ExternalImage): ImageId = bot.withSession {
|
||||
.sendAndExpectAsync<FriendImageIdRequestPacket.Response, ImageId> {
|
||||
return@sendAndExpectAsync when (it) {
|
||||
is FriendImageIdRequestPacket.Response.RequireUpload -> {
|
||||
httpClient.postImage(
|
||||
Http.postImage(
|
||||
htcmd = "0x6ff0070",
|
||||
uin = bot.qqAccount,
|
||||
groupId = null,
|
||||
@ -132,11 +133,11 @@ internal suspend inline fun HttpClient.postImage(
|
||||
imageInput.close()
|
||||
}
|
||||
|
||||
|
||||
internal suspend inline fun HttpClient.download(
|
||||
url: String
|
||||
): ByteArray = get<HttpResponse>(url).readBytes() // TODO 不知道为什么找不到 `ByteReadChannel`.
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* 似乎没有必要. 服务器的返回永远都是 01 00 00 00 02 00 00
|
||||
@ -195,7 +196,7 @@ object SubmitImageFilenamePacket : PacketFactory {
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.FRIEND_IMAGE_ID)
|
||||
@PacketVersion(date = "2019.11.14", timVersion = "2.3.2 (21173)")
|
||||
object FriendImageIdDownloadLinkRequestPacket : SessionPacketFactory<FriendImageIdDownloadLinkRequestPacket.DownloadLink>() {
|
||||
object FriendImageIdDownloadLinkRequestPacket : SessionPacketFactory<FriendImageIdDownloadLinkRequestPacket.ImageLinkResponse>() {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
@ -239,14 +240,14 @@ object FriendImageIdDownloadLinkRequestPacket : SessionPacketFactory<FriendImage
|
||||
/**
|
||||
* 图片下载链接. 直接 'get' 请求即可
|
||||
*/
|
||||
data class DownloadLink(
|
||||
data class ImageLinkResponse(
|
||||
val imageId: ImageId,
|
||||
val link: String
|
||||
val link: ImageLink
|
||||
) : Packet
|
||||
|
||||
// TODO: 2019/11/14 需要跟 RequestId packet 合并. 因为现行结构无法分别处理; 或者考虑修改结构(不推荐)
|
||||
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): DownloadLink {
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): ImageLinkResponse {
|
||||
//00 00 00 08 00 00
|
||||
// [02 2B]
|
||||
// 12 [06] 98 01 02 A0 01 00
|
||||
@ -282,7 +283,7 @@ object FriendImageIdDownloadLinkRequestPacket : SessionPacketFactory<FriendImage
|
||||
|
||||
val link = readUVarIntLVString()
|
||||
discard()
|
||||
return DownloadLink(imageId, link)
|
||||
return ImageLinkResponse(imageId, ImageLink(link))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse,
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): LoginResponse {
|
||||
val size = remaining.toInt()
|
||||
return when {
|
||||
size == 229 || size == 271 || size == 207 -> {
|
||||
size == 229 || size == 271 || size == 207 || size == 165 /* TODO CHECK 165 */ -> {
|
||||
discardExact(5)//01 00 1E 00 10
|
||||
val privateKeyUpdate = PrivateKey(readBytes(0x10))
|
||||
discardExact(4)//00 06 00 78
|
||||
@ -243,6 +243,8 @@ object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse,
|
||||
279, 495, 551, 487 -> LoginResult.DEVICE_LOCK
|
||||
343, 359 -> LoginResult.TAKEN_BACK
|
||||
|
||||
// 165: 01 00 1E 00 10 72 36 7B 6B 6D 78 3A 4B 63 7B 47 5B 68 3E 21 59 00 06 00 78 34 F6 F9 49 AA 13 F5 F5 01 36 13 E1 4C F7 0F 25 C1 2C 10 75 CA 69 E9 12 B3 6D F4 A7 59 60 FF 01 03 73 28 47 A3 2A B8 46 C3 92 24 D5 8A AE 8B C2 45 0C 31 27 B5 17 9E 22 13 59 AF B4 CC F6 E3 3A 91 60 13 21 11 3C 25 D9 50 F4 23 C6 06 1D F4 15 41 BA 5D 7B 66 26 96 EB 0E 04 14 8E 5B D4 33 6E B8 5D E7 10 3A 0E EF 96 B1 D4 22 E4 74 48 A7 1D 3A 46 7D E6 EF 1F 6B 69 01 15 00 10 6F 99 48 5E 98 AE D3 4B F8 35 63 1D 70 EE 6D 82
|
||||
|
||||
else -> {
|
||||
MiraiLogger.error("login response packet size = $size, data=${this.readRemainingBytes().toUHexString()}")
|
||||
LoginResult.UNKNOWN
|
||||
|
@ -43,7 +43,7 @@ expect fun localIpAddress(): String
|
||||
/**
|
||||
* Ktor HttpClient. 不同平台使用不同引擎.
|
||||
*/
|
||||
internal expect val httpClient: HttpClient
|
||||
internal expect val Http: HttpClient
|
||||
|
||||
|
||||
// FIXME: 2019/10/28 这个方法不是很好的实现
|
||||
|
@ -55,7 +55,7 @@ actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(host
|
||||
|
||||
actual fun localIpAddress(): String = InetAddress.getLocalHost().hostAddress
|
||||
|
||||
internal actual val httpClient: HttpClient = HttpClient(CIO)
|
||||
internal actual val Http: HttpClient = HttpClient(CIO)
|
||||
|
||||
internal actual fun HttpRequestBuilder.configureBody(
|
||||
inputSize: Long,
|
||||
|
@ -9,6 +9,8 @@ dependencies {
|
||||
api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlin_version
|
||||
api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: coroutines_version
|
||||
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-io:$kotlinxio_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-io:$coroutinesio_version")
|
||||
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.62'
|
||||
implementation 'org.jsoup:jsoup:1.12.1'
|
||||
}
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
package demo.gentleman
|
||||
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.addFriend
|
||||
@ -12,7 +14,11 @@ import net.mamoe.mirai.event.Subscribable
|
||||
import net.mamoe.mirai.event.subscribeAlways
|
||||
import net.mamoe.mirai.event.subscribeMessages
|
||||
import net.mamoe.mirai.login
|
||||
import net.mamoe.mirai.message.Image
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.downloadAsByteArray
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.FriendMessage
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
|
||||
import net.mamoe.mirai.utils.currentTime
|
||||
import java.io.File
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -52,21 +58,23 @@ suspend fun main() {
|
||||
sender.profile.await().toString()
|
||||
}
|
||||
|
||||
/*
|
||||
has<Image> {
|
||||
reply(message)
|
||||
}*/
|
||||
if (this is FriendMessage) {
|
||||
withContext(IO) {
|
||||
reply(message[Image] + " downloading")
|
||||
sender.downloadAsByteArray(message[Image]).inputStream()
|
||||
.transferTo(File(System.getProperty("user.dir", "testDownloadedImage${currentTime}.png")).outputStream())
|
||||
reply(message[Image] + " downloaded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startsWith("随机图片", removePrefix = true) {
|
||||
try {
|
||||
repeat(it.toIntOrNull() ?: 1) {
|
||||
GlobalScope.launch {
|
||||
delay(Random.Default.nextLong(100, 1000))
|
||||
Gentlemen.provide(subject).receive().image.await().send()
|
||||
}
|
||||
repeat(it.toIntOrNull() ?: 1) {
|
||||
GlobalScope.launch {
|
||||
delay(Random.Default.nextLong(100, 1000))
|
||||
Gentlemen.provide(subject).receive().image.await().send()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
reply(e.message ?: "exception: null")
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user