Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
f7040c18
Commit
f7040c18
authored
Mar 29, 2020
by
Him188
Committed by
GitHub
Mar 29, 2020
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #170 from mamoe/long-message
Support long message in general `sendMessage`
parents
6b332a73
2f063987
Changes
43
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
43 changed files
with
282 additions
and
373 deletions
+282
-373
mirai-core-qqandroid/src/androidMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDHAndroid.kt
...in/net/mamoe/mirai/qqandroid/utils/cryptor/ECDHAndroid.kt
+2
-2
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt
...mmonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt
+20
-32
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
...ain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
+14
-4
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt
...in/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt
+2
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt
...onMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt
+22
-6
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt
...in/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt
+3
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
...Main/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
+27
-149
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
.../mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+10
-27
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/MultiMsg.kt
.../mirai/qqandroid/network/protocol/packet/chat/MultiMsg.kt
+13
-99
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
...ndroid/network/protocol/packet/chat/receive/MessageSvc.kt
+28
-18
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDH.kt
...in/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDH.kt
+5
-5
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/TEA.kt
...ain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/TEA.kt
+2
-2
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/output.kt
...nMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/output.kt
+8
-10
mirai-core-qqandroid/src/jvmMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDHJvm.kt
...kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDHJvm.kt
+2
-2
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/Bot.kt
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/Bot.kt
+2
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt
.../androidMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt
+4
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/Contact.kt
...src/androidMain/kotlin/net/mamoe/mirai/contact/Contact.kt
+2
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt
.../kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt
+2
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/Group.kt
...e/src/androidMain/kotlin/net/mamoe/mirai/contact/Group.kt
+2
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/Member.kt
.../src/androidMain/kotlin/net/mamoe/mirai/contact/Member.kt
+2
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt
...core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt
+2
-0
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/message/MessageReceipt.kt
...roidMain/kotlin/net/mamoe/mirai/message/MessageReceipt.kt
+7
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+11
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
.../src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
...re/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
...e/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
...-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt
...core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt
+3
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
...ommonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
+2
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
...mmonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
+15
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
+3
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
...nMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
+13
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
...Main/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
+20
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt
...monMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt
+4
-1
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/Bot.kt
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/Bot.kt
+2
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt
.../src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt
+4
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Contact.kt
...ore/src/jvmMain/kotlin/net/mamoe/mirai/contact/Contact.kt
+2
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt
.../kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt
+2
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt
...-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt
+2
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Member.kt
...core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Member.kt
+2
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/QQ.kt
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/QQ.kt
+2
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessageReceipt.kt
.../jvmMain/kotlin/net/mamoe/mirai/message/MessageReceipt.kt
+5
-1
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt
...mMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt
+1
-1
No files found.
mirai-core-qqandroid/src/androidMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDHAndroid.kt
View file @
f7040c18
...
...
@@ -32,9 +32,9 @@ internal actual class ECDHKeyPairImpl(
}
@Suppress
(
"FunctionName"
)
actual
fun
ECDH
()
=
ECDH
(
ECDH
.
generateKeyPair
())
internal
actual
fun
ECDH
()
=
ECDH
(
ECDH
.
generateKeyPair
())
actual
class
ECDH
actual
constructor
(
actual
val
keyPair
:
ECDHKeyPair
)
{
internal
actual
class
ECDH
actual
constructor
(
actual
val
keyPair
:
ECDHKeyPair
)
{
actual
companion
object
{
@Suppress
(
"ObjectPropertyName"
)
private
var
_isECDHAvailable
:
Boolean
=
false
// because `runCatching` has no contract.
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt
View file @
f7040c18
...
...
@@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.qqandroid
import
io.ktor.client.HttpClient
...
...
@@ -29,12 +31,12 @@ import net.mamoe.mirai.contact.*
import
net.mamoe.mirai.data.*
import
net.mamoe.mirai.event.broadcast
import
net.mamoe.mirai.event.events.MessageRecallEvent
import
net.mamoe.mirai.message.MessageReceipt
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.contact.checkIsGroupImpl
import
net.mamoe.mirai.qqandroid.io.serialization.toByteArray
import
net.mamoe.mirai.qqandroid.message.MessageSourceFromSendFriend
import
net.mamoe.mirai.qqandroid.message.OnlineFriendImageImpl
import
net.mamoe.mirai.qqandroid.message.OnlineGroupImageImpl
import
net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
...
...
@@ -162,6 +164,7 @@ internal abstract class QQAndroidBotBase constructor(
TODO
(
"not implemented"
)
}
@ExperimentalMessageSource
override
suspend
fun
recall
(
source
:
MessageSource
)
{
if
(
source
.
senderId
!=
uin
&&
source
.
groupId
!=
0L
)
{
getGroup
(
source
.
groupId
).
checkBotPermissionOperator
()
...
...
@@ -368,34 +371,21 @@ internal abstract class QQAndroidBotBase constructor(
@LowLevelAPI
@MiraiExperimentalAPI
override
suspend
fun
_lowLevelSendLong
Message
(
groupCode
:
Long
,
message
:
Message
)
{
override
suspend
fun
_lowLevelSendLong
GroupMessage
(
groupCode
:
Long
,
message
:
Message
):
MessageReceipt
<
Group
>
{
val
chain
=
message
.
asMessageChain
()
check
(
chain
.
toString
().
length
<=
4500
&&
chain
.
count
{
it
is
Image
}
<=
50
)
{
"message is too large"
}
check
(
chain
.
toString
().
length
<=
4500
&&
chain
.
count
{
it
is
Image
}
<=
50
)
{
"message is too large
. Allow up to 4500 chars or 50 images
"
}
val
group
=
getGroup
(
groupCode
)
val
source
=
MessageSourceFromSendFriend
(
messageRandom
=
Random
.
nextInt
().
absoluteValue
,
senderId
=
client
.
uin
,
toUin
=
Group
.
calculateGroupUinByGroupCode
(
groupCode
),
time
=
currentTimeSeconds
,
groupId
=
groupCode
,
originalMessage
=
chain
,
sequenceId
=
client
.
atomicNextMessageSequenceId
()
// sourceMessage = message
)
// TODO: 2020/3/26 util 方法来添加单例元素
val
toSend
=
buildMessageChain
(
chain
.
size
)
{
source
.
originalMessage
.
forEach
{
if
(
it
!
is
MessageSource
)
{
add
(
it
)
}
}
add
(
source
)
}
val
time
=
currentTimeSeconds
network
.
run
{
val
data
=
toSend
.
calculateValidationDataForGroup
(
group
)
val
data
=
chain
.
calculateValidationDataForGroup
(
sequenceId
=
client
.
atomicNextMessageSequenceId
(),
time
=
time
.
toInt
(),
random
=
Random
.
nextInt
().
absoluteValue
.
toUInt
(),
groupCode
,
group
.
botAsMember
.
nameCardOrNick
)
val
response
=
MultiMsg
.
ApplyUp
.
createForGroupLongMessage
(
...
...
@@ -441,17 +431,15 @@ internal abstract class QQAndroidBotBase constructor(
}
}
group
.
sendMessage
(
return
group
.
sendMessage
(
RichMessage
.
longMessage
(
brief
=
toSend
.
joinToString
(
limit
=
30
)
{
when
(
it
)
{
is
PlainText
->
it
.
stringValue
is
At
->
it
.
toString
()
else
->
""
}
brief
=
chain
.
toString
().
let
{
// already cached
if
(
it
.
length
>
27
)
{
it
.
take
(
27
)
+
"..."
}
else
it
},
resId
=
resId
,
timeSeconds
=
source
.
time
timeSeconds
=
time
)
)
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
View file @
f7040c18
...
...
@@ -23,9 +23,7 @@ import net.mamoe.mirai.event.broadcast
import
net.mamoe.mirai.event.events.*
import
net.mamoe.mirai.event.events.MessageSendEvent.GroupMessageSendEvent
import
net.mamoe.mirai.message.MessageReceipt
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.message.data.*
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.message.MessageSourceFromSendGroup
import
net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
...
...
@@ -273,13 +271,25 @@ internal class GroupImpl(
return
members
.
delegate
.
filteringGetOrNull
{
it
.
id
==
id
}
}
@OptIn
(
MiraiExperimentalAPI
::
class
)
@JvmSynthetic
override
suspend
fun
sendMessage
(
message
:
Message
):
MessageReceipt
<
Group
>
{
check
(!
isBotMuted
)
{
"bot is muted. Remaining seconds=$botMuteRemaining"
}
val
event
=
GroupMessageSendEvent
(
this
,
message
.
asMessageChain
()).
broadcast
()
if
(
event
.
isCancelled
)
{
throw
EventCancelledException
(
"cancelled by FriendMessageSendEvent"
)
throw
EventCancelledException
(
"cancelled by GroupMessageSendEvent"
)
}
if
(
message
!
is
LongMessage
)
{
val
length
=
event
.
message
.
toString
().
length
if
(
length
>
4000
||
event
.
message
.
count
{
it
is
Image
}
>
3
||
(
event
.
message
.
any
<
QuoteReply
>()
&&
(
event
.
message
.
any
<
Image
>()
||
length
>
100
))
)
{
return
bot
.
_lowLevelSendLongGroupMessage
(
this
.
id
,
message
)
}
}
lateinit
var
source
:
MessageSourceFromSendGroup
bot
.
network
.
run
{
val
response
:
MessageSvc
.
PbSendMsg
.
Response
=
MessageSvc
.
PbSendMsg
.
ToGroup
(
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt
View file @
f7040c18
...
...
@@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.qqandroid.contact
import
kotlinx.coroutines.launch
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/QQImpl.kt
View file @
f7040c18
...
...
@@ -8,9 +8,12 @@
*/
@
file
:
OptIn
(
MiraiInternalAPI
::
class
,
LowLevelAPI
::
class
)
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.qqandroid.contact
import
kotlinx.atomicfu.AtomicInt
import
kotlinx.atomicfu.atomic
import
kotlinx.io.core.Closeable
import
net.mamoe.mirai.LowLevelAPI
import
net.mamoe.mirai.contact.Contact
...
...
@@ -36,6 +39,8 @@ 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.contracts.ExperimentalContracts
import
kotlin.contracts.contract
import
kotlin.coroutines.CoroutineContext
import
kotlin.jvm.JvmSynthetic
...
...
@@ -46,12 +51,23 @@ internal inline class FriendInfoImpl(
override
val
uin
:
Long
get
()
=
jceFriendInfo
.
friendUin
}
@OptIn
(
ExperimentalContracts
::
class
)
internal
fun
QQ
.
checkIsQQImpl
():
QQImpl
{
contract
{
returns
()
implies
(
this
@
checkIsQQImpl
is
QQImpl
)
}
check
(
this
is
QQImpl
)
{
"A QQ instance is not instance of QQImpl. Don't interlace two protocol implementations together!"
}
return
this
}
internal
class
QQImpl
(
bot
:
QQAndroidBot
,
override
val
coroutineContext
:
CoroutineContext
,
override
val
id
:
Long
,
private
val
friendInfo
:
FriendInfo
)
:
QQ
()
{
var
lastMessageSequence
:
AtomicInt
=
atomic
(-
1
)
override
val
bot
:
QQAndroidBot
by
bot
.
unsafeWeakRef
()
override
val
nick
:
String
get
()
=
friendInfo
.
nick
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceImpl.kt
View file @
f7040c18
...
...
@@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
,
"EXPERIMENTAL_OVERRIDE"
)
package
net.mamoe.mirai.qqandroid.message
import
kotlinx.coroutines.CoroutineScope
...
...
@@ -146,7 +148,7 @@ internal abstract class MessageSourceFromSend : MessageSource {
}
private
val
elems
by
lazy
{
originalMessage
.
toRichTextElems
(
groupId
!=
0L
)
originalMessage
.
toRichTextElems
(
groupId
!=
0L
,
true
)
}
private
fun
toJceDataImplForFriend
():
ImMsgBody
.
SourceMsg
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt
View file @
f7040c18
...
...
@@ -7,6 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@
file
:
OptIn
(
MiraiExperimentalAPI
::
class
,
MiraiInternalAPI
::
class
,
LowLevelAPI
::
class
,
ExperimentalUnsignedTypes
::
class
)
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.qqandroid.message
...
...
@@ -56,44 +57,6 @@ internal fun OfflineFriendImage.toJceData(): ImMsgBody.NotOnlineImage {
)
}
/*
CustomFace#24412994 {
guid=<Empty ByteArray>
filePath={01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
shortcut=
buffer=<Empty ByteArray>
flag=00 00 00 00
oldData=15 36 20 39 32 6B 41 31 00 38 37 32 66 30 36 36 30 33 61 65 31 30 33 62 37 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 30 31 45 39 34 35 31 42 2D 37 30 45 44 2D 45 41 45 33 2D 42 33 37 43 2D 31 30 31 46 31 45 45 42 46 35 42 35 7D 2E 70 6E 67 41
fileId=0x872F0660(-2026961312)
serverIp=0x3AE103B7(987825079)
serverPort=0x00000050(80)
fileType=0x00000000(0)
signature=<Empty ByteArray>
useful=0x00000001(1)
md5=01 E9 45 1B 70 ED EA E3 B3 7C 10 1F 1E EB F5 B5
thumbUrl=/gchatpic_new/1040400290/1041235568-2268005984-01E9451B70EDEAE3B37C101F1EEBF5B5/198?term=2
bigUrl=
origUrl=/gchatpic_new/1040400290/1041235568-2268005984-01E9451B70EDEAE3B37C101F1EEBF5B5/0?term=2
bizType=0x00000000(0)
repeatIndex=0x00000000(0)
repeatImage=0x00000000(0)
imageType=0x00000000(0)
index=0x00000000(0)
width=0x0000015F(351)
height=0x000000EB(235)
source=0x00000000(0)
size=0x0000057C(1404)
origin=0x00000000(0)
thumbWidth=0x000000C6(198)
thumbHeight=0x00000084(132)
showLen=0x00000000(0)
downloadLen=0x00000000(0)
_400Url=/gchatpic_new/1040400290/1041235568-2268005984-01E9451B70EDEAE3B37C101F1EEBF5B5/400?term=2
_400Width=0x0000015F(351)
_400Height=0x000000EB(235)
pbReserve=<Empty ByteArray>
}
*/
internal
val
FACE_BUF
=
"00 01 00 04 52 CC F5 D0"
.
hexToBytes
()
internal
fun
Face
.
toJceData
():
ImMsgBody
.
Face
{
...
...
@@ -133,76 +96,6 @@ internal fun OfflineGroupImage.toJceData(): ImMsgBody.CustomFace {
private
val
oldData
:
ByteArray
=
"15 36 20 39 32 6B 41 31 00 38 37 32 66 30 36 36 30 33 61 65 31 30 33 62 37 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 30 31 45 39 34 35 31 42 2D 37 30 45 44 2D 45 41 45 33 2D 42 33 37 43 2D 31 30 31 46 31 45 45 42 46 35 42 35 7D 2E 70 6E 67 41"
.
hexToBytes
()
/*
customFace=CustomFace#2050019814 {
guid=<Empty ByteArray>
filePath=5F6C522DEAC4F36C0ED8EF362660EFD6.png
shortcut=
buffer=<Empty ByteArray>
flag=<Empty ByteArray>
oldData=<Empty ByteArray>
fileId=0xB40AF10E(-1274351346)
serverIp=0xB703E13A(-1224482502)
serverPort=0x00000050(80)
fileType=0x00000042(66)
signature=6B 44 61 76 72 79 68 79 57 67 70 52 41 45 78 49
useful=0x00000001(1)
md5=5F 6C 52 2D EA C4 F3 6C 0E D8 EF 36 26 60 EF D6
thumbUrl=
bigUrl=
origUrl=
bizType=0x00000005(5)
repeatIndex=0x00000000(0)
repeatImage=0x00000000(0)
imageType=0x000003E9(1001)
index=0x00000000(0)
width=0x0000005F(95)
height=0x00000054(84)
source=0x00000067(103)
size=0x000006E2(1762)
origin=0x00000000(0)
thumbWidth=0x00000000(0)
thumbHeight=0x00000000(0)
showLen=0x00000000(0)
downloadLen=0x00000000(0)
_400Url=
_400Width=0x00000000(0)
_400Height=0x00000000(0)
pbReserve=08 01 10 00 32 00 4A 0E 5B E5 8A A8 E7 94 BB E8 A1 A8 E6 83 85 5D 50 00 78 05
}
notOnlineImage=NotOnlineImage#2050019814 {
filePath=41AEF2D4B5BD24CF3791EFC5FEB67D60.jpg
fileLen=0x00000350(848)
downloadPath=/f2b7e5c0-acb3-4e83-aa5c-c8383840cc91
oldVerSendFile=<Empty ByteArray>
imgType=0x000003E8(1000)
previewsImage=<Empty ByteArray>
picMd5=41 AE F2 D4 B5 BD 24 CF 37 91 EF C5 FE B6 7D 60
picHeight=0x00000032(50)
picWidth=0x00000033(51)
resId=/f2b7e5c0-acb3-4e83-aa5c-c8383840cc91
flag=<Empty ByteArray>
thumbUrl=
original=0x00000000(0)
bigUrl=
origUrl=
bizType=0x00000005(5)
result=0x00000000(0)
index=0x00000000(0)
opFaceBuf=<Empty ByteArray>
oldPicMd5=false
thumbWidth=0x00000000(0)
thumbHeight=0x00000000(0)
fileId=0x00000000(0)
showLen=0x00000000(0)
downloadLen=0x00000000(0)
_400Url=
_400Width=0x00000000(0)
_400Height=0x00000000(0)
pbReserve=08 01 10 00 32 00 42 0E 5B E5 8A A8 E7 94 BB E8 A1 A8 E6 83 85 5D 50 00 78 05
}
*/
private
val
atAllData
=
ImMsgBody
.
Elem
(
text
=
ImMsgBody
.
Text
(
...
...
@@ -222,7 +115,7 @@ private val atAllData = ImMsgBody.Elem(
private
val
UNSUPPORTED_MERGED_MESSAGE_PLAIN
=
PlainText
(
"你的QQ暂不支持查看[转发多条消息],请期待后续版本。"
)
@OptIn
(
MiraiInternalAPI
::
class
,
MiraiExperimentalAPI
::
class
)
internal
fun
MessageChain
.
toRichTextElems
(
forGroup
:
Boolean
):
MutableList
<
ImMsgBody
.
Elem
>
{
internal
fun
MessageChain
.
toRichTextElems
(
forGroup
:
Boolean
,
withGeneralFlags
:
Boolean
):
MutableList
<
ImMsgBody
.
Elem
>
{
val
elements
=
mutableListOf
<
ImMsgBody
.
Elem
>()
if
(
this
.
any
<
QuoteReply
>())
{
...
...
@@ -310,6 +203,7 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgB
}
this
.
forEach
(
::
transformOneMessage
)
if
(
withGeneralFlags
)
{
when
{
longTextResId
!=
null
->
{
elements
.
add
(
...
...
@@ -324,14 +218,19 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean): MutableList<ImMsgB
}
this
.
any
<
RichMessage
>()
->
{
// 08 09 78 00 A0 01 81 DC 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00
elements
.
add
(
ImMsgBody
.
Elem
(
generalFlags
=
ImMsgBody
.
GeneralFlags
(
pbReserve
=
"08 09 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00"
.
hexToBytes
())))
elements
.
add
(
ImMsgBody
.
Elem
(
generalFlags
=
ImMsgBody
.
GeneralFlags
(
pbReserve
=
PB_RESERVE_FOR_RICH_MESSAGE
)))
}
else
->
elements
.
add
(
ImMsgBody
.
Elem
(
generalFlags
=
ImMsgBody
.
GeneralFlags
(
pbReserve
=
PB_RESERVE_FOR_ELSE
)))
}
else
->
elements
.
add
(
ImMsgBody
.
Elem
(
generalFlags
=
ImMsgBody
.
GeneralFlags
(
pbReserve
=
"78 00 F8 01 00 C8 02 00"
.
hexToBytes
())))
}
return
elements
}
private
val
PB_RESERVE_FOR_RICH_MESSAGE
=
"08 09 78 00 C8 01 00 F0 01 00 F8 01 00 90 02 00 C8 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 02 08 03 90 04 80 80 80 10 B8 04 00 C0 04 00"
.
hexToBytes
()
private
val
PB_RESERVE_FOR_ELSE
=
"78 00 F8 01 00 C8 02 00"
.
hexToBytes
()
internal
class
OnlineGroupImageImpl
(
internal
val
delegate
:
ImMsgBody
.
CustomFace
)
:
OnlineGroupImage
()
{
...
...
@@ -416,17 +315,12 @@ private fun MessageChain.cleanupRubbishMessageElements(): MessageChain {
var
last
:
SingleMessage
?
=
null
return
buildMessageChain
(
initialSize
=
this
.
count
())
{
this
@
cleanupRubbishMessageElements
.
forEach
{
element
->
if
(
last
==
null
)
{
last
=
element
return
@
forEach
}
else
{
if
(
last
is
LongMessage
&&
element
is
PlainText
)
{
if
(
element
==
UNSUPPORTED_MERGED_MESSAGE_PLAIN
)
{
last
=
element
return
@
forEach
}
}
}
add
(
element
)
last
=
element
...
...
@@ -443,19 +337,6 @@ internal inline fun <reified R> Iterable<*>.firstIsInstance(): R {
throw
NoSuchElementException
(
"Collection contains no element matching the predicate."
)
}
/*
if (this.any<QuoteReply>()) {
var removed = false
this.filter {
if (it is At && !removed) {
false
} else {
removed = true
true
}
}.asMessageChain()
} else this*/
internal
fun
List
<
ImMsgBody
.
Elem
>.
joinToMessageChain
(
message
:
MessageChainBuilder
)
{
this
.
forEach
{
when
{
...
...
@@ -467,9 +348,6 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilde
if
(
it
.
text
.
attr6Buf
.
isEmpty
())
{
message
.
add
(
it
.
text
.
str
.
toMessage
())
}
else
{
// 00 01 00 00 00 05 01 00 00 00 00 00 00 all
// 00 01 00 00 00 0A 00 3E 03 3F A2 00 00 one/nick
// 00 01 00 00 00 07 00 44 71 47 90 00 00 one/groupCard
val
id
:
Long
it
.
text
.
attr6Buf
.
read
{
discardExact
(
7
)
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
View file @
f7040c18
...
...
@@ -27,14 +27,17 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat
import
net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
import
net.mamoe.mirai.qqandroid.network.protocol.packet.login.WtLogin
import
net.mamoe.mirai.qqandroid.network.readUShortLVByteArray
import
net.mamoe.mirai.qqandroid.utils.cryptor.TEA
import
net.mamoe.mirai.qqandroid.utils.cryptor.adjustToPublicKey
import
net.mamoe.mirai.qqandroid.utils.io.readPacketExact
import
net.mamoe.mirai.qqandroid.utils.io.readString
import
net.mamoe.mirai.qqandroid.utils.io.useBytes
import
net.mamoe.mirai.qqandroid.utils.io.withUse
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.qqandroid.utils.cryptor.TEA
import
net.mamoe.mirai.qqandroid.utils.cryptor.adjustToPublicKey
import
net.mamoe.mirai.utils.io.*
import
net.mamoe.mirai.utils.io.ByteArrayPool
import
net.mamoe.mirai.utils.io.toInt
import
net.mamoe.mirai.utils.io.toReadPacket
import
net.mamoe.mirai.utils.io.toUHexString
import
kotlin.jvm.JvmName
...
...
@@ -171,9 +174,6 @@ internal object KnownPacketFactories {
?:
IncomingFactories
.
firstOrNull
{
it
.
receivingCommandName
==
commandName
}
}
/**
* full packet without length
*/
// do not inline. Exceptions thrown will not be reported correctly
@OptIn
(
MiraiInternalAPI
::
class
)
@Suppress
(
"UNCHECKED_CAST"
)
...
...
@@ -183,22 +183,12 @@ internal object KnownPacketFactories {
val
flag1
=
readInt
()
PacketLogger
.
verbose
{
"开始处理一个包"
}
PacketLogger
.
verbose
{
"flag1(0A/0B) = ${flag1.toUByte().toUHexString()}"
}
val
flag2
=
readByte
().
toInt
()
PacketLogger
.
verbose
{
"包类型(flag2) = $flag2. (可能是 ${when (flag2) {
2
->
"OicqRequest"
1
->
"Uni/ProtoBuf"
0
->
"Heartbeat"
else
->
"未知"
}})
"
}
val
flag3
=
readByte
().
toInt
()
check
(
flag3
==
0
)
{
"Illegal flag3. Expected 0, whereas got $flag3. flag1=$flag1, flag2=$flag2.
Remaining=${this.readBytes()
.
toUHexString
()}
"
"Illegal flag3. Expected 0, whereas got $flag3. flag1=$flag1, flag2=$flag2.
"
+
"Remaining=${this.readBytes()
.toUHexString()}"
}
readString
(
readInt
()
-
4
)
// uinAccount
...
...
@@ -209,14 +199,11 @@ internal object KnownPacketFactories {
kotlin
.
runCatching
{
when
(
flag2
)
{
2
->
TEA
.
decrypt
(
data
,
DECRYPTER_16_ZERO
,
size
)
.
also
{
PacketLogger
.
verbose
{
"成功使用 16 zero 解密"
}
}
1
->
TEA
.
decrypt
(
data
,
bot
.
client
.
wLoginSigInfo
.
d2Key
,
size
)
.
also
{
PacketLogger
.
verbose
{
"成功使用 d2Key 解密"
}
}
0
->
data
else
->
error
(
""
)
}
}.
getOrElse
{
PacketLogger
.
verbose
{
"失败, 尝试其他各种key"
}
bot
.
client
.
tryDecryptOrNull
(
data
,
size
)
{
it
}
}
?.
toReadPacket
()
?.
let
{
decryptedData
->
when
(
flag1
)
{
...
...
@@ -236,7 +223,7 @@ internal object KnownPacketFactories {
}
else
{
handleIncomingPacket
(
it
,
bot
,
flag2
,
consumer
)
}
}
?:
inline
{
}
?:
kotlin
.
run
{
PacketLogger
.
error
{
"任何key都无法解密: ${data.take(size).toUHexString()}"
}
return
}
...
...
@@ -295,8 +282,6 @@ internal object KnownPacketFactories {
}
}
private
inline
fun
<
R
>
inline
(
block
:
()
->
R
):
R
=
block
()
class
IncomingPacket
<
T
:
Packet
?>(
val
packetFactory
:
PacketFactory
<
T
>?,
val
sequenceId
:
Int
,
...
...
@@ -358,9 +343,7 @@ internal object KnownPacketFactories {
}
}
}
8
->
{
input
}
8
->
input
else
->
error
(
"unknown dataCompressed flag: $dataCompressed"
)
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/MultiMsg.kt
View file @
f7040c18
This diff is collapsed.
Click to expand it.
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt
View file @
f7040c18
...
...
@@ -11,6 +11,7 @@
package
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
import
kotlinx.atomicfu.loop
import
kotlinx.coroutines.FlowPreview
import
kotlinx.coroutines.flow.*
import
kotlinx.io.core.ByteReadPacket
...
...
@@ -19,16 +20,15 @@ import net.mamoe.mirai.LowLevelAPI
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.MemberPermission
import
net.mamoe.mirai.data.MemberInfo
import
net.mamoe.mirai.qqandroid.network.MultiPacketByIterable
import
net.mamoe.mirai.qqandroid.network.Packet
import
net.mamoe.mirai.event.events.BotJoinGroupEvent
import
net.mamoe.mirai.event.events.BotOfflineEvent
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.contact.GroupImpl
import
net.mamoe.mirai.qqandroid.QQAndroidBot
import
net.mamoe.mirai.qqandroid.contact.GroupImpl
import
net.mamoe.mirai.qqandroid.contact.checkIsQQImpl
import
net.mamoe.mirai.qqandroid.io.serialization.decodeUniPacket
import
net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
import
net.mamoe.mirai.qqandroid.io.serialization.toByteArray
...
...
@@ -37,6 +37,8 @@ import net.mamoe.mirai.qqandroid.message.MessageSourceFromSendFriend
import
net.mamoe.mirai.qqandroid.message.MessageSourceFromSendGroup
import
net.mamoe.mirai.qqandroid.message.toMessageChain
import
net.mamoe.mirai.qqandroid.message.toRichTextElems
import
net.mamoe.mirai.qqandroid.network.MultiPacketByIterable
import
net.mamoe.mirai.qqandroid.network.Packet
import
net.mamoe.mirai.qqandroid.network.QQAndroidClient
import
net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushForceOffline
import
net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPushNotify
...
...
@@ -195,9 +197,8 @@ internal class MessageSvc {
bot
.
groups
.
delegate
.
addLast
(
newGroup
)
return
@
mapNotNull
BotJoinGroupEvent
(
newGroup
)
}
else
{
if
(
group
==
null
)
{
return
@
mapNotNull
null
}
group
?:
return
@
mapNotNull
null
if
(
group
.
members
.
contains
(
msg
.
msgHead
.
authUin
))
{
return
@
mapNotNull
null
}
...
...
@@ -207,22 +208,31 @@ internal class MessageSvc {
override
val
specialTitle
:
String
get
()
=
""
override
val
muteTimestamp
:
Int
get
()
=
0
override
val
uin
:
Long
get
()
=
msg
.
msgHead
.
authUin
override
val
nick
:
String
get
()
=
msg
.
msgHead
.
authNick
.
takeIf
{
it
.
isNotEmpty
()
}
override
val
nick
:
String
=
msg
.
msgHead
.
authNick
.
takeIf
{
it
.
isNotEmpty
()
}
?:
msg
.
msgHead
.
fromNick
}).
also
{
group
.
members
.
delegate
.
addLast
(
it
)
})
}
}
166
->
{
val
friend
=
bot
.
getFriendOrNull
(
msg
.
msgHead
.
fromUin
)
?:
return
@
mapNotNull
null
return
@
mapNotNull
when
{
msg
.
msgHead
.
fromUin
==
bot
.
uin
->
null
!
bot
.
firstLoginSucceed
->
null
else
->
FriendMessage
(
friend
.
checkIsQQImpl
()
if
(
msg
.
msgHead
.
fromUin
==
bot
.
uin
||
!
bot
.
firstLoginSucceed
)
{
return
@
mapNotNull
null
}
friend
.
lastMessageSequence
.
loop
{
instant
->
if
(
msg
.
msgHead
.
msgSeq
>
instant
)
{
println
(
"bigger"
)
if
(
friend
.
lastMessageSequence
.
compareAndSet
(
instant
,
msg
.
msgHead
.
msgSeq
))
{
println
(
"set ok"
)
return
@
mapNotNull
FriendMessage
(
friend
,
msg
.
toMessageChain
()
)
}
}
else
return
@
mapNotNull
null
}
}
else
->
return
@
mapNotNull
null
}
...
...
@@ -319,7 +329,7 @@ internal class MessageSvc {
contentHead
=
MsgComm
.
ContentHead
(
pkgNum
=
1
),
msgBody
=
ImMsgBody
.
MsgBody
(
richText
=
ImMsgBody
.
RichText
(
elems
=
message
.
toRichTextElems
(
false
)
elems
=
message
.
toRichTextElems
(
false
,
true
)
)
),
msgSeq
=
source
.
sequenceId
,
...
...
@@ -372,7 +382,7 @@ internal class MessageSvc {
contentHead
=
MsgComm
.
ContentHead
(
pkgNum
=
1
),
msgBody
=
ImMsgBody
.
MsgBody
(
richText
=
ImMsgBody
.
RichText
(
elems
=
message
.
toRichTextElems
(
true
)
elems
=
message
.
toRichTextElems
(
true
,
true
)
)
),
msgSeq
=
client
.
atomicNextMessageSequenceId
(),
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDH.kt
View file @
f7040c18
...
...
@@ -21,7 +21,7 @@ expect interface ECDHPublicKey {
internal
expect
class
ECDHKeyPairImpl
:
ECDHKeyPair
interface
ECDHKeyPair
{
inter
nal
inter
face
ECDHKeyPair
{
val
privateKey
:
ECDHPrivateKey
val
publicKey
:
ECDHPublicKey
...
...
@@ -43,7 +43,7 @@ interface ECDHKeyPair {
/**
* 椭圆曲线密码, ECDH 加密
*/
expect
class
ECDH
(
keyPair
:
ECDHKeyPair
)
{
internal
expect
class
ECDH
(
keyPair
:
ECDHKeyPair
)
{
val
keyPair
:
ECDHKeyPair
/**
...
...
@@ -74,9 +74,9 @@ expect class ECDH(keyPair: ECDHKeyPair) {
}
@Suppress
(
"FunctionName"
)
expect
fun
ECDH
():
ECDH
internal
expect
fun
ECDH
():
ECDH
val
initialPublicKey
internal
val
initialPublicKey
get
()
=
ECDH
.
constructPublicKey
(
"3046301006072A8648CE3D020106052B8104001F03320004928D8850673088B343264E0C6BACB8496D697799F37211DEB25BB73906CB089FEA9639B4E0260498B51A992D50813DA8"
.
chunkedHexToBytes
())
private
val
commonHeadFor02
=
"302E301006072A8648CE3D020106052B8104001F031A00"
.
chunkedHexToBytes
()
private
val
commonHeadForNot02
=
"3046301006072A8648CE3D020106052B8104001F033200"
.
chunkedHexToBytes
()
...
...
@@ -86,7 +86,7 @@ private val byteArray_04 = byteArrayOf(0x04)
private
val
head1
=
"302E301006072A8648CE3D020106052B8104001F031A00"
.
chunkedHexToBytes
()
private
val
head2
=
"3046301006072A8648CE3D020106052B8104001F03320004"
.
chunkedHexToBytes
()
fun
ByteArray
.
adjustToPublicKey
():
ECDHPublicKey
{
internal
fun
ByteArray
.
adjustToPublicKey
():
ECDHPublicKey
{
val
head
=
if
(
this
.
size
<
30
)
head1
else
head2
return
ECDH
.
constructPublicKey
(
head
+
this
)
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/TEA.kt
View file @
f7040c18
...
...
@@ -23,7 +23,7 @@ import kotlin.random.Random
/**
* 解密错误
*/
class
DecryptionFailedException
:
Exception
{
internal
class
DecryptionFailedException
:
Exception
{
constructor
()
:
super
()
constructor
(
message
:
String
?)
:
super
(
message
)
}
...
...
@@ -34,7 +34,7 @@ class DecryptionFailedException : Exception {
* **注意**: 此为 Mirai 内部 API. 它可能会在任何时刻被改变.
*/
@MiraiInternalAPI
object
TEA
{
internal
object
TEA
{
// TODO: 2020/2/28 使用 stream 式输入以避免缓存
/**
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/io/output.kt
View file @
f7040c18
...
...
@@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
fun
BytePacketBuilder
.
writeShortLVByteArrayLimitedLength
(
array
:
ByteArray
,
maxLength
:
Int
)
{
internal
fun
BytePacketBuilder
.
writeShortLVByteArrayLimitedLength
(
array
:
ByteArray
,
maxLength
:
Int
)
{
if
(
array
.
size
<=
maxLength
)
{
writeShort
(
array
.
size
.
toShort
())
writeFully
(
array
)
...
...
@@ -32,13 +32,13 @@ fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLe
}
}
inline
fun
BytePacketBuilder
.
writeShortLVByteArray
(
byteArray
:
ByteArray
):
Int
{
in
ternal
in
line
fun
BytePacketBuilder
.
writeShortLVByteArray
(
byteArray
:
ByteArray
):
Int
{
this
.
writeShort
(
byteArray
.
size
.
toShort
())
this
.
writeFully
(
byteArray
)
return
byteArray
.
size
}
inline
fun
BytePacketBuilder
.
writeIntLVPacket
(
tag
:
UByte
?
=
null
,
lengthOffset
:
((
Long
)
->
Long
)
=
{
it
},
builder
:
BytePacketBuilder
.()
->
Unit
):
Int
=
in
ternal
in
line
fun
BytePacketBuilder
.
writeIntLVPacket
(
tag
:
UByte
?
=
null
,
lengthOffset
:
((
Long
)
->
Long
)
=
{
it
},
builder
:
BytePacketBuilder
.()
->
Unit
):
Int
=
BytePacketBuilder
().
apply
(
builder
).
build
().
use
{
if
(
tag
!=
null
)
writeUByte
(
tag
)
val
length
=
lengthOffset
.
invoke
(
it
.
remaining
).
coerceAtMostOrFail
(
0
xFFFFFFFFL
)
...
...
@@ -47,7 +47,7 @@ inline fun BytePacketBuilder.writeIntLVPacket(tag: UByte? = null, lengthOffset:
return
length
.
toInt
()
}
inline
fun
BytePacketBuilder
.
writeShortLVPacket
(
tag
:
UByte
?
=
null
,
lengthOffset
:
((
Long
)
->
Long
)
=
{
it
},
builder
:
BytePacketBuilder
.()
->
Unit
):
Int
=
in
ternal
in
line
fun
BytePacketBuilder
.
writeShortLVPacket
(
tag
:
UByte
?
=
null
,
lengthOffset
:
((
Long
)
->
Long
)
=
{
it
},
builder
:
BytePacketBuilder
.()
->
Unit
):
Int
=
BytePacketBuilder
().
apply
(
builder
).
build
().
use
{
if
(
tag
!=
null
)
writeUByte
(
tag
)
val
length
=
lengthOffset
.
invoke
(
it
.
remaining
).
coerceAtMostOrFail
(
0
xFFFFFFFFL
)
...
...
@@ -56,18 +56,16 @@ inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset
return
length
.
toInt
()
}
inline
fun
BytePacketBuilder
.
writeShortLVString
(
str
:
String
)
=
writeShortLVByteArray
(
str
.
toByteArray
())
in
ternal
in
line
fun
BytePacketBuilder
.
writeShortLVString
(
str
:
String
)
=
writeShortLVByteArray
(
str
.
toByteArray
())
fun
BytePacketBuilder
.
writeHex
(
uHex
:
String
)
{
internal
fun
BytePacketBuilder
.
writeHex
(
uHex
:
String
)
{
uHex
.
split
(
" "
).
forEach
{
if
(
it
.
isNotBlank
())
{
writeUByte
(
it
.
toUByte
(
16
))
}
}
}
/**
* 会使用 [ByteArrayPool] 缓存
*/
@OptIn
(
MiraiInternalAPI
::
class
)
inline
fun
BytePacketBuilder
.
encryptAndWrite
(
key
:
ByteArray
,
encoder
:
BytePacketBuilder
.()
->
Unit
)
=
in
ternal
in
line
fun
BytePacketBuilder
.
encryptAndWrite
(
key
:
ByteArray
,
encoder
:
BytePacketBuilder
.()
->
Unit
)
=
TEA
.
encrypt
(
BytePacketBuilder
().
apply
(
encoder
).
build
(),
key
)
{
decrypted
->
writeFully
(
decrypted
)
}
\ No newline at end of file
mirai-core-qqandroid/src/jvmMain/kotlin/net/mamoe/mirai/qqandroid/utils/cryptor/ECDHJvm.kt
View file @
f7040c18
...
...
@@ -32,10 +32,10 @@ internal actual class ECDHKeyPairImpl(
}
@Suppress
(
"FunctionName"
)
actual
fun
ECDH
()
=
internal
actual
fun
ECDH
()
=
ECDH
(
ECDH
.
generateKeyPair
())
actual
class
ECDH
actual
constructor
(
actual
val
keyPair
:
ECDHKeyPair
)
{
internal
actual
class
ECDH
actual
constructor
(
actual
val
keyPair
:
ECDHKeyPair
)
{
actual
companion
object
{
actual
val
isECDHAvailable
:
Boolean
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/Bot.kt
View file @
f7040c18
...
...
@@ -7,6 +7,7 @@ import kotlinx.coroutines.io.ByteReadChannel
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.data.AddFriendResult
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.ExperimentalMessageSource
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
...
...
@@ -152,6 +153,7 @@ actual abstract class Bot actual constructor() : CoroutineScope, LowLevelBotAPIA
* @see _lowLevelRecallFriendMessage 低级 API
* @see _lowLevelRecallGroupMessage 低级 API
*/
@ExperimentalMessageSource
@JvmSynthetic
actual
abstract
suspend
fun
recall
(
source
:
MessageSource
)
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt
View file @
f7040c18
...
...
@@ -5,6 +5,7 @@ import net.mamoe.mirai.contact.PermissionDeniedException
import
net.mamoe.mirai.contact.recall
import
net.mamoe.mirai.data.AddFriendResult
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.ExperimentalMessageSource
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
...
...
@@ -61,6 +62,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
*
* @see Bot.recall (扩展函数) 接受参数 [MessageChain]
*/
@ExperimentalMessageSource
@JvmName
(
"recall"
)
fun
__recallBlockingForJava__
(
source
:
MessageSource
)
{
runBlocking
{
recall
(
source
)
}
...
...
@@ -88,6 +90,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
* @param millis 延迟的时间, 单位为毫秒
* @see recall
*/
@ExperimentalMessageSource
@JvmName
(
"recallIn"
)
fun
__recallIn_MemberForJava__
(
source
:
MessageSource
,
millis
:
Long
)
{
runBlocking
{
recallIn
(
source
,
millis
)
}
...
...
@@ -148,6 +151,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
/**
* 异步调用 [__recallBlockingForJava__]
*/
@ExperimentalMessageSource
@JvmName
(
"recallAsync"
)
fun
__recallAsyncForJava__
(
source
:
MessageSource
):
Future
<
Unit
>
{
return
future
{
recall
(
source
)
}
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/Contact.kt
View file @
f7040c18
...
...
@@ -54,6 +54,8 @@ actual abstract class Contact : CoroutineScope, ContactJavaFriendlyAPI() {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt
View file @
f7040c18
...
...
@@ -48,6 +48,8 @@ actual abstract class ContactJavaFriendlyAPI {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/Group.kt
View file @
f7040c18
...
...
@@ -125,6 +125,8 @@ actual abstract class Group : Contact(), CoroutineScope {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/Member.kt
View file @
f7040c18
...
...
@@ -110,6 +110,8 @@ actual abstract class Member : MemberJavaFriendlyAPI() {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/contact/QQ.kt
View file @
f7040c18
...
...
@@ -78,6 +78,8 @@ actual abstract class QQ : Contact(), CoroutineScope {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/androidMain/kotlin/net/mamoe/mirai/message/MessageReceipt.kt
View file @
f7040c18
...
...
@@ -29,7 +29,8 @@ import net.mamoe.mirai.utils.unsafeWeakRef
*/
@Suppress
(
"FunctionName"
)
@OptIn
(
MiraiInternalAPI
::
class
)
actual
open
class
MessageReceipt
<
C
:
Contact
>
actual
constructor
(
actual
open
class
MessageReceipt
<
C
:
Contact
>
@OptIn
(
ExperimentalMessageSource
::
class
)
actual
constructor
(
actual
val
source
:
MessageSource
,
target
:
C
,
private
val
botAsMember
:
Member
?
...
...
@@ -56,6 +57,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* @see Bot.recall
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
actual
suspend
fun
recall
()
{
@Suppress
(
"BooleanLiteralArgument"
)
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
...
...
@@ -82,7 +84,8 @@ actual open class MessageReceipt<C : Contact> actual constructor(
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
return
when
(
val
contact
=
target
)
{
is
QQ
,
is
Group
->
contact
.
bot
.
recallIn
(
source
,
millis
)
is
Group
,
->
contact
.
bot
.
recallIn
(
source
,
millis
)
else
->
error
(
"Unknown contact type"
)
}
}
else
error
(
"message is already or planned to be recalled"
)
...
...
@@ -92,6 +95,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* [确保 sequenceId可用][MessageSource.ensureSequenceIdAvailable] 然后引用这条消息.
* @see MessageChain.quote 引用一条消息
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
actual
open
suspend
fun
quote
():
QuoteReplyToSend
{
this
.
source
.
ensureSequenceIdAvailable
()
@OptIn
(
LowLevelAPI
::
class
)
...
...
@@ -105,6 +109,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
*
* @see MessageChain.quote 引用一条消息
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
@LowLevelAPI
@Suppress
(
"FunctionName"
)
actual
fun
_unsafeQuote
():
QuoteReplyToSend
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
View file @
f7040c18
...
...
@@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.data.AddFriendResult
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.ExperimentalMessageSource
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
...
...
@@ -33,6 +34,7 @@ import kotlin.jvm.JvmSynthetic
/**
* 登录, 返回 [this]
*/
@JvmSynthetic
suspend
inline
fun
<
B
:
Bot
>
B
.
alsoLogin
():
B
=
also
{
login
()
}
// 任何人都能看到这个方法
...
...
@@ -167,6 +169,7 @@ expect abstract class Bot() : CoroutineScope, LowLevelBotAPIAccessor {
* @see _lowLevelRecallFriendMessage 低级 API
* @see _lowLevelRecallGroupMessage 低级 API
*/
@ExperimentalMessageSource
@JvmSynthetic
abstract
suspend
fun
recall
(
source
:
MessageSource
)
...
...
@@ -223,6 +226,7 @@ expect abstract class Bot() : CoroutineScope, LowLevelBotAPIAccessor {
* @throws PermissionDeniedException 当 [Bot] 无权限操作时
* @see Bot.recall
*/
@JvmSynthetic
suspend
inline
fun
Bot
.
recall
(
message
:
MessageChain
)
=
this
.
recall
(
message
[
MessageSource
])
/**
...
...
@@ -233,6 +237,7 @@ suspend inline fun Bot.recall(message: MessageChain) = this.recall(message[Messa
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
@JvmSynthetic
inline
fun
Bot
.
recallIn
(
source
:
MessageSource
,
millis
:
Long
,
...
...
@@ -249,6 +254,7 @@ inline fun Bot.recallIn(
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
@JvmSynthetic
inline
fun
Bot
.
recallIn
(
message
:
MessageChain
,
millis
:
Long
,
...
...
@@ -265,15 +271,20 @@ inline fun Bot.recallIn(
*
* @param cause 原因. 为 null 时视为正常关闭, 非 null 时视为异常关闭
*/
@JvmSynthetic
suspend
inline
fun
Bot
.
closeAndJoin
(
cause
:
Throwable
?
=
null
)
{
close
(
cause
)
coroutineContext
[
Job
]
?.
join
()
}
@JvmSynthetic
inline
fun
Bot
.
containsFriend
(
id
:
Long
):
Boolean
=
this
.
friends
.
contains
(
id
)
@JvmSynthetic
inline
fun
Bot
.
containsGroup
(
id
:
Long
):
Boolean
=
this
.
groups
.
contains
(
id
)
@JvmSynthetic
inline
fun
Bot
.
getFriendOrNull
(
id
:
Long
):
QQ
?
=
this
.
friends
.
getOrNull
(
id
)
@JvmSynthetic
inline
fun
Bot
.
getGroupOrNull
(
id
:
Long
):
Group
?
=
this
.
groups
.
getOrNull
(
id
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt
View file @
f7040c18
...
...
@@ -57,6 +57,8 @@ expect abstract class Contact() : CoroutineScope, ContactJavaFriendlyAPI {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
View file @
f7040c18
...
...
@@ -129,6 +129,8 @@ expect abstract class Group() : Contact, CoroutineScope {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt
View file @
f7040c18
...
...
@@ -132,6 +132,8 @@ expect abstract class Member() : MemberJavaFriendlyAPI {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see MessageSendEvent.FriendMessageSendEvent 发送好友信息事件, cancellable
* @see MessageSendEvent.GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt
View file @
f7040c18
...
...
@@ -87,6 +87,8 @@ expect abstract class QQ() : Contact, CoroutineScope {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt
View file @
f7040c18
...
...
@@ -13,6 +13,7 @@ import kotlinx.coroutines.Job
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.data.*
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.Message
import
net.mamoe.mirai.message.data.MessageSource
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
...
...
@@ -137,6 +138,7 @@ interface LowLevelBotAPIAccessor {
/**
* 获取群活跃信息
*/
@SinceMirai
(
"0.29.0"
)
@LowLevelAPI
@MiraiExperimentalAPI
suspend
fun
_lowLevelGetGroupActiveData
(
groupId
:
Long
):
GroupActiveData
...
...
@@ -147,7 +149,7 @@ interface LowLevelBotAPIAccessor {
@SinceMirai
(
"0.31.0"
)
@LowLevelAPI
@MiraiExperimentalAPI
suspend
fun
_lowLevelSendLong
Message
(
groupCode
:
Long
,
message
:
Message
)
suspend
fun
_lowLevelSendLong
GroupMessage
(
groupCode
:
Long
,
message
:
Message
):
MessageReceipt
<
Group
>
}
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt
View file @
f7040c18
...
...
@@ -7,7 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@
file
:
Suppress
(
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"EXPERIMENTAL_API_USAGE"
)
@
file
:
Suppress
(
"EXPERIMENTAL_UNSIGNED_LITERALS"
,
"EXPERIMENTAL_API_USAGE"
,
"unused"
)
package
net.mamoe.mirai.message
...
...
@@ -153,6 +153,7 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact> : Packet, Bot
/**
* 引用这个消息
*/
@ExperimentalMessageSource
inline
fun
MessageChain
.
quote
():
QuoteReplyToSend
=
this
.
quote
(
sender
)
operator
fun
<
M
:
Message
>
get
(
at
:
Message
.
Key
<
M
>):
M
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessageReceipt.kt
View file @
f7040c18
...
...
@@ -15,12 +15,16 @@ import net.mamoe.mirai.LowLevelAPI
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.recallIn
import
kotlin.jvm.JvmSynthetic
/**
* 发送消息后得到的回执. 可用于撤回.
*
* 此对象持有 [Contact] 的弱引用, [Bot] 离线后将会释放引用, 届时 [target] 将无法访问.
*
* @param source 指代发送出去的消息
* @param target 消息发送对象
*
* @see Group.sendMessage 发送群消息, 返回回执(此对象)
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
*
...
...
@@ -28,11 +32,15 @@ import net.mamoe.mirai.recallIn
* @see MessageReceipt.sourceSequenceId 源序列号
* @see MessageReceipt.sourceTime 源时间
*/
expect
open
class
MessageReceipt
<
C
:
Contact
>(
expect
open
class
MessageReceipt
<
C
:
Contact
>
@OptIn
(
ExperimentalMessageSource
::
class
)
constructor
(
source
:
MessageSource
,
target
:
C
,
botAsMember
:
Member
?
)
{
/**
* 指代发送出去的消息
*/
@ExperimentalMessageSource
val
source
:
MessageSource
/**
...
...
@@ -90,6 +98,8 @@ expect open class MessageReceipt<C : Contact>(
*
* @see MessageSource.id
*/
@
get
:
JvmSynthetic
@ExperimentalMessageSource
inline
val
MessageReceipt
<*>.
sourceId
:
Long
get
()
=
this
.
source
.
id
/**
...
...
@@ -97,6 +107,8 @@ inline val MessageReceipt<*>.sourceId: Long get() = this.source.id
*
* @see MessageSource.sequenceId
*/
@
get
:
JvmSynthetic
@ExperimentalMessageSource
inline
val
MessageReceipt
<*>.
sourceSequenceId
:
Int
get
()
=
this
.
source
.
sequenceId
/**
...
...
@@ -104,6 +116,8 @@ inline val MessageReceipt<*>.sourceSequenceId: Int get() = this.source.sequenceI
*
* @see MessageSource.time
*/
@
get
:
JvmSynthetic
@ExperimentalMessageSource
inline
val
MessageReceipt
<*>.
sourceTime
:
Long
get
()
=
this
.
source
.
time
suspend
inline
fun
MessageReceipt
<
out
Contact
>.
quoteReply
(
message
:
Message
)
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
View file @
f7040c18
...
...
@@ -37,7 +37,7 @@ interface Image : Message, MessageContent {
* 图片的 id. 只需要有这个 id 即可发送图片.
*
* 示例:
* 好友图片的 id: `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
* 好友图片的 id: `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
或 `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206`
* 群图片的 id: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png`
*/
val
imageId
:
String
...
...
@@ -53,7 +53,7 @@ interface Image : Message, MessageContent {
@JsName
(
"newImage"
)
@JvmName
(
"newImage"
)
fun
Image
(
imageId
:
String
):
Image
=
when
(
imageId
.
length
)
{
37
->
OfflineFriendImage
(
imageId
)
// /f8f1ab55-bf8e-4236-b55e-955848d7069f
54
,
37
->
OfflineFriendImage
(
imageId
)
// /f8f1ab55-bf8e-4236-b55e-955848d7069f
42
->
OfflineGroupImage
(
imageId
)
// {01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png
else
->
throw
IllegalArgumentException
(
"Bad imageId, expecting length=37 or 42, got ${imageId.length}"
)
}
...
...
@@ -211,7 +211,7 @@ abstract class OnlineGroupImage : GroupImage(), OnlineImage
/**
* 好友图片
*
* [imageId] 形如 `/f8f1ab55-bf8e-4236-b55e-955848d7069f` (37 长度)
* [imageId] 形如 `/f8f1ab55-bf8e-4236-b55e-955848d7069f` (37 长度)
或 `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206` (54 长度)
*/
// NotOnlineImage
@OptIn
(
MiraiInternalAPI
::
class
)
sealed
class
FriendImage
:
AbstractImage
()
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt
View file @
f7040c18
...
...
@@ -127,6 +127,7 @@ inline fun <reified M : Message> MessageChain.any(): Boolean = this.any { it is
/**
* 获取第一个 [M] 类型的 [Message] 实例
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
@JvmSynthetic
@Suppress
(
"UNCHECKED_CAST"
)
fun
<
M
:
Message
>
MessageChain
.
firstOrNull
(
key
:
Message
.
Key
<
M
>):
M
?
=
when
(
key
)
{
...
...
@@ -415,7 +416,10 @@ internal class MessageChainImplByIterable constructor(
)
:
Message
,
Iterable
<
SingleMessage
>,
MessageChain
{
override
val
size
:
Int
by
lazy
{
delegate
.
count
()
}
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
delegate
.
iterator
()
override
fun
toString
():
String
=
this
.
delegate
.
joinToString
(
""
)
{
it
.
toString
()
}
var
toStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
toStringTemp
?:
this
.
delegate
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
toStringTemp
=
it
}
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
delegate
.
any
{
it
.
contains
(
sub
)
}
}
...
...
@@ -428,7 +432,10 @@ internal class MessageChainImplByCollection constructor(
)
:
Message
,
Iterable
<
SingleMessage
>,
MessageChain
{
override
val
size
:
Int
get
()
=
delegate
.
size
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
delegate
.
iterator
()
override
fun
toString
():
String
=
this
.
delegate
.
joinToString
(
""
)
{
it
.
toString
()
}
var
toStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
toStringTemp
?:
this
.
delegate
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
toStringTemp
=
it
}
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
delegate
.
any
{
it
.
contains
(
sub
)
}
}
...
...
@@ -446,7 +453,10 @@ internal class MessageChainImplBySequence constructor(
*/
private
val
collected
:
List
<
SingleMessage
>
by
lazy
{
delegate
.
toList
()
}
override
fun
iterator
():
Iterator
<
SingleMessage
>
=
collected
.
iterator
()
override
fun
toString
():
String
=
this
.
collected
.
joinToString
(
""
)
{
it
.
toString
()
}
var
toStringTemp
:
String
?
=
null
override
fun
toString
():
String
=
toStringTemp
?:
this
.
collected
.
joinToString
(
""
)
{
it
.
toString
()
}.
also
{
toStringTemp
=
it
}
override
operator
fun
contains
(
sub
:
String
):
Boolean
=
collected
.
any
{
it
.
contains
(
sub
)
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt
View file @
f7040c18
...
...
@@ -19,6 +19,12 @@ import kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmSynthetic
/**
* MessageSource 正计划于 0.32 或 0.33 或之后进行 API 不兼容的重写.
*/
@RequiresOptIn
(
message
=
"MessageSource 正计划于 0.32 或 0.33 或之后进行 API 不兼容的重写"
,
level
=
RequiresOptIn
.
Level
.
WARNING
)
annotation
class
ExperimentalMessageSource
/**
* 消息源, 它存在于 [MessageChain] 中, 用于表示这个消息的来源.
*
...
...
@@ -29,6 +35,7 @@ import kotlin.jvm.JvmSynthetic
* @see Bot.recall 撤回一条消息
* @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
*/
@ExperimentalMessageSource
interface
MessageSource
:
Message
,
MessageMetadata
{
companion
object
Key
:
Message
.
Key
<
MessageSource
>
...
...
@@ -82,6 +89,7 @@ interface MessageSource : Message, MessageMetadata {
* 序列号. 若是机器人发出去的消息, 请先 [确保 sequenceId 可用][MessageSource.ensureSequenceIdAvailable]
* @see MessageSource.id
*/
@ExperimentalMessageSource
@
get
:
JvmSynthetic
inline
val
MessageSource
.
sequenceId
:
Int
get
()
=
(
this
.
id
shr
32
).
toInt
()
...
...
@@ -90,6 +98,7 @@ inline val MessageSource.sequenceId: Int
* 消息随机数. 由服务器或客户端指定后不能更改. 它是消息 id 的一部分.
* @see MessageSource.id
*/
@ExperimentalMessageSource
@
get
:
JvmSynthetic
inline
val
MessageSource
.
messageRandom
:
Int
get
()
=
this
.
id
.
toInt
()
...
...
@@ -98,24 +107,33 @@ inline val MessageSource.messageRandom: Int
/**
* 消息 id.
*
* 仅接收到的消息才可以获取这个 id.
*
* @see MessageSource.id
*/
@ExperimentalMessageSource
@
get
:
JvmSynthetic
inline
val
MessageChain
.
id
:
Long
get
()
=
this
[
MessageSource
].
id
/**
* 消息序列号, 可能来自服务器也可以发送时赋值, 不唯一.
*
* 仅接收到的消息才可以获取这个序列号.
*
* @see MessageSource.id
*/
@ExperimentalMessageSource
@
get
:
JvmSynthetic
inline
val
MessageChain
.
sequenceId
:
Int
get
()
=
this
[
MessageSource
].
sequenceId
get
()
=
this
.
getOrNull
(
MessageSource
)
?.
sequenceId
?:
error
(
"Only MessageChain from server has sequenceId"
)
/**
* 消息随机数. 由服务器或客户端指定后不能更改. 它是消息 id 的一部分.
* @see MessageSource.id
*/
@ExperimentalMessageSource
@
get
:
JvmSynthetic
inline
val
MessageChain
.
messageRandom
:
Int
get
()
=
this
[
MessageSource
].
messageRandom
get
()
=
this
.
getOrNull
(
MessageSource
)
?.
messageRandom
?:
error
(
"Only MessageChain from server has sequenceId"
)
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt
View file @
f7040c18
...
...
@@ -29,6 +29,7 @@ import kotlin.jvm.JvmName
* 总是使用 [quote] 来构造这个实例.
*/
open
class
QuoteReply
@OptIn
(
ExperimentalMessageSource
::
class
)
@MiraiInternalAPI
constructor
(
val
source
:
MessageSource
)
:
Message
,
MessageMetadata
{
companion
object
Key
:
Message
.
Key
<
QuoteReply
>
...
...
@@ -39,7 +40,7 @@ open class QuoteReply
* 用于发送的引用回复.
* 总是使用 [quote] 来构造实例.
*/
@OptIn
(
MiraiInternalAPI
::
class
)
@OptIn
(
MiraiInternalAPI
::
class
,
ExperimentalMessageSource
::
class
)
sealed
class
QuoteReplyToSend
@MiraiInternalAPI
constructor
(
source
:
MessageSource
)
:
QuoteReply
(
source
)
{
class
ToGroup
(
source
:
MessageSource
,
val
sender
:
QQ
)
:
QuoteReplyToSend
(
source
)
{
...
...
@@ -53,6 +54,7 @@ sealed class QuoteReplyToSend
* 引用这条消息.
* @see sender 消息发送人.
*/
@ExperimentalMessageSource
@OptIn
(
MiraiInternalAPI
::
class
)
fun
MessageChain
.
quote
(
sender
:
QQ
?):
QuoteReplyToSend
{
this
.
firstOrNull
<
MessageSource
>()
?.
let
{
...
...
@@ -65,6 +67,7 @@ fun MessageChain.quote(sender: QQ?): QuoteReplyToSend {
* 引用这条消息.
* @see from 消息来源. 若是好友发送
*/
@ExperimentalMessageSource
@OptIn
(
MiraiInternalAPI
::
class
)
fun
MessageSource
.
quote
(
from
:
QQ
?):
QuoteReplyToSend
{
return
if
(
this
.
groupId
!=
0L
)
{
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/Bot.kt
View file @
f7040c18
...
...
@@ -7,6 +7,7 @@ import kotlinx.coroutines.io.ByteReadChannel
import
net.mamoe.mirai.contact.*
import
net.mamoe.mirai.data.AddFriendResult
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.ExperimentalMessageSource
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
...
...
@@ -162,6 +163,7 @@ actual abstract class Bot actual constructor() : CoroutineScope, LowLevelBotAPIA
* @see _lowLevelRecallFriendMessage 低级 API
* @see _lowLevelRecallGroupMessage 低级 API
*/
@ExperimentalMessageSource
@JvmSynthetic
actual
abstract
suspend
fun
recall
(
source
:
MessageSource
)
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotJavaFriendlyAPI.kt
View file @
f7040c18
...
...
@@ -5,6 +5,7 @@ import net.mamoe.mirai.contact.PermissionDeniedException
import
net.mamoe.mirai.contact.recall
import
net.mamoe.mirai.data.AddFriendResult
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.ExperimentalMessageSource
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.MessageChain
import
net.mamoe.mirai.message.data.MessageSource
...
...
@@ -61,6 +62,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
*
* @see Bot.recall (扩展函数) 接受参数 [MessageChain]
*/
@ExperimentalMessageSource
@JvmName
(
"recall"
)
fun
__recallBlockingForJava__
(
source
:
MessageSource
)
{
runBlocking
{
recall
(
source
)
}
...
...
@@ -88,6 +90,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
* @param millis 延迟的时间, 单位为毫秒
* @see recall
*/
@ExperimentalMessageSource
@JvmName
(
"recallIn"
)
fun
__recallIn_MemberForJava__
(
source
:
MessageSource
,
millis
:
Long
)
{
runBlocking
{
recallIn
(
source
,
millis
)
}
...
...
@@ -148,6 +151,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
/**
* 异步调用 [__recallBlockingForJava__]
*/
@ExperimentalMessageSource
@JvmName
(
"recallAsync"
)
fun
__recallAsyncForJava__
(
source
:
MessageSource
):
Future
<
Unit
>
{
return
future
{
recall
(
source
)
}
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Contact.kt
View file @
f7040c18
...
...
@@ -53,6 +53,8 @@ actual abstract class Contact : CoroutineScope, ContactJavaFriendlyAPI() {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJavaFriendlyAPI.kt
View file @
f7040c18
...
...
@@ -48,6 +48,8 @@ actual abstract class ContactJavaFriendlyAPI {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Group.kt
View file @
f7040c18
...
...
@@ -127,6 +127,8 @@ actual abstract class Group : Contact(), CoroutineScope {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/Member.kt
View file @
f7040c18
...
...
@@ -118,6 +118,8 @@ actual abstract class Member : MemberJavaFriendlyAPI() {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/QQ.kt
View file @
f7040c18
...
...
@@ -78,6 +78,8 @@ actual abstract class QQ : Contact(), CoroutineScope {
/**
* 向这个对象发送消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessageSendEvent 发送好友信息事件, cancellable
* @see GroupMessageSendEvent 发送群消息事件. cancellable
*
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/MessageReceipt.kt
View file @
f7040c18
...
...
@@ -29,7 +29,8 @@ import net.mamoe.mirai.utils.unsafeWeakRef
*/
@Suppress
(
"FunctionName"
)
@OptIn
(
MiraiInternalAPI
::
class
)
actual
open
class
MessageReceipt
<
C
:
Contact
>
actual
constructor
(
actual
open
class
MessageReceipt
<
C
:
Contact
>
@OptIn
(
ExperimentalMessageSource
::
class
)
actual
constructor
(
actual
val
source
:
MessageSource
,
target
:
C
,
private
val
botAsMember
:
Member
?
...
...
@@ -56,6 +57,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* @see Bot.recall
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
actual
suspend
fun
recall
()
{
@Suppress
(
"BooleanLiteralArgument"
)
if
(
_isRecalled
.
compareAndSet
(
false
,
true
))
{
...
...
@@ -84,6 +86,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* [确保 sequenceId可用][MessageSource.ensureSequenceIdAvailable] 然后引用这条消息.
* @see MessageChain.quote 引用一条消息
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
actual
open
suspend
fun
quote
():
QuoteReplyToSend
{
this
.
source
.
ensureSequenceIdAvailable
()
@OptIn
(
LowLevelAPI
::
class
)
...
...
@@ -97,6 +100,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
*
* @see MessageChain.quote 引用一条消息
*/
@OptIn
(
ExperimentalMessageSource
::
class
)
@LowLevelAPI
@Suppress
(
"FunctionName"
)
actual
fun
_unsafeQuote
():
QuoteReplyToSend
{
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt
View file @
f7040c18
...
...
@@ -116,7 +116,7 @@ suspend fun InputStream.uploadAsImage(contact: Contact): OfflineImage =
*/
@Throws
(
OverFileSizeMaxException
::
class
)
suspend
fun
File
.
uploadAsImage
(
contact
:
Contact
):
OfflineImage
{
require
(
this
.
exists
()
&&
this
.
canRead
())
require
(
this
.
isFile
&&
this
.
exists
()
&&
this
.
canRead
())
{
"file ${this.path} is not readable"
}
return
withContext
(
Dispatchers
.
IO
)
{
toExternalImage
()
}.
upload
(
contact
)
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment