Commit 93607e49 authored by Him188's avatar Him188

Platform specified Contact

parent ad43a92b
# Mirai # Mirai
[![HitCount](http://hits.dwyl.io/him188/mamoe/mirai.svg)](http://hits.dwyl.io/him188/mamoe/mirai) [![HitCount](http://hits.dwyl.io/him188/mamoe/mirai.svg)](http://hits.dwyl.io/him188/mamoe/mirai)
一个以 **TIM QQ协议(非web)** 驱动的QQ机器人服务端核心 一个以 **TIM PC协议(非web)** 驱动的跨平台QQ机器人服务端核心, 虽然目前仅支持 JVM
采用服务端-插件模式运行,同时提供独立的核心库 采用服务端-插件模式运行,同时提供独立的跨平台核心库.
Mirai 的所有模块均开源 Mirai 的所有模块均开源
项目处于开发阶段,学生无法每日大量更新。 项目处于开发阶段, 还有很多未完善的地方. 欢迎任何的代码贡献, 或是 issue.
项目还有很多未完善的地方, 欢迎任何的代码贡献, 或是 issue.
部分协议来自网络上开源项目 部分协议来自网络上开源项目
**一切开发旨在学习,请勿用于非法用途** **一切开发旨在学习,请勿用于非法用途**
...@@ -22,7 +21,8 @@ Mirai 的所有模块均开源 ...@@ -22,7 +21,8 @@ Mirai 的所有模块均开源
3. Run demo main [Demo 1 Main](mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt#L22) 3. Run demo main [Demo 1 Main](mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt#L22)
### 事件 ### 事件
#### Kotlin
#### 使用 Kotlin
这里只演示进行不终止地监听。 这里只演示进行不终止地监听。
##### Top-level reified ##### Top-level reified
多数情况下这是最好的方式。 多数情况下这是最好的方式。
...@@ -35,7 +35,7 @@ subscribeAlways<FriendMessageEvent>{ ...@@ -35,7 +35,7 @@ subscribeAlways<FriendMessageEvent>{
``` ```
##### DSL ##### DSL
查看更多: [ListenerBuilder](mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/Subscribers.kt#L69) 查看更多: [ListenerBuilder](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt#L87)
```kotlin ```kotlin
inline fun <reified E: Event> subscribeAll(builder: ListenerBuilder.() -> Unit) inline fun <reified E: Event> subscribeAll(builder: ListenerBuilder.() -> Unit)
...@@ -66,38 +66,25 @@ FriendMessageEvent::class.subscribeAlways{ ...@@ -66,38 +66,25 @@ FriendMessageEvent::class.subscribeAlways{
![AYWVE86P](.github/A%7DYWVE860U%28%25YQD%24R1GB1%5BP.png) ![AYWVE86P](.github/A%7DYWVE860U%28%25YQD%24R1GB1%5BP.png)
### 图片测试 ### 图片测试
**现在可以接收图片消息**(并解析为消息链): 现在可以接收图片消息(并解析为消息链):
![JsssF](.github/J%5DCE%29IK4BU08%28EO~UVLJ%7B%5BF.png) ![JsssF](.github/J%5DCE%29IK4BU08%28EO~UVLJ%7B%5BF.png)
![](.github/68f8fec9.png) ![](.github/68f8fec9.png)
发送图片已经完成,但我们还在开发上传图片至服务器。 发送图片已经完成,但我们还在开发上传图片至服务器。
现在你可以通过发送一张图片给机器人账号,再让机器人账号发送这张图片。你可以查看 [Image.kt](mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/Message.kt#L81) 机器人可以转发图片消息.详情查看 [Image.kt](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt#L81)
# TODO # 现已支持
- [x] 事件(Event)模块 - 发送好友/群消息(2019/10/14)
- [ ] 插件(Plugin)模块 - 接收好友/群消息, 消息链解析(2019/10/14)
- [x] Network - Touch - 好友在线状态改变(2019/10/14)
- [X] Network - Login
- [X] Network - Session
- [X] Network - Verification Code
- [X] Network - Message Receiving
- [X] Network - Message Sending
- [ ] Network - Events
- [ ] Bot - Friend/group list
- [ ] Bot - Actions(joining group, adding friend, etc.)
- [x] Message Section
- [ ] Image uploading
- [ ] Contact
- [ ] UI
- [ ] Console
<br> <br>
# 使用方法 # 使用方法
## 要求 ## 要求
- Kotlin 1.3+ - Kotlin 1.3+
### JVM ### 用于 JVM 平台
- Java 11 - Java 8
## 插件开发 ## 插件开发
``` text ``` text
to be continued to be continued
......
...@@ -5,6 +5,7 @@ import kotlinx.coroutines.sync.Mutex ...@@ -5,6 +5,7 @@ import kotlinx.coroutines.sync.Mutex
import net.mamoe.mirai.Bot.ContactSystem import net.mamoe.mirai.Bot.ContactSystem
import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.contact.groupIdToNumber
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
......
...@@ -7,15 +7,11 @@ import net.mamoe.mirai.message.PlainText ...@@ -7,15 +7,11 @@ import net.mamoe.mirai.message.PlainText
import net.mamoe.mirai.message.toChain import net.mamoe.mirai.message.toChain
/** /**
* 联系人. * 联系人平台基础. 包含所有平台通用的函数等.
* *
* A contact is a [QQ] or a [Group] for one particular [Bot] instance only.
*
* @param bot the Owner [Bot]
* @param number the id number of this contact
* @author Him188moe * @author Him188moe
*/ */
abstract class Contact internal constructor(val bot: Bot, val number: Long) { abstract class PlatformContactBase internal constructor(val bot: Bot, val number: Long) {
abstract suspend fun sendMessage(message: MessageChain) abstract suspend fun sendMessage(message: MessageChain)
...@@ -26,13 +22,15 @@ abstract class Contact internal constructor(val bot: Bot, val number: Long) { ...@@ -26,13 +22,15 @@ abstract class Contact internal constructor(val bot: Bot, val number: Long) {
return sendMessage(message.toChain()) return sendMessage(message.toChain())
} }
suspend fun sendMessage(plain: String) { suspend fun sendMessage(plain: String) = this.sendMessage(PlainText(plain))
this.sendMessage(PlainText(plain))
}
suspend fun sendMessage(message: List<Message>) {
this.sendMessage(MessageChain(message))
}
abstract suspend fun sendXMLMessage(message: String) abstract suspend fun sendXMLMessage(message: String)
} }
/**
* 所有的 [QQ], [Group] 都继承自这个类.
* 在不同平台可能有不同的实现.
* 如在 JVM, suspend 调用不便, [Contact] 中有简化调用的 `blocking`() 和 `async`
*/
expect sealed class Contact(bot: Bot, number: Long) : PlatformContactBase
\ No newline at end of file
package net.mamoe.mirai.contact package net.mamoe.mirai.contact
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.Group.Companion.groupNumberToId
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import net.mamoe.mirai.utils.ContactList import net.mamoe.mirai.utils.ContactList
import kotlin.jvm.JvmStatic
/** /**
* 群. * 群.
...@@ -14,125 +11,110 @@ import kotlin.jvm.JvmStatic ...@@ -14,125 +11,110 @@ import kotlin.jvm.JvmStatic
* - Group Number([Group.number]) 是通常使用的群号码.(在 QQ 客户端中可见) * - Group Number([Group.number]) 是通常使用的群号码.(在 QQ 客户端中可见)
* - Group ID([Group.groupId]) 是与服务器通讯时使用的 id.(在 QQ 客户端中不可见) * - Group ID([Group.groupId]) 是与服务器通讯时使用的 id.(在 QQ 客户端中不可见)
* *
* Java 获取 groupNumber: `group.getNumber()`
* Java 获取所属 bot: `group.getBot()`
* Java 获取群成员列表: `group.getMembers()`
* Java 获取 groupId: `group.getGroupId()`
*
* Java 调用 [groupNumberToId] : `Group.groupNumberToId(number)`
* @author Him188moe * @author Him188moe
*/ */
class Group(bot: Bot, number: Long) : Contact(bot, number) { expect class Group(bot: Bot, number: Long) : Contact {
val groupId = groupNumberToId(number) val groupId: Long
val members: ContactList<QQ> val members: ContactList<QQ>
//todo members
get() = throw UnsupportedOperationException("Not yet supported")
override suspend fun sendMessage(message: MessageChain) { override suspend fun sendMessage(message: MessageChain)
bot.network[EventPacketHandler].sendGroupMessage(this, message) override suspend fun sendXMLMessage(message: String)
companion object
}
fun Group.Companion.groupNumberToId(number: Long): Long {//求你别出错
val left: Long = number.toString().let {
if (it.length < 6) {
return@groupNumberToId number
}
it.substring(0, it.length - 6).toLong()
}
val right: Long = number.toString().let {
it.substring(it.length - 6).toLong()
} }
override suspend fun sendXMLMessage(message: String) { return when (left) {
in 1..10 -> {
((left + 202).toString() + right.toString()).toLong()
}
in 11..19 -> {
((left + 469).toString() + right.toString()).toLong()
}
in 20..66 -> {
((left + 208).toString() + right.toString()).toLong()
}
in 67..156 -> {
((left + 1943).toString() + right.toString()).toLong()
}
in 157..209 -> {
((left + 199).toString() + right.toString()).toLong()
}
in 210..309 -> {
((left + 389).toString() + right.toString()).toLong()
}
in 310..499 -> {
((left + 349).toString() + right.toString()).toLong()
}
else -> number
}
}
fun Group.Companion.groupIdToNumber(id: Long): Long {//求你别出错
var left: Long = id.toString().let {
if (it.length < 6) {
return@groupIdToNumber id
}
it.substring(0 until it.length - 6).toLong()
} }
companion object { return when (left) {
@JvmStatic in 203..212 -> {
fun groupNumberToId(number: Long): Long {//求你别出错 val right: Long = id.toString().let {
val left: Long = number.toString().let { it.substring(it.length - 6).toLong()
if (it.length < 6) {
return@groupNumberToId number
}
it.substring(0, it.length - 6).toLong()
} }
val right: Long = number.toString().let { ((left - 202).toString() + right.toString()).toLong()
}
in 480..488 -> {
val right: Long = id.toString().let {
it.substring(it.length - 6).toLong() it.substring(it.length - 6).toLong()
} }
((left - 469).toString() + right.toString()).toLong()
return when (left) { }
in 1..10 -> { in 2100..2146 -> {
((left + 202).toString() + right.toString()).toLong() val right: Long = id.toString().let {
} it.substring(it.length - 7).toLong()
in 11..19 -> {
((left + 469).toString() + right.toString()).toLong()
}
in 20..66 -> {
((left + 208).toString() + right.toString()).toLong()
}
in 67..156 -> {
((left + 1943).toString() + right.toString()).toLong()
}
in 157..209 -> {
((left + 199).toString() + right.toString()).toLong()
}
in 210..309 -> {
((left + 389).toString() + right.toString()).toLong()
}
in 310..499 -> {
((left + 349).toString() + right.toString()).toLong()
}
else -> number
} }
left = left.toString().substring(0 until 3).toLong()
((left - 208).toString() + right.toString()).toLong()
} }
in 2010..2099 -> {
@JvmStatic val right: Long = id.toString().let {
fun groupIdToNumber(id: Long): Long {//求你别出错 it.substring(it.length - 6).toLong()
var left: Long = id.toString().let {
if (it.length < 6) {
return@groupIdToNumber id
}
it.substring(0 until it.length - 6).toLong()
} }
((left - 1943).toString() + right.toString()).toLong()
return when (left) { }
in 203..212 -> { in 2147..2199 -> {
val right: Long = id.toString().let { val right: Long = id.toString().let {
it.substring(it.length - 6).toLong() it.substring(it.length - 7).toLong()
} }
((left - 202).toString() + right.toString()).toLong() left = left.toString().substring(0 until 3).toLong()
} ((left - 199).toString() + right.toString()).toLong()
in 480..488 -> { }
val right: Long = id.toString().let { in 4100..4199 -> {
it.substring(it.length - 6).toLong() val right: Long = id.toString().let {
} it.substring(it.length - 7).toLong()
((left - 469).toString() + right.toString()).toLong()
}
in 2100..2146 -> {
val right: Long = id.toString().let {
it.substring(it.length - 7).toLong()
}
left = left.toString().substring(0 until 3).toLong()
((left - 208).toString() + right.toString()).toLong()
}
in 2010..2099 -> {
val right: Long = id.toString().let {
it.substring(it.length - 6).toLong()
}
((left - 1943).toString() + right.toString()).toLong()
}
in 2147..2199 -> {
val right: Long = id.toString().let {
it.substring(it.length - 7).toLong()
}
left = left.toString().substring(0 until 3).toLong()
((left - 199).toString() + right.toString()).toLong()
}
in 4100..4199 -> {
val right: Long = id.toString().let {
it.substring(it.length - 7).toLong()
}
left = left.toString().substring(0 until 3).toLong()
((left - 389).toString() + right.toString()).toLong()
}
in 3800..3989 -> {
val right: Long = id.toString().let {
it.substring(it.length - 7).toLong()
}
left = left.toString().substring(0 until 3).toLong()
((left - 349).toString() + right.toString()).toLong()
}
else -> id
} }
left = left.toString().substring(0 until 3).toLong()
((left - 389).toString() + right.toString()).toLong()
} }
in 3800..3989 -> {
val right: Long = id.toString().let {
it.substring(it.length - 7).toLong()
}
left = left.toString().substring(0 until 3).toLong()
((left - 349).toString() + right.toString()).toLong()
}
else -> id
} }
} }
\ No newline at end of file
...@@ -4,28 +4,20 @@ import net.mamoe.mirai.Bot ...@@ -4,28 +4,20 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.At import net.mamoe.mirai.message.At
import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
/** /**
* QQ 账号. * QQ 账号.
* 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot]. * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot].
* *
* Java 获取 qq 号: `qq.getNumber()`
* Java 获取所属 bot: `qq.getBot()`
*
* A QQ instance helps you to receive event from or sendPacket event to. * A QQ instance helps you to receive event from or sendPacket event to.
* Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same. * Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same.
* *
* @author Him188moe * @author Him188moe
*/ */
class QQ(bot: Bot, number: Long) : Contact(bot, number) { expect class QQ(bot: Bot, number: Long) : Contact {
override suspend fun sendMessage(message: MessageChain) { override suspend fun sendMessage(message: MessageChain)
bot.network[EventPacketHandler].sendFriendMessage(this, message)
}
override suspend fun sendXMLMessage(message: String) {
} override suspend fun sendXMLMessage(message: String)
} }
/** /**
......
...@@ -18,7 +18,5 @@ class FriendMessageEvent(bot: Bot, sender: QQ, val message: MessageChain) : Frie ...@@ -18,7 +18,5 @@ class FriendMessageEvent(bot: Bot, sender: QQ, val message: MessageChain) : Frie
suspend inline fun reply(message: String) = sender.sendMessage(message) suspend inline fun reply(message: String) = sender.sendMessage(message)
suspend inline fun reply(message: List<Message>) = sender.sendMessage(message)
suspend inline fun reply(message: MessageChain) = sender.sendMessage(message)//shortcut suspend inline fun reply(message: MessageChain) = sender.sendMessage(message)//shortcut
} }
\ No newline at end of file
...@@ -15,7 +15,5 @@ class GroupMessageEvent(bot: Bot, group: Group, val sender: QQ, val message: Mes ...@@ -15,7 +15,5 @@ class GroupMessageEvent(bot: Bot, group: Group, val sender: QQ, val message: Mes
suspend inline fun reply(message: String) = group.sendMessage(message) suspend inline fun reply(message: String) = group.sendMessage(message)
suspend inline fun reply(message: List<Message>) = group.sendMessage(message)
suspend inline fun reply(message: MessageChain) = group.sendMessage(message) suspend inline fun reply(message: MessageChain) = group.sendMessage(message)
} }
\ No newline at end of file
...@@ -70,7 +70,10 @@ internal fun ByteReadPacket.readMessage(): Message? { ...@@ -70,7 +70,10 @@ internal fun ByteReadPacket.readMessage(): Message? {
0x19 -> {//未知, 可能是长文本? 0x19 -> {//未知, 可能是长文本?
//bot手机自己跟自己发消息会出这个 //bot手机自己跟自己发消息会出这个
//似乎手机发消息就会有这个?
//sectionData: 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 //sectionData: 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
// 01 00 1C AA 02 19 08 00 88 01 00 9A 01 11 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00
return null
sectionData.readBytes().debugPrint("sectionData") sectionData.readBytes().debugPrint("sectionData")
return PlainText("[UNKNOWN(${this.readBytes().toUHexString()})]") return PlainText("[UNKNOWN(${this.readBytes().toUHexString()})]")
println() println()
......
...@@ -71,4 +71,9 @@ interface BotNetworkHandler<Socket : DataPacketSocket> : Closeable { ...@@ -71,4 +71,9 @@ interface BotNetworkHandler<Socket : DataPacketSocket> : Closeable {
override fun close() { override fun close() {
NetworkScope.cancel("handler closed", HandlerClosedException()) NetworkScope.cancel("handler closed", HandlerClosedException())
} }
} }
\ No newline at end of file
/**
* [BotNetworkHandler] closed
*/
class HandlerClosedException : Exception()
\ No newline at end of file
package net.mamoe.mirai.network package net.mamoe.mirai.network
class HandlerClosedException : Exception()
\ No newline at end of file
...@@ -70,6 +70,9 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) { ...@@ -70,6 +70,9 @@ class EventPacketHandler(session: LoginSession) : PacketHandler(session) {
//TODO //TODO
} }
is IgnoredServerEventPacket -> {
}
else -> { else -> {
//ignored //ignored
} }
......
...@@ -8,7 +8,7 @@ import net.mamoe.mirai.utils.* ...@@ -8,7 +8,7 @@ import net.mamoe.mirai.utils.*
@PacketId("00 58") @PacketId("00 58")
class ClientHeartbeatPacket( class ClientHeartbeatPacket(
private val qq: Long, private val bot: Long,
private val sessionKey: ByteArray private val sessionKey: ByteArray
) : ClientPacket() { ) : ClientPacket() {
override val idHex: String by lazy { override val idHex: String by lazy {
...@@ -16,7 +16,7 @@ class ClientHeartbeatPacket( ...@@ -16,7 +16,7 @@ class ClientHeartbeatPacket(
} }
override fun encode(builder: BytePacketBuilder) = with(builder) { override fun encode(builder: BytePacketBuilder) = with(builder) {
this.writeQQ(qq) this.writeQQ(bot)
this.writeHex(TIMProtocol.fixVer) this.writeHex(TIMProtocol.fixVer)
this.encryptAndWrite(sessionKey) { this.encryptAndWrite(sessionKey) {
writeHex("00 01 00 01") writeHex("00 01 00 01")
......
...@@ -9,6 +9,9 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol ...@@ -9,6 +9,9 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
import kotlin.properties.Delegates import kotlin.properties.Delegates
/**
* 事件的识别 ID. 在 [事件确认包][ServerEventPacket.ResponsePacket] 中被使用.
*/
data class EventPacketIdentity( data class EventPacketIdentity(
val from: UInt,//对于好友消息, 这个是发送人 val from: UInt,//对于好友消息, 这个是发送人
val to: UInt,//对于好友消息, 这个是bot val to: UInt,//对于好友消息, 这个是bot
...@@ -37,8 +40,9 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -37,8 +40,9 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
to = readUInt(), to = readUInt(),
uniqueId = readIoBuffer(8) uniqueId = readIoBuffer(8)
) )
readBytes(2).takeIf { it[0].toUInt() != 0x1Fu && it[1].toUInt() != 0x40u }?.debugPrint("type前面2个byte") discardExact(2)
val type = readBytes(2) val type = readBytes(2)
//DebugLogger.logPurple("unknown2Byte+byte = ${unknown2Byte.toUHexString()} ${type.toUHexString()}")
return when (type.toUHexString()) { return when (type.toUHexString()) {
"00 C4" -> { "00 C4" -> {
discardExact(13) discardExact(13)
...@@ -56,11 +60,17 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -56,11 +60,17 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E //00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 07 00 00 00
"02 10" -> { "02 10" -> {
discardExact(19) discardExact(19)
println(readUByte().toUInt())
//todo 错了. 可能是 00 79 才是.
return@with ServerFriendTypingCanceledPacket(input, eventIdentity)
if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity) if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity)
else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity) else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)
} }
"00 79" -> IgnoredServerEventPacket(type, input, eventIdentity)
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity) //"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
...@@ -95,6 +105,12 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -95,6 +105,12 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
} }
} }
/**
* 忽略的事件.
* 如 00 79: 总是与 01 12 一起发生, 但 00 79 却没多大意义
*/
class IgnoredServerEventPacket(val eventId: ByteArray/*2*/, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity)
/** /**
* Unknown event * Unknown event
*/ */
...@@ -121,7 +137,6 @@ class ServerFriendTypingStartedPacket(input: ByteReadPacket, eventIdentity: Even ...@@ -121,7 +137,6 @@ class ServerFriendTypingStartedPacket(input: ByteReadPacket, eventIdentity: Even
class ServerFriendTypingCanceledPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity) class ServerFriendTypingCanceledPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerFriendTypingPacket(input, eventIdentity)
/** /**
* Android 客户端上线 * Android 客户端上线
*/ */
......
package net.mamoe.mirai.contact
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.Message
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import net.mamoe.mirai.utils.ContactList
/**
* 联系人.
*
* A contact is a [QQ] or a [Group] for one particular [Bot] instance only.
*
* @param bot the Owner [Bot]
* @param number the id number of this contact
* @author Him188moe
*/
@Suppress("unused")
actual sealed class Contact actual constructor(bot: Bot, number: Long) : PlatformContactBase(bot, number) {
abstract override suspend fun sendMessage(message: MessageChain)
abstract override suspend fun sendXMLMessage(message: String)
/**
* 阻塞发送一个消息. 仅应在 Java 使用
*/
fun blockingSendMessage(chain: MessageChain) = runBlocking { sendMessage(chain) }
/**
* 阻塞发送一个消息. 仅应在 Java 使用
*/
fun blockingSendMessage(message: Message) = runBlocking { sendMessage(message) }
/**
* 阻塞发送一个消息. 仅应在 Java 使用
*/
fun blockingSendMessage(plain: String) = runBlocking { sendMessage(plain) }
/**
* 异步发送一个消息. 仅应在 Java 使用
*/
fun asyncSendMessage(chain: MessageChain) {
bot.network.NetworkScope.launch { sendMessage(chain) }
}
/**
* 异步发送一个消息. 仅应在 Java 使用
*/
fun asyncSendMessage(message: Message) {
bot.network.NetworkScope.launch { sendMessage(message) }
}
/**
* 异步发送一个消息. 仅应在 Java 使用
*/
fun asyncSendMessage(plain: String) {
bot.network.NetworkScope.launch { sendMessage(plain) }
}
}
/**
* 群.
*
* Group ID 与 Group Number 并不是同一个值.
* - Group Number([Group.number]) 是通常使用的群号码.(在 QQ 客户端中可见)
* - Group ID([Group.groupId]) 是与服务器通讯时使用的 id.(在 QQ 客户端中不可见)
*
* Java 获取 groupNumber: `group.getNumber()`
* Java 获取所属 bot: `group.getBot()`
* Java 获取群成员列表: `group.getMembers()`
* Java 获取 groupId: `group.getGroupId()`
*
* Java 调用 [groupNumberToId] : `Group.groupNumberToId(number)`
* @author Him188moe
*/
actual class Group actual constructor(bot: Bot, number: Long) : Contact(bot, number) {
actual val groupId = groupNumberToId(number)
actual val members: ContactList<QQ>
//todo members
get() = throw UnsupportedOperationException("Not yet supported")
actual override suspend fun sendMessage(message: MessageChain) {
bot.network[EventPacketHandler].sendGroupMessage(this, message)
}
actual override suspend fun sendXMLMessage(message: String) {
}
actual companion object
}
/**
* QQ 账号.
* 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot].
*
* Java 获取 qq 号: `qq.getNumber()`
* Java 获取所属 bot: `qq.getBot()`
*
* A QQ instance helps you to receive event from or sendPacket event to.
* Notice that, one QQ instance belong to one [Bot], that is, QQ instances from different [Bot] are NOT the same.
*
* @author Him188moe
*/
actual class QQ actual constructor(bot: Bot, number: Long) : Contact(bot, number) {
actual override suspend fun sendMessage(message: MessageChain) {
bot.network[EventPacketHandler].sendFriendMessage(this, message)
}
actual override suspend fun sendXMLMessage(message: String) {
TODO()
}
}
\ No newline at end of file
...@@ -49,10 +49,7 @@ suspend fun main() { ...@@ -49,10 +49,7 @@ suspend fun main() {
"复读" in it.message -> it.sender.sendMessage(it.message) "复读" in it.message -> it.sender.sendMessage(it.message)
"发群" in it.message -> { "发群" in it.message -> {
it.message.list.toMutableList().let { messages ->
messages.removeAt(0)
Group(bot, 580266363).sendMessage(messages)
}
} }
/*it.event eq "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image -> /*it.event eq "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment