mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-11 21:30:11 +08:00
Extract implementations of Contact
s to separate files; correct package name
This commit is contained in:
parent
94e40e2e6a
commit
83793d3f7e
@ -28,6 +28,8 @@ import net.mamoe.mirai.data.*
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.MessageRecallEvent
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.qqandroid.contact.MemberInfoImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.message.OnlineFriendImageImpl
|
||||
import net.mamoe.mirai.qqandroid.message.OnlineGroupImageImpl
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
|
||||
|
@ -9,383 +9,34 @@
|
||||
|
||||
@file: Suppress("INAPPLICABLE_JVM_NAME")
|
||||
|
||||
package net.mamoe.mirai.qqandroid
|
||||
package net.mamoe.mirai.qqandroid.contact
|
||||
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlinx.io.core.Closeable
|
||||
import net.mamoe.mirai.LowLevelAPI
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.*
|
||||
import net.mamoe.mirai.data.GroupInfo
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent.FriendMessageSendEvent
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.OfflineGroupImage
|
||||
import net.mamoe.mirai.message.data.asMessageChain
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.message.MessageSourceFromSendGroup
|
||||
import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
|
||||
import net.mamoe.mirai.qqandroid.network.highway.postImage
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.qqandroid.utils.toIpV4AddressString
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo as JceFriendInfo
|
||||
|
||||
internal inline class FriendInfoImpl(
|
||||
private val jceFriendInfo: JceFriendInfo
|
||||
) : FriendInfo {
|
||||
override val nick: String get() = jceFriendInfo.nick ?: ""
|
||||
override val uin: Long get() = jceFriendInfo.friendUin
|
||||
}
|
||||
|
||||
internal class QQImpl(
|
||||
bot: QQAndroidBot,
|
||||
override val coroutineContext: CoroutineContext,
|
||||
override val id: Long,
|
||||
private val friendInfo: FriendInfo
|
||||
) : QQ() {
|
||||
override val bot: QQAndroidBot by bot.unsafeWeakRef()
|
||||
override val nick: String
|
||||
get() = friendInfo.nick
|
||||
|
||||
@JvmSynthetic
|
||||
@Suppress("DuplicatedCode")
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<out QQ> {
|
||||
val event = FriendMessageSendEvent(this, message.asMessageChain()).broadcast()
|
||||
if (event.isCancelled) {
|
||||
throw EventCancelledException("cancelled by FriendMessageSendEvent")
|
||||
}
|
||||
lateinit var source: MessageSource
|
||||
bot.network.run {
|
||||
check(
|
||||
MessageSvc.PbSendMsg.ToFriend(
|
||||
bot.client,
|
||||
id,
|
||||
event.message
|
||||
) {
|
||||
source = it
|
||||
}.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS
|
||||
) { "send message failed" }
|
||||
}
|
||||
return MessageReceipt(source, this, null)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
@OptIn(MiraiInternalAPI::class)
|
||||
override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = try {
|
||||
if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) {
|
||||
throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup")
|
||||
}
|
||||
bot.network.run {
|
||||
val response = LongConn.OffPicUp(
|
||||
bot.client, Cmd0x352.TryUpImgReq(
|
||||
srcUin = bot.uin.toInt(),
|
||||
dstUin = id.toInt(),
|
||||
fileId = 0,
|
||||
fileMd5 = image.md5,
|
||||
fileSize = image.inputSize.toInt(),
|
||||
fileName = image.md5.toUHexString("") + "." + image.format,
|
||||
imgOriginal = 1,
|
||||
imgWidth = image.width,
|
||||
imgHeight = image.height,
|
||||
imgType = image.imageType
|
||||
)
|
||||
).sendAndExpect<LongConn.OffPicUp.Response>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST") // bug
|
||||
return when (response) {
|
||||
is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(
|
||||
filepath = response.resourceId,
|
||||
md5 = response.imageInfo.fileMd5,
|
||||
fileLength = response.imageInfo.fileSize.toInt(),
|
||||
height = response.imageInfo.fileHeight,
|
||||
width = response.imageInfo.fileWidth,
|
||||
resourceId = response.resourceId
|
||||
).also {
|
||||
ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast()
|
||||
}
|
||||
is LongConn.OffPicUp.Response.RequireUpload -> {
|
||||
MiraiPlatformUtils.Http.postImage(
|
||||
"0x6ff0070",
|
||||
bot.uin,
|
||||
null,
|
||||
imageInput = image.input,
|
||||
inputSize = image.inputSize,
|
||||
uKeyHex = response.uKey.toUHexString("")
|
||||
)
|
||||
//HighwayHelper.uploadImage(
|
||||
// client = bot.client,
|
||||
// serverIp = response.serverIp[0].toIpV4AddressString(),
|
||||
// serverPort = response.serverPort[0],
|
||||
// imageInput = image.input,
|
||||
// inputSize = image.inputSize.toInt(),
|
||||
// fileMd5 = image.md5,
|
||||
// uKey = response.uKey,
|
||||
// commandId = 1
|
||||
//)
|
||||
// 为什么不能 ??
|
||||
|
||||
return OfflineFriendImage(
|
||||
filepath = response.resourceId,
|
||||
md5 = image.md5,
|
||||
fileLength = image.inputSize.toInt(),
|
||||
height = image.height,
|
||||
width = image.width,
|
||||
resourceId = response.resourceId
|
||||
).also {
|
||||
ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast()
|
||||
}
|
||||
}
|
||||
is LongConn.OffPicUp.Response.Failed -> {
|
||||
ImageUploadEvent.Failed(this@QQImpl, image, -1, response.message).broadcast()
|
||||
error(response.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
(image.input as? Closeable)?.close()
|
||||
(image.input as? Closeable)?.close()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@Suppress("DuplicatedCode")
|
||||
if (this === other) return true
|
||||
if (other !is Contact) return false
|
||||
if (this::class != other::class) return false
|
||||
return this.id == other.id && this.bot == other.bot
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryProfile(): Profile {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryPreviousNameList(): PreviousNameList {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryRemark(): FriendNameRemark {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
override fun toString(): String = "QQ($id)"
|
||||
}
|
||||
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
internal class MemberImpl(
|
||||
val qq: QQImpl, // 不要 WeakRef
|
||||
group: GroupImpl,
|
||||
override val coroutineContext: CoroutineContext,
|
||||
memberInfo: MemberInfo
|
||||
) : Member() {
|
||||
override val group: GroupImpl by group.unsafeWeakRef()
|
||||
|
||||
// region QQ delegate
|
||||
override val id: Long = qq.id
|
||||
override val nick: String = qq.nick
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryProfile(): Profile = qq.queryProfile()
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryPreviousNameList(): PreviousNameList = qq.queryPreviousNameList()
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryRemark(): FriendNameRemark = qq.queryRemark()
|
||||
|
||||
@JvmSynthetic
|
||||
@Suppress("DuplicatedCode")
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<Member> {
|
||||
val event = FriendMessageSendEvent(this, message.asMessageChain()).broadcast()
|
||||
if (event.isCancelled) {
|
||||
throw EventCancelledException("cancelled by FriendMessageSendEvent")
|
||||
}
|
||||
lateinit var source: MessageSource
|
||||
bot.network.run {
|
||||
check(
|
||||
MessageSvc.PbSendMsg.ToFriend(
|
||||
bot.client,
|
||||
id,
|
||||
event.message
|
||||
) {
|
||||
source = it
|
||||
}.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS
|
||||
) { "send message failed" }
|
||||
}
|
||||
return MessageReceipt(source, this, null)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = qq.uploadImage(image)
|
||||
// endregion
|
||||
|
||||
override var permission: MemberPermission = memberInfo.permission
|
||||
|
||||
@Suppress("PropertyName")
|
||||
internal var _nameCard: String = memberInfo.nameCard
|
||||
|
||||
@Suppress("PropertyName")
|
||||
internal var _specialTitle: String = memberInfo.specialTitle
|
||||
|
||||
@Suppress("PropertyName")
|
||||
var _muteTimestamp: Int = memberInfo.muteTimestamp
|
||||
|
||||
override val muteTimeRemaining: Int =
|
||||
if (_muteTimestamp == 0 || _muteTimestamp == 0xFFFFFFFF.toInt()) {
|
||||
0
|
||||
} else {
|
||||
_muteTimestamp - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt()
|
||||
}
|
||||
|
||||
override var nameCard: String
|
||||
get() = _nameCard
|
||||
set(newValue) {
|
||||
group.checkBotPermissionOperator()
|
||||
if (_nameCard != newValue) {
|
||||
val oldValue = _nameCard
|
||||
_nameCard = newValue
|
||||
launch {
|
||||
bot.network.run {
|
||||
TroopManagement.EditGroupNametag(
|
||||
bot.client,
|
||||
this@MemberImpl,
|
||||
newValue
|
||||
).sendWithoutExpect()
|
||||
}
|
||||
MemberCardChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var specialTitle: String
|
||||
get() = _specialTitle
|
||||
set(newValue) {
|
||||
group.checkBotPermission(MemberPermission.OWNER)
|
||||
if (_specialTitle != newValue) {
|
||||
val oldValue = _specialTitle
|
||||
_specialTitle = newValue
|
||||
launch {
|
||||
bot.network.run {
|
||||
TroopManagement.EditSpecialTitle(
|
||||
bot.client,
|
||||
this@MemberImpl,
|
||||
newValue
|
||||
).sendWithoutExpect()
|
||||
}
|
||||
MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val bot: QQAndroidBot get() = qq.bot
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun mute(durationSeconds: Int) {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
TroopManagement.Mute(
|
||||
client = bot.client,
|
||||
groupCode = group.id,
|
||||
memberUin = this@MemberImpl.id,
|
||||
timeInSecond = durationSeconds
|
||||
).sendAndExpect<TroopManagement.Mute.Response>()
|
||||
}
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName") // or unresolved reference
|
||||
net.mamoe.mirai.event.events.MemberMuteEvent(this@MemberImpl, durationSeconds, null).broadcast()
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun unmute() {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
TroopManagement.Mute(
|
||||
client = bot.client,
|
||||
groupCode = group.id,
|
||||
memberUin = this@MemberImpl.id,
|
||||
timeInSecond = 0
|
||||
).sendAndExpect<TroopManagement.Mute.Response>()
|
||||
}
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName") // or unresolved reference
|
||||
net.mamoe.mirai.event.events.MemberUnmuteEvent(this@MemberImpl, null).broadcast()
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun kick(message: String) {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
TroopManagement.Kick(
|
||||
client = bot.client,
|
||||
member = this@MemberImpl,
|
||||
message = message
|
||||
).sendAndExpect<TroopManagement.Kick.Response>().success.also {
|
||||
MemberLeaveEvent.Kick(this@MemberImpl, null).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Contact) return false
|
||||
if (this::class != other::class) return false
|
||||
return this.id == other.id && this.bot == other.bot
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Member($id)"
|
||||
}
|
||||
}
|
||||
|
||||
internal class MemberInfoImpl(
|
||||
jceInfo: StTroopMemberInfo,
|
||||
groupOwnerId: Long
|
||||
) : MemberInfo {
|
||||
override val uin: Long = jceInfo.memberUin
|
||||
override val nameCard: String = jceInfo.sName ?: ""
|
||||
override val nick: String = jceInfo.nick
|
||||
override val permission: MemberPermission = when {
|
||||
jceInfo.memberUin == groupOwnerId -> MemberPermission.OWNER
|
||||
jceInfo.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
|
||||
else -> MemberPermission.MEMBER
|
||||
}
|
||||
override val specialTitle: String = jceInfo.sSpecialTitle ?: ""
|
||||
override val muteTimestamp: Int = jceInfo.dwShutupTimestap?.toInt() ?: 0
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal fun GroupImpl.Companion.checkIsInstance(expression: Boolean) {
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* 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.qqandroid.contact
|
||||
|
||||
import kotlinx.coroutines.launch
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.FriendNameRemark
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.data.PreviousNameList
|
||||
import net.mamoe.mirai.data.Profile
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
import net.mamoe.mirai.message.data.OfflineFriendImage
|
||||
import net.mamoe.mirai.message.data.asMessageChain
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.utils.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
internal class MemberImpl(
|
||||
val qq: QQImpl, // 不要 WeakRef
|
||||
group: GroupImpl,
|
||||
override val coroutineContext: CoroutineContext,
|
||||
memberInfo: MemberInfo
|
||||
) : Member() {
|
||||
override val group: GroupImpl by group.unsafeWeakRef()
|
||||
|
||||
// region QQ delegate
|
||||
override val id: Long = qq.id
|
||||
override val nick: String = qq.nick
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryProfile(): Profile = qq.queryProfile()
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryPreviousNameList(): PreviousNameList = qq.queryPreviousNameList()
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryRemark(): FriendNameRemark = qq.queryRemark()
|
||||
|
||||
@JvmSynthetic
|
||||
@Suppress("DuplicatedCode")
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<Member> {
|
||||
val event = MessageSendEvent.FriendMessageSendEvent(this, message.asMessageChain()).broadcast()
|
||||
if (event.isCancelled) {
|
||||
throw EventCancelledException("cancelled by FriendMessageSendEvent")
|
||||
}
|
||||
lateinit var source: MessageSource
|
||||
bot.network.run {
|
||||
check(
|
||||
MessageSvc.PbSendMsg.ToFriend(
|
||||
bot.client,
|
||||
id,
|
||||
event.message
|
||||
) {
|
||||
source = it
|
||||
}.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS
|
||||
) { "send message failed" }
|
||||
}
|
||||
return MessageReceipt(source, this, null)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = qq.uploadImage(image)
|
||||
// endregion
|
||||
|
||||
override var permission: MemberPermission = memberInfo.permission
|
||||
|
||||
@Suppress("PropertyName")
|
||||
internal var _nameCard: String = memberInfo.nameCard
|
||||
|
||||
@Suppress("PropertyName")
|
||||
internal var _specialTitle: String = memberInfo.specialTitle
|
||||
|
||||
@Suppress("PropertyName")
|
||||
var _muteTimestamp: Int = memberInfo.muteTimestamp
|
||||
|
||||
override val muteTimeRemaining: Int =
|
||||
if (_muteTimestamp == 0 || _muteTimestamp == 0xFFFFFFFF.toInt()) {
|
||||
0
|
||||
} else {
|
||||
_muteTimestamp - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt()
|
||||
}
|
||||
|
||||
override var nameCard: String
|
||||
get() = _nameCard
|
||||
set(newValue) {
|
||||
group.checkBotPermissionOperator()
|
||||
if (_nameCard != newValue) {
|
||||
val oldValue = _nameCard
|
||||
_nameCard = newValue
|
||||
launch {
|
||||
bot.network.run {
|
||||
TroopManagement.EditGroupNametag(
|
||||
bot.client,
|
||||
this@MemberImpl,
|
||||
newValue
|
||||
).sendWithoutExpect()
|
||||
}
|
||||
MemberCardChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override var specialTitle: String
|
||||
get() = _specialTitle
|
||||
set(newValue) {
|
||||
group.checkBotPermission(MemberPermission.OWNER)
|
||||
if (_specialTitle != newValue) {
|
||||
val oldValue = _specialTitle
|
||||
_specialTitle = newValue
|
||||
launch {
|
||||
bot.network.run {
|
||||
TroopManagement.EditSpecialTitle(
|
||||
bot.client,
|
||||
this@MemberImpl,
|
||||
newValue
|
||||
).sendWithoutExpect()
|
||||
}
|
||||
MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val bot: QQAndroidBot get() = qq.bot
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun mute(durationSeconds: Int) {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
TroopManagement.Mute(
|
||||
client = bot.client,
|
||||
groupCode = group.id,
|
||||
memberUin = this@MemberImpl.id,
|
||||
timeInSecond = durationSeconds
|
||||
).sendAndExpect<TroopManagement.Mute.Response>()
|
||||
}
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName") // or unresolved reference
|
||||
net.mamoe.mirai.event.events.MemberMuteEvent(this@MemberImpl, durationSeconds, null).broadcast()
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun unmute() {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
TroopManagement.Mute(
|
||||
client = bot.client,
|
||||
groupCode = group.id,
|
||||
memberUin = this@MemberImpl.id,
|
||||
timeInSecond = 0
|
||||
).sendAndExpect<TroopManagement.Mute.Response>()
|
||||
}
|
||||
|
||||
@Suppress("RemoveRedundantQualifierName") // or unresolved reference
|
||||
net.mamoe.mirai.event.events.MemberUnmuteEvent(this@MemberImpl, null).broadcast()
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun kick(message: String) {
|
||||
if (group.botPermission != MemberPermission.OWNER && (!group.botPermission.isOperator() || this.isOperator())) {
|
||||
throw PermissionDeniedException()
|
||||
}
|
||||
|
||||
bot.network.run {
|
||||
TroopManagement.Kick(
|
||||
client = bot.client,
|
||||
member = this@MemberImpl,
|
||||
message = message
|
||||
).sendAndExpect<TroopManagement.Kick.Response>().success.also {
|
||||
MemberLeaveEvent.Kick(this@MemberImpl, null).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Contact) return false
|
||||
if (this::class != other::class) return false
|
||||
return this.id == other.id && this.bot == other.bot
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Member($id)"
|
||||
}
|
||||
}
|
||||
|
||||
internal class MemberInfoImpl(
|
||||
jceInfo: StTroopMemberInfo,
|
||||
groupOwnerId: Long
|
||||
) : MemberInfo {
|
||||
override val uin: Long = jceInfo.memberUin
|
||||
override val nameCard: String = jceInfo.sName ?: ""
|
||||
override val nick: String = jceInfo.nick
|
||||
override val permission: MemberPermission = when {
|
||||
jceInfo.memberUin == groupOwnerId -> MemberPermission.OWNER
|
||||
jceInfo.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
|
||||
else -> MemberPermission.MEMBER
|
||||
}
|
||||
override val specialTitle: String = jceInfo.sSpecialTitle ?: ""
|
||||
override val muteTimestamp: Int = jceInfo.dwShutupTimestap?.toInt() ?: 0
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
package net.mamoe.mirai.qqandroid.contact
|
||||
|
||||
import kotlinx.io.core.Closeable
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.FriendInfo
|
||||
import net.mamoe.mirai.data.FriendNameRemark
|
||||
import net.mamoe.mirai.data.PreviousNameList
|
||||
import net.mamoe.mirai.data.Profile
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.BeforeImageUploadEvent
|
||||
import net.mamoe.mirai.event.events.EventCancelledException
|
||||
import net.mamoe.mirai.event.events.ImageUploadEvent
|
||||
import net.mamoe.mirai.event.events.MessageSendEvent
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageSource
|
||||
import net.mamoe.mirai.message.data.OfflineFriendImage
|
||||
import net.mamoe.mirai.message.data.asMessageChain
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.network.highway.postImage
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
internal inline class FriendInfoImpl(
|
||||
private val jceFriendInfo: net.mamoe.mirai.qqandroid.network.protocol.data.jce.FriendInfo
|
||||
) : FriendInfo {
|
||||
override val nick: String get() = jceFriendInfo.nick ?: ""
|
||||
override val uin: Long get() = jceFriendInfo.friendUin
|
||||
}
|
||||
|
||||
internal class QQImpl(
|
||||
bot: QQAndroidBot,
|
||||
override val coroutineContext: CoroutineContext,
|
||||
override val id: Long,
|
||||
private val friendInfo: FriendInfo
|
||||
) : QQ() {
|
||||
override val bot: QQAndroidBot by bot.unsafeWeakRef()
|
||||
override val nick: String
|
||||
get() = friendInfo.nick
|
||||
|
||||
@JvmSynthetic
|
||||
@Suppress("DuplicatedCode")
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<out QQ> {
|
||||
val event = MessageSendEvent.FriendMessageSendEvent(this, message.asMessageChain()).broadcast()
|
||||
if (event.isCancelled) {
|
||||
throw EventCancelledException("cancelled by FriendMessageSendEvent")
|
||||
}
|
||||
lateinit var source: MessageSource
|
||||
bot.network.run {
|
||||
check(
|
||||
MessageSvc.PbSendMsg.ToFriend(
|
||||
bot.client,
|
||||
id,
|
||||
event.message
|
||||
) {
|
||||
source = it
|
||||
}
|
||||
.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS
|
||||
) { "send message failed" }
|
||||
}
|
||||
return MessageReceipt(source, this, null)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
@OptIn(MiraiInternalAPI::class)
|
||||
override suspend fun uploadImage(image: ExternalImage): OfflineFriendImage = try {
|
||||
if (BeforeImageUploadEvent(this, image).broadcast().isCancelled) {
|
||||
throw EventCancelledException("cancelled by BeforeImageUploadEvent.ToGroup")
|
||||
}
|
||||
bot.network.run {
|
||||
val response = LongConn.OffPicUp(
|
||||
bot.client, Cmd0x352.TryUpImgReq(
|
||||
srcUin = bot.uin.toInt(),
|
||||
dstUin = id.toInt(),
|
||||
fileId = 0,
|
||||
fileMd5 = image.md5,
|
||||
fileSize = image.inputSize.toInt(),
|
||||
fileName = image.md5.toUHexString("") + "." + image.format,
|
||||
imgOriginal = 1,
|
||||
imgWidth = image.width,
|
||||
imgHeight = image.height,
|
||||
imgType = image.imageType
|
||||
)
|
||||
).sendAndExpect<LongConn.OffPicUp.Response>()
|
||||
|
||||
@Suppress("UNCHECKED_CAST") // bug
|
||||
return when (response) {
|
||||
is LongConn.OffPicUp.Response.FileExists -> OfflineFriendImage(
|
||||
filepath = response.resourceId,
|
||||
md5 = response.imageInfo.fileMd5,
|
||||
fileLength = response.imageInfo.fileSize.toInt(),
|
||||
height = response.imageInfo.fileHeight,
|
||||
width = response.imageInfo.fileWidth,
|
||||
resourceId = response.resourceId
|
||||
).also {
|
||||
ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast()
|
||||
}
|
||||
is LongConn.OffPicUp.Response.RequireUpload -> {
|
||||
MiraiPlatformUtils.Http.postImage(
|
||||
"0x6ff0070",
|
||||
bot.uin,
|
||||
null,
|
||||
imageInput = image.input,
|
||||
inputSize = image.inputSize,
|
||||
uKeyHex = response.uKey.toUHexString("")
|
||||
)
|
||||
//HighwayHelper.uploadImage(
|
||||
// client = bot.client,
|
||||
// serverIp = response.serverIp[0].toIpV4AddressString(),
|
||||
// serverPort = response.serverPort[0],
|
||||
// imageInput = image.input,
|
||||
// inputSize = image.inputSize.toInt(),
|
||||
// fileMd5 = image.md5,
|
||||
// uKey = response.uKey,
|
||||
// commandId = 1
|
||||
//)
|
||||
// 为什么不能 ??
|
||||
|
||||
return OfflineFriendImage(
|
||||
filepath = response.resourceId,
|
||||
md5 = image.md5,
|
||||
fileLength = image.inputSize.toInt(),
|
||||
height = image.height,
|
||||
width = image.width,
|
||||
resourceId = response.resourceId
|
||||
).also {
|
||||
ImageUploadEvent.Succeed(this@QQImpl, image, it).broadcast()
|
||||
}
|
||||
}
|
||||
is LongConn.OffPicUp.Response.Failed -> {
|
||||
ImageUploadEvent.Failed(this@QQImpl, image, -1, response.message).broadcast()
|
||||
error(response.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
(image.input as? Closeable)?.close()
|
||||
(image.input as? Closeable)?.close()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = bot.hashCode()
|
||||
result = 31 * result + id.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
@Suppress("DuplicatedCode")
|
||||
if (this === other) return true
|
||||
if (other !is Contact) return false
|
||||
if (this::class != other::class) return false
|
||||
return this.id == other.id && this.bot == other.bot
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryProfile(): Profile {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryPreviousNameList(): PreviousNameList {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
@MiraiExperimentalAPI
|
||||
override suspend fun queryRemark(): FriendNameRemark {
|
||||
TODO("not implemented")
|
||||
}
|
||||
|
||||
override fun toString(): String = "QQ($id)"
|
||||
}
|
@ -25,10 +25,10 @@ import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||
import net.mamoe.mirai.event.events.BotOnlineEvent
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.WrongPasswordException
|
||||
import net.mamoe.mirai.qqandroid.FriendInfoImpl
|
||||
import net.mamoe.mirai.qqandroid.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.FriendInfoImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
|
||||
@ -264,32 +264,32 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
bot.groups.delegate.addLast(
|
||||
@Suppress("DuplicatedCode")
|
||||
(GroupImpl(
|
||||
bot = bot,
|
||||
coroutineContext = bot.coroutineContext,
|
||||
id = troopNum.groupCode,
|
||||
groupInfo = bot._lowLevelQueryGroupInfo(troopNum.groupCode).apply {
|
||||
this as GroupInfoImpl
|
||||
bot = bot,
|
||||
coroutineContext = bot.coroutineContext,
|
||||
id = troopNum.groupCode,
|
||||
groupInfo = bot._lowLevelQueryGroupInfo(troopNum.groupCode).apply {
|
||||
this as GroupInfoImpl
|
||||
|
||||
if (this.delegate.groupName == null) {
|
||||
this.delegate.groupName = troopNum.groupName
|
||||
}
|
||||
if (this.delegate.groupName == null) {
|
||||
this.delegate.groupName = troopNum.groupName
|
||||
}
|
||||
|
||||
if (this.delegate.groupMemo == null) {
|
||||
this.delegate.groupMemo = troopNum.groupMemo
|
||||
}
|
||||
if (this.delegate.groupMemo == null) {
|
||||
this.delegate.groupMemo = troopNum.groupMemo
|
||||
}
|
||||
|
||||
if (this.delegate.groupUin == null) {
|
||||
this.delegate.groupUin = troopNum.groupUin
|
||||
}
|
||||
if (this.delegate.groupUin == null) {
|
||||
this.delegate.groupUin = troopNum.groupUin
|
||||
}
|
||||
|
||||
this.delegate.groupCode = troopNum.groupCode
|
||||
},
|
||||
members = bot._lowLevelQueryGroupMemberList(
|
||||
troopNum.groupUin,
|
||||
troopNum.groupCode,
|
||||
troopNum.dwGroupOwnerUin
|
||||
)
|
||||
))
|
||||
this.delegate.groupCode = troopNum.groupCode
|
||||
},
|
||||
members = bot._lowLevelQueryGroupMemberList(
|
||||
troopNum.groupUin,
|
||||
troopNum.groupCode,
|
||||
troopNum.dwGroupOwnerUin
|
||||
)
|
||||
))
|
||||
)
|
||||
}?.let {
|
||||
logger.error { "群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试" }
|
||||
|
@ -24,7 +24,7 @@ import net.mamoe.mirai.event.events.MemberJoinEvent
|
||||
import net.mamoe.mirai.getFriendOrNull
|
||||
import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.qqandroid.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
|
||||
|
@ -19,10 +19,10 @@ import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.message.GroupMessage
|
||||
import net.mamoe.mirai.qqandroid.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.MemberImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.MemberImpl
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.checkIsInstance
|
||||
import net.mamoe.mirai.qqandroid.contact.checkIsInstance
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.message.toMessageChain
|
||||
|
Loading…
Reference in New Issue
Block a user